I recently started following the James M Kernel Dev tutorials and was able to create an operating system in C++.
Here is the source on GitHub.
I have a couple of questions:
- Is my coding style ok?
- Is it wrong to write bash scripts for building the project?
JOSMake.sh
#
# Build File for JOS
#
# To Build
# bash build.sh
# To Run
# bash run.sh
# ----------------------------------------------------------------------------------------------
# JOS uses assembly to build the bootsector
# Compile the boot Sectors in boot
echo "==============================================="
echo "-------- Building Boot Sectors ----------------"
cd boot
# Run the Make Script inside the boot directory
bash buildboot.sh
cd ..
echo "==============================================="
# ----------------------------------------------------------------------------------------------
# ----------------------------------------------------------------------------------------------
# Compile the C++ Sources into Respective Objects
# Compile main.cc
echo "==============================================="
echo "--------- Compiling C++ Sources --------------"
g++ -c -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 -o main.o main.cc
mv main.o build
# Run scons to build the Entire Lbrary of C++ Files
cd include
rm *.o
scons
# Move all Object Files into Build Directory
cp *.o ../build
cd ..
echo "==============================================="
# ----------------------------------------------------------------------------------------------
# ----------------------------------------------------------------------------------------------
## When Everything is Finished Link together the Objects into a Kernel File
echo "==============================================="
echo "--------- Linking ----------------"
cd build
# require ld , link.ld
ld -T '../link.ld' -m elf_i386 -o kernel.jos *.o
# Clean Up After Build
#rm *.o
echo "==============================================="
# ----------------------------------------------------------------------------------------------
# ----------------------------------------------------------------------------------------------
## When Everything is Finished Run the Kernel
qemu-system-i386 -kernel kernel.jos
# -----------------------------------------------------------------------------------------
2 Answers 2
Instead of repeated statements like this:
echo "==============================================="
I suggest adding a helper function, for example:
print_hr() { # hr - as in horizontal rule
echo "==============================================="
}
The advantage of this is if you later decide to change the length of the =
in the line, you can change it in one place.
Instead of entering into sub-directories with cd dirname
and later stepping back with cd ..
, I recommend to use sub-shell environments with (...)
. For example, instead of this:
cd include rm *.o scons # Move all Object Files into Build Directory cp *.o ../build cd ..
Do like this:
(
cd include
rm *.o
scons
# Move all Object Files into Build Directory
cp *.o ../build
)
Notice that there is no more cd ..
.
Working directory changes in a (...)
sub-shell environment are only in effect within.
This maybe a matter of taste, but I find that the many comment lines like this are just noise, and make the script hard to read, I suggest to remove them:
# ----------------------------------------------------------------------------------------------
It's not wrong to use a Bash script to build your project, but it is suboptimal and unconventional. Usually, a makefile is preferred, since Make can compare timestamps and rebuild just the objects that need to be rebuilt.
There are other advantages to makefiles as well. For example, a common convention would be to define variables like
CXX = g++
CXXFLAGS = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -ffreestanding -m32 $(EXTRA_CXXFLAGS)
Then, you would have the flexibility to run make EXTRA_CXXFLAGS=-O2
to compile with -O2
without having to edit the script.
A lot of your script's sequences of operations seem complicated and error-prone. For example:
cd include rm *.o scons # Move all Object Files into Build Directory cp *.o ../build cd ..
When your script changes directories, that's a bit of global state information that you need to keep track of. That makes the script "brittle" — deleting or rearranging a few lines of the script can have massive effects on all subsequent commands. If you need to change directories, use a subshell as @janos suggested. Better yet, avoid changing directories at all, if possible — and you should be able to build a simple project like this without jumping around.
Why are there .o files in the include
directory? By convention, a directory named include
would only contain .h
header files that are included elsewhere, and don't need to be compiled (unless you are using precompiled headers — but that's not the case here).
Why copy the .o files into the ../build
directory? Find some way to get the compiler to produce them in the right place the first time (using the -o
option). Copying is inefficient, messes up timestamps, and leaves unnecessary junk.
Your script violates the Single Responsibility Principle:
## When Everything is Finished Run the Kernel qemu-system-i386 -kernel kernel.jos
If you advertise your script as a build script, then it should be just that. Imagine you were packaging this software as a component in a Linux distribution. Having such a line in the build script would be a serious annoyance.
-
\$\begingroup\$ Thanks ! I will dump the bash script and Rewrite it in make . \$\endgroup\$aswin mohan– aswin mohan2015年12月03日 08:15:42 +00:00Commented Dec 3, 2015 at 8:15