problems with kernel not being loaded - gcc

I'm creating an OS and when I compile the code nothing happened, simply nothing(No errors, warnings or anything) I"m thinking that the make file has some issues.
Makefile:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
link:
echo "Linking..."
${LINKER} -o ${BUILD_DIR}/kernel.bin ${BUILD_DIR}/kernel_ports.o \
${BUILD_DIR}/kernel_printutils.o ${BUILD_DIR}/kernel_start.o \
${BUILD_DIR}/kernel_entry.o -Ttext 0x1000 --oformat binary
echo "Linking complete"
run:
echo "Running qemu..."
qemu-system-x86_64 -fda ${BUILD_DIR}/os.bin
merge_binary:
echo "Merging binary..."
cat ${BUILD_DIR}/boot.bin ${BUILD_DIR}/kernel.bin > ${BUILD_DIR}/os.bin
echo "Binary merged."
post_build:
rm -f ${BUILD_DIR}/boot.bin
rm -f ${BUILD_DIR}/kernel.bin
rm -f ${BUILD_DIR}/kernel.o
rm -f ${BUILD_DIR}/kernel_entry.o
rm -f ${BUILD_DIR}/kernel_ports.o
rm -f ${BUILD_DIR}/kernel_printutils.o
rm -f ${BUILD_DIR}/kernel_start.o
I'm wondering what is happening with the makefile and is this the correct way to compile all the code into object files and link them.
Any help will be appreciated.

I'm just commenting on your make style -- this does not answer why you are outputting nothing (and it is unclear what you mean by that -- if you run make, it should output at least echo "Building kernel..."...). As far as the makefile style goes, this seems to be built using a scripting mentality rather than a make mentality. Consider your first part:
build_kernel:
echo "Building kernel..."
${ASM} ./src/kernel/kernel_entry.asm -f elf64 -o ${BUILD_DIR}/kernel_entry.o
${C_COMPILER} -c ./src/kernel/kernel.c -o ${BUILD_DIR}/kernel_start.o
${C_COMPILER} -c ./src/kernel/drivers/printutils.c -o ${BUILD_DIR}/kernel_printutils.o
${C_COMPILER} -c ./src/kernel/drivers/port.c -o ${BUILD_DIR}/kernel_ports.o
echo "kernel build complete."
This has several issues. First is the name -- this looks to build a bunch of artifacts rather than building the kernel. Also, the recipe never produces a file named build_kernel, thus this should have been a phony target. Next, this is actually a script, which builds four separate things. These could be separated out into four separate rules, each which builds one thing, and then the main target would be dependent on this. Thus, it might look like:
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo done building $#
${BUILD_DIR}/kernel_start.o : ./src/kernel/kernel.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_printutils.o : ./src/kernel/kernel_printutils.c
${C_COMPILER} -c $< -o $#
${BUILD_DIR}/kernel_ports.o : ./src/kernel/kernel_ports.c
${C_COMPILER} -c $< -o $#
Note that the above is repetitive, and if you have hundreds of files, will bolat very quickly. This can also be done using static pattern rules:
C_FILES := \
./src/kernel/kernel_start.c
./src/kernel/kernel_printutils.c
./src/kernel/kernel_ports.c
ASM_FILES := \
./src/kernel/kernel_entry.asm
C_OBJS := ${C_FILES :./src/kernel/%.c=${BUILD_DIR}/%.o}
ASM_OBJS := ${ASM_FILES :./src/kernel/%.asm=${BUILD_DIR}/%.o}
${C_OBJS} : ${BUILD_DIR}/%.o : ./src/kernel/%.c
${C_COMPILER} -c $< $#
.PHONY: build_kernel_objs
build_kernel_objs: ${C_OBJS} ${ASM_OBJS}
#echo "done building $#"
These have several advantages over what you've done -- first, make will only ever build the objects that are out of date, so it doesn't do needless work. It can also build the files in parallel if a -j option is specified on the make command line. Next, it's more maintainable -- if you have to add extra files, you can do it in one place, and everything works out. Also, the .PHONY prevents the make from failing if you happen to have a file named build_kernel_objs in your make directory. Lastly, the # in front of the echo lines prevents the actual echo command from being echoed, which will look nicer.
On caveat to this is that it does not handle modification of header files (as written, if a header file is updated, c files that depend on it would not be rebuilt. See here for some notes about getting around that.
The next section, link, the makefile recipe should reflect the target.
.PHONY: link
link : ${BUILD_DIR}/kernel.bin
${BUILD_DIR}/kernel.bin: ${C_OBJS} ${ASM_OBJS}
${LINKER} -o $# $^ -Ttext 0x1000 --oformat binary
This creates a phony target link, so you can type make link. It will only do the link if any of the C objects or ASM objects have been updated. The same concept applies to your merge_binary target
For run, this seems to be somewhat contentious, but a common rule of thumb is that a make should be used to make an executable, not to run it. A separate shell script is better suited if you want to invoke your built target with specific parameters.
Lastly, your post_build rule should likely be renamed to CLEAN, and declared as a phony.

Related

Simple makefile command not found

I was given a makefile that looks like this, and told not to change it.
all: clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp clean: rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
I am trying to run this makefile in a folder with files named: scanner.lex, parser.ypp, output.hpp and output.cpp
I copied it to a file like this:
all:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c rm -f parser.tab.*pp rm -f hw2
When I run the make command in my terminal I get an error:
clean flex scanner.lex bison -d parser.ypp g++ -std=c++11 -o hw2 *.c *.cpp
/bin/sh: clean: command not found
make: *** [all] Error 127
Am I doing something wrong? Again, I was given this line and told not to change it.
Thanks a lot.
Line breaks are essential in most computer environments. If you were given a Makefile without the line breaks and you try to cut it randomly you will have difficulties before if finally works. Try this, maybe:
all: clean
flex scanner.lex
bison -d parser.ypp
g++ -std=c++11 -o hw2 *.c *.cpp
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
And use tabs to indent the indented lines, not spaces.
Explanations: all and clean are what is called a target in make parlance. They are the names of the things you want make to do. clean to delete some files, all to do everything else. The
target: prerequisite1 prerequisite2...
recipe1
recipe2
...
template is the basic make template. It means that target depends on prerequisite1, prerequisite2 and that in order to build it make shall pass recipe1 to the shell for execution, then recipe2...
Note that this Makefile is poorly written. As all and clean are not real file names they should be declared as phony, such that, if a file with that name exists make does the job anyway. As is, it wouldn't. Give it a try:
$ make all
$ touch clean
$ make clean
make: 'clean' is up to date.
See? Because a file named clean exists you cannot make clean anymore, make considers that there is nothing to do for clean. Add this at the beginning of your Makefile:
.PHONY: all clean
A second issue is that make works by comparing last modification times of targets and prerequisites to decide if targets must be rebuilt or not. With your Makefile make will always recompile everything, even if the inputs did not change and the outputs are up-to-date. This is a waste. A better (but untested) Makefile would be something like:
.PHONY: all clean
CFILES := $(filter-out lex.yy.c,$(wildcard *.c))
CPPFILES := $(filter-out parser.tab.cpp,$(wildcard *.cpp))
all: hw2
hw2: lex.yy.c parser.tab.cpp $(CFILES) $(CPPFILES)
g++ -std=c++11 -o $# $^
lex.yy.c: scanner.lex
flex $<
parser.tab.cpp: parser.ypp
bison -d $<
clean:
rm -f lex.yy.c
rm -f parser.tab.*pp
rm -f hw2
Understanding it and why it is better is left as an exercise.

Using Makefile to run multiple programs

Whenever I try to run this, the only output I get is "make: foo.o is up to date." It seems as if the rest of the program does not run and I do not know why. My instructions are as follows: "Compile a C program. Run a C program. Run a Python program. Compile and run a java program. Check for a README, display it. Compare 2 files. Clean up intermediary files."
cc = gcc
EXE = foo
JAVAC = javac
JRE = java
PAGER = less
TEST_OUT = test.out
EXP_OUT = expected.out
foo.o: foo.c foo.h
$(cc) -c foo.c
main.o: main.c foo.h
$(cc) -c main.c
$(EXE): foo.o main.o
$(cc) -o$(EXE) main.o foo.o
run-c: $(EXE)
./$(EXE)
run-py:
./foo.py
read: README
$(PAGER)
foo.class: foo.java
$(JAVAC) foo.java
run-java: foo.cass
$(JRE) foo
save-java:
./(run-java) >> $(TEST_OUT)
test-java: $(TEST_OUT) $(EXP_OUT)
#if diff $(TEST_OUT) $(EXP_OUT) &> /dev/null ; then \
echo "Passed!" ;\
else \
echo "Not the same!" ;\
fi
clean:
-rm test.out
Whenever I try to run this, the only output I get is "make: foo.o is up to date."
By default, make runs the topmost rule when no target is specified. You have to run for example make run-c to invoke a corresponding recipe, or you can just put an all rule before any others which depends on and does all the things.
read: README
$(PAGER)
I suspect you might have missed putting $# after $(PAGER) as the argument.
save-java:
./(run-java) >> $(TEST_OUT)
You can't just "include" other recipes this way. Instead, repeat what's in run-java and append the redirection.
If you want to specify "pseudo" targets, I recommend you to specify them as .PHONY, such as:
.PHONY: all run-c run-py run-java save-java test-java clean
To mark some targets as intermediate files, use the .INTERMEDIATE directive. GNU Make manual (texinfo) is available both online and via the info command.

Make rebuilds everytime

I have a Makefile as :
BUILD_DIR= $(BASE_DIR)/build
_OBJ := a.o b.o
CLEAN_OBJECTS := $(_OBJ)
.PHONY: clean
create_code:
python ../script/my_script.py
all: create_code $(_OBJ)
$(_OBJ): %.o: %.c
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $(INCLUDE_PATH) -c $< -o $#
cp *.o $(BUILD_DIR)
clean:
rm -f $(CLEAN_OBJECTS)
The target create_code executes the python script and generates a set of .c/.h files.
The target _obj compiles them.
Every time I run make all , create_code target is run even though there is no change to .c/.h generated earlier .
Any suggestions on why this is happening and how to make this create_code target run only if make clean was done earlier .
The underlying problem is that you have one or more generated files that depend on something other than the underlying file system -- namely the contents of your database.
One possibility would be to take advantage of the fact that make, having invoked a rule to rebuild a target will, nonetheless, always check the update time of that target when it is specified as a prerequisite in any other rule.
So, given the rule (untested)...
.PHONY: FORCE
%.c: FORCE
command-to-generate-source $#.tmp
diff -q $#.tmp $# || cp $#.tmp $#
Invoking make foo.c from the command line. make will run the commands...
command-to-generate-source foo.c.tmp
diff -q foo.c.tmp foo.c || cp foo.c.tmp foo.c
where command-to-generate-source foo.c.tmp is expected to leave its output in foo.c.tmp. If the newly generated output file is different than the existing file the cp operation will be run and, hence, the target timestamp will be updated and anything dependent on the target will be updated accordingly.
If, however, the newly generated output file is the same as the existing one then no cp will be run, the target file will be left untouched and make will not consider it to be changed when it appears as a prerequisite in other rules.
This is just one possibility but it's the obvious one given that you already have most (if not all) of the required logic in the command python ../script/my_script.py.

How is this complex generic Makefile rule constructed

Several modules each are tested independently with their own test_$(MODULE).c.
A shared library has been generated $(LIBRARY) containing modules without coverage. $(basename $<).o should override the one in $(LIBRARY). For some reason, I get results as if they are not overridden. Can someone review this and make suggestions on fixes? Currently I have non-generic gcov rules for each of the five objects. These gcovs work correctly. Below I show the generic rule and one specific use of the rule.
SHARED_OPTS=-O0 -Wall -Wextra -fPIC
GOPTS=$(SHARED_OPTS) -g -coverage -pg
%.gcov : %
#echo "\t$# generic (needs work)"
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
#-gcc $(GOPTS) -o gcov_test_$(basename $<) \
test_$(basename $<).o \
$(basename $<).o \
-L . -l $(LIBRARY)
#-./gcov_test_$(basename $<)
#-gcov $< >$#.out 2>&1
#echo "no Mac gprof: -gprof gcov_test_$(basename $<) gmon.out > $<.prof"
#$(call timestamp,$#)
Unicode.c.gcov: Unicode.c
If anyone is interested in collaborating on high efficiency high quality Unicode lexing/parsing support by developing a shared library, I would love to have reviewers or contributors.
The Makefile fragment shown above is in a github repository:
https://github.com/jlettvin/Unicode Specifically down the c subdirectory.
While you're trying to find problems in your makefile you should avoid using #, as it hides the command line and so you can't see issues. Also you should avoid - here: if any of those commands fail you certainly don't want to continue to run the rest of the recipe, I wouldn't expect.
I don't know if it's a cut/paste problem but I have to assume that these lines, at least, are wrong:
#-gcc $(GOPTS) -c -o test_$(basename $<).o test_$<
#-gcc $(GOPTS) -c -o $(basename $<).o $<
As far as I can tell from your makefile, the last words on these lines should be test_$<.c and $<.c respectively.

How do I shut up make when it doesn't need to do anything?

How I stop make from saying make: Nothing to be done for 'all'. or make: 'file' is up to date? I'd like my build to be silent when it's not doing anything - there are other places where echo is called to track build progress, so this message is just cluttering things up. I am currently silencing it like this:
all: dependency1 dependency2
#:
Something tells me there must be a better way. Any ideas?
Edit:
I would like to keep command echo working when it does need to build something, however. A good example of what I'm hoping for is along the lines of --no-print-directory, but I can't find any other flags to shut up selected messages.
Maybe make -s?
So after a couple days of reading around the web, it looks like there isn't any better way than what I'm doing. Some people recommended something along the lines of:
all: dependency1 dependency2 | silent
silent:
#:
That is, just depending on the silent target would be enough to quiet things down. Since I didn't come up with any other workable solutions, I'm going with what I have.
You might try...
$ make -q || make
The advantage of doing it this way is that nothing is printed when there is nothing to do but make produces the normal output when it does need to proceed...
To quote (from memory) from the old make(1) man page, BUGS section: There are some things you can't get make to shut up about. Meanwhile, the -s or --silent option may help.
You can set the -s commandline argument to make in the makefile itself, by setting MAKEFLAGS. Nothing is printed unless you explicitely print it, so I use the following makefile to echo invoked commands.
MAKEFLAGS += -s
PROJECT = progname
CC = g++
SDIR = src
ODIR = obj
BDIR = bin
IDIR = include
OBJS = $(patsubst $(SDIR)/%.cc,$(ODIR)/%.o,$(wildcard $(SDIR)/*.cc))
.PHONY: all debug clean
all: $(BDIR)/$(PROJECT)
debug: CFLAGS += -g -Wall -Wextra
debug: all
$(BDIR)/$(PROJECT): $(OBJS)
#mkdir -p $(BDIR)
#echo LINKING $<
#$(CC) -o $# $(OBJS) -I$(IDIR)
$(ODIR)/%.o: $(SDIR)/%.cc
#mkdir -p $(ODIR)
#echo "COMPILING $<"
#$(CC) -o $# -c $< $(CFLAGS)
clean:
#echo "CLEAN"
#rm -rf $(BDIR) $(ODIR)
Removing the MAKEFLAGS variable will print all invoked commands. The Makefile compiles any c++ project where source files (with .cc extension) are put into the src directory and header files are put into the include directory.
make 2>&1 | egrep -v 'Nothing to be done|up to date'

Resources