Makefile wiki
Makefile wiki
Hello all.
I'm having trouble making use of the Makefile article (http://wiki.osdev.org/Makefile).
How do I include a call to NASM for my kernel's header/header.s file?
Where exactly is the linker called in the example, if it is called at all?
Also, if I have Minix-style library subdirectories with one file per function e.g. lib/string/strlen.c, do I need to add each subdirectory lib/string, /lib/stdio etc. to PROJDIRS?
Thank you.
I'm having trouble making use of the Makefile article (http://wiki.osdev.org/Makefile).
How do I include a call to NASM for my kernel's header/header.s file?
Where exactly is the linker called in the example, if it is called at all?
Also, if I have Minix-style library subdirectories with one file per function e.g. lib/string/strlen.c, do I need to add each subdirectory lib/string, /lib/stdio etc. to PROJDIRS?
Thank you.
Re: Makefile wiki
The Makefile tutorial is merely pointing out one way how the 'make' utility could be used. Starting from there, any additional information you might be looking for can be found in the 'make' documentation.
The skeleton of a more powerful Makefile can be found here, but I have not found the time to put that into appropriate prose. Since you are apparently new to the field of managing a source tree, I doubt it will be much help for you.
The first thing I'd do is to get rid of those "Minix-style library subdirectories"...
The skeleton of a more powerful Makefile can be found here, but I have not found the time to put that into appropriate prose. Since you are apparently new to the field of managing a source tree, I doubt it will be much help for you.
The first thing I'd do is to get rid of those "Minix-style library subdirectories"...
Every good solution is obvious once you've found it.
Re: Makefile wiki
It's not used for compiling a kernel at all? Indeed, pdclib.a doesn't look like a kernel.Solar wrote:The Makefile tutorial is merely pointing out one way how the 'make' utility could be used. Starting from there, any additional information you might be looking for can be found in the 'make' documentation.
So the linker is called implicitly for the object files? That's a problem, because I need to feed it my linker.ld script.
As for the Assembly header.s, something like this should do it?
Code: Select all
%.o: %.s # <--- ?
@nasm ... # I don't have the file at hand but assume this line is OK
True, I saw that page before posting this topic. It's too advanced for me. Thanks anyway.Solar wrote:The skeleton of a more powerful Makefile can be found here, but I have not found the time to put that into appropriate prose. Since you are apparently new to the field of managing a source tree, I doubt it will be much help for you.
I'd like to know the reason why. Slower build? Because otherwise, I find the source very easy to browse.Solar wrote:The first thing I'd do is to get rid of those "Minix-style library subdirectories"...
Re: Makefile wiki
Civillian wrote:It's not used for compiling a kernel at all? Indeed, pdclib.a doesn't look like a kernel.
Makefile tutorial wrote:The 'make' manual will tell you about the hundreds of things you can do with a Makefile, but it doesn't give you an example for a good Makefile. The following examples are mostly shaped after the real-life PDCLib Makefile, and show some of the "tricks" used therein that may not be that obvious to the make beginner.
The Makefile creates only one project-wide linker library, but it should be easy to expand it for multiple binaries/libraries.
No, the linker is not called at all, because this example Makefile builds a linker archive.Civillian wrote:So the linker is called implicitly for the object files?
Go for it:Civillian wrote:That's a problem, because I need to feed it my linker.ld script.
This isn't about providing a ready-made solution. It's about giving people a starting point, an impression of what 'make' can do, and a couple of frequently used "tricks" (building file lists, phony targets, unit tests embedded in library implementation files, automatic C/C++ header dependency handling, conditional evaluation).Makefile tutorial wrote:The general syntax is:Code: Select all
target: dependency command
Makefiles are a tool and language of their own. There is no "one true Makefile" any more than the "one true C program".
[/quote]Civillian wrote:I'd like to know the reason why. Slower build? Because otherwise, I find the source very easy to browse.Solar wrote:The first thing I'd do is to get rid of those "Minix-style library subdirectories"...
If every subdirectory of name "X" has only one file of name "X.c", what's the purpose of the subdirectory (other than making navigation, Makefile building etc. that one step more complex)?
Every good solution is obvious once you've found it.
Re: Makefile wiki
OK, although IMHO a better starting point would be a Makefile for a kernel, since that is what people need.Solar wrote:This isn't about providing a ready-made solution. It's about giving people a starting point, an impression of what 'make' can do, and a couple of frequently used "tricks" (building file lists, phony targets, unit tests embedded in library implementation files, automatic C/C++ header dependency handling, conditional evaluation).
That would indeed be silly. So to clear that up, it's not like that.Solar wrote:If every subdirectory of name "X" has only one file of name "X.c", what's the purpose of the subdirectory (other than making navigation, Makefile building etc. that one step more complex)?
It is: e.g. include/string.h
-> lib/string/strlen.c
-> lib/string/strcpy.c
-> lib/string/memcpy.c
and so on... with one function per file and one directory per header.
Re: Makefile wiki
There was no Makefile tutorial in the Wiki, and I opted to add one based on a Makefile I use frequently, so that any problems I solve in my Makefile go into the tutorial, too.Civillian wrote:OK, although IMHO a better starting point would be a Makefile for a kernel, since that is what people need.
The differences between "makefile that creates a linker lib" and "makefile that creates a kernel binary" would be no more complex than the differences between "makefile that builds kernel X" and "makefile that builds kernel Y"; indeed, to turn the tutorial Makefile into one that generates a binary, all you need is to replace one rule. Instead of the pdclib.a rule, write:
Code: Select all
kernel.bin: $(OBJFILES) linker.ld
@ld -T linker.ld -o $@ $? $(OBJFILES)
Besides, there is a reason why the tutorial does not present a "complete" Makefile in one block, or why the GCC Cross-Compiler tutorial doesn't provide an automated script. This isn't about copy & paste, it's about understanding how it works, and adapting it to whatever needs you might have. The idea is not to do the work for you, but to provide the information that might be hard to come by otherwise. (Most Makefiles out in the wild suck because people did c&p some code they didn't understand, usually crappy code to begin with, and did some trial&error on it until it worked for them so-so. I wanted to provide a better starting point plus some guidance, not a ready-made solution.)
In that case, it would be sufficient to set PROJDIRS like this:It is: e.g. include/string.h
-> lib/string/strlen.c
-> lib/string/strcpy.c
-> lib/string/memcpy.c
and so on... with one function per file and one directory per header.
Code: Select all
PROJDIRS := lib include
Every good solution is obvious once you've found it.
Re: Makefile wiki
My current problem is that I can't get NASM to be used for the header/header.s file, which I stuck in SRCFILES alongside the C source files.
Also note that I had to remove the backslashes in -name's parameter at the find calls.
Also note that I had to remove the backslashes in -name's parameter at the find calls.
Code: Select all
KERNNAME := kernel.bin
PROJDIRS := header include lib
SRCFILES := $(shell find $(PROJDIRS) -type f -name "*.[cs]")
HDRFILES := $(shell find $(PROJDIRS) -type f -name "*.h")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
WARNINGS := -Wall -Wextra -pedantic
CFLAGS := -std=c99 -Werror $(WARNINGS) -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -O2 -I ./include
ASFLAGS := -f elf
LDFLAGS := -T linker.ld -m elf_i386
.PHONY: build clean
build: $(KERNNAME)
$(KERNNAME): $(OBJFILES) linker.ld
@ld $(LDFLAGS) -o $@ $? $(OBJFILES)
clean:
-@$(RM) -v $(wildcard $(OBJFILES) $(DEPFILES) $(KERNNAME) *~ */*~ */*/*~)
-include $(DEPFILES)
%.o: %.c Makefile
@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.o: %.s
nasm $(ASFLAGS) $<
Re: Makefile wiki
You have to set make to handle specific suffixes.
Note: Verify this works on some junk files first, if you mess up the $^ and $@ tokens you can actually end up overwriting your source files
Code: Select all
CC = gcc
CFLAGS =
ASM = nasm
ASM_FLAGS = -f elf
.SUFFIXES: .c .s .o
.c.o: $^
$(CC) $(CFLAGS) -o $@ $^
.s.o: $^
$(ASM) $(ASM_FLAGS) -o $@ $^
Reserved for OEM use.
Re: Makefile wiki
@ Cognition:
You got it wrong. It's either:
or:
I prefer GNU style, as it is more consistent with "normal" rules. In any case, no "$^" in either the rule target or the prerequisite; those variables are for the commands only.
$@: The target of the rule.
$^: All prerequisites of a rule.
(You should rather use $<, which is the first prerequisite for a rule; not that it makes much of a difference when you only have one prerequisite, but you might want to add the Makefile itself as prerequisite so that changes in e.g. the compiler flags trigger a recompile.)
You got it wrong. It's either:
Code: Select all
% GNU style
%.o: %.s
Code: Select all
% POSIX style
.s.o:
Sound advice, but checking the manual, section "Automatic Variables", would be even better. There is a lot more that 'make' can do that is not covered in the tutorial, which is only an introduction to a basic use case. That's why it says "tutorial"...Cognition wrote:Verify this works on some junk files first, if you mess up the $^ and $@ tokens you can actually end up overwriting your source files.
$@: The target of the rule.
$^: All prerequisites of a rule.
(You should rather use $<, which is the first prerequisite for a rule; not that it makes much of a difference when you only have one prerequisite, but you might want to add the Makefile itself as prerequisite so that changes in e.g. the compiler flags trigger a recompile.)
Every good solution is obvious once you've found it.
Re: Makefile wiki
@Solar: You're right, it's been a long time since I hacked my Makefile together and tbh it's a bit of mess. Thanks for the advice.
Reserved for OEM use.
Re: Makefile wiki
Thanks for the replies.
Because I kept getting the below error, I changed the makefile.
Because I kept getting the below error, I changed the makefile.
Let me know if you spot anything wrong, so far it seems to work.header/header.s:1: *** missing rule before commands. Stop.
Code: Select all
KERNNAME := kernel.bin
PROJDIRS := header include lib
SRCFILES := $(shell find $(PROJDIRS) -type f -name "*.c")
HDRFILES := $(shell find $(PROJDIRS) -type f -name "*.h")
ASMFILES := $(shell find $(PROJDIRS) -type f -name "*.s")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
ASOFILES := $(patsubst %.s,%.o,$(ASMFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
WARNINGS := -Wall -Wextra -pedantic
CFLAGS := -std=c99 -Werror $(WARNINGS) -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -O2 -I ./include
ASFLAGS := -f elf
LDFLAGS := -T linker.ld -m elf_i386
.PHONY: build clean
build: $(KERNNAME)
$(KERNNAME): $(ASOFILES) $(OBJFILES) linker.ld
@ld $(LDFLAGS) -o $@ $? $(ASOFILES) $(OBJFILES)
clean:
-@$(RM) -v $(wildcard $(OBJFILES) $(ASOFILES) $(DEPFILES) $(KERNNAME) *~ */*~ */*/*~)
-include $(DEPFILES)
%.o: %.c Makefile
@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.o: %.s
@nasm $(ASFLAGS) $< -o $@
Re: Makefile wiki
Nothing wrong as far as I could see while skimming over it.
But two things could be simpler:
You don't need this anywhere.
You don't need to keep a separate ASOFILES. Once it's a *.o file, it doesn't matter what it was originally. Replace with:
...and delete all other occurences of ASOFILES (in kernel and clean rule).
But two things could be simpler:
Code: Select all
HDRFILES := $(shell find $(PROJDIRS) -type f -name "*.h")
Code: Select all
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
ASOFILES := $(patsubst %.s,%.o,$(ASMFILES))
Code: Select all
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) $(patsubst %.s,%.o,$(ASMFILES))
Every good solution is obvious once you've found it.
Re: Makefile wiki
Good suggestions, thank you.
As a final improvement, I wanted to add Automated testing, but I'm given this error:
used TESTFILES, TESTDEPFILES and the _test suffix instead of the original ones.
Edit: extra question, what does the $? do, in the linker call?
As a final improvement, I wanted to add Automated testing, but I'm given this error:
I deviated only slightly from the Wiki to increase readability:make: *** No rule to make target `lib/string/strlen_test', needed by `tests'. Stop.
used TESTFILES, TESTDEPFILES and the _test suffix instead of the original ones.
Edit: extra question, what does the $? do, in the linker call?
Code: Select all
KERNNAME := kernel.bin
PROJDIRS := header include lib
SRCFILES := $(shell find $(PROJDIRS) -type f -name "*.c")
ASMFILES := $(shell find $(PROJDIRS) -type f -name "*.s")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) $(patsubst %.s,%.o,$(ASMFILES))
TESTFILES := $(patsubst %.c,%_test,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
TESTDEPFILES := $(patsubst %,%.d,$(TESTFILES))
WARNINGS := -Wall -Wextra -pedantic
CFLAGS := -std=c99 -Werror $(WARNINGS) -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -O2 -I ./include
ASFLAGS := -f elf -Ox
LDFLAGS := -T linker.ld -m elf_i386
.PHONY: build clean check tests
build: $(KERNNAME)
$(KERNNAME): $(OBJFILES) linker.ld
@ld $(LDFLAGS) -o $@ $? $(OBJFILES)
clean:
-@$(RM) -v $(wildcard $(OBJFILES) $(DEPFILES) $(TESTFILES) $(KERNNAME) $(shell find -type f -name "*~"))
check: tests
-@rc=0; count=0; \
for file in $(TESTFILES); do \
echo "Test: $$file"; ./$$file; \
rc=`expr $$rc + $$?`; count=`expr $$count + 1`; \
done; \
echo; \
echo "Tests failed: $$rc out of $$count."
tests: $(TESTFILES)
-include $(DEPFILES) $(TESTDEPFILES)
%.o: %.c Makefile
@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.o: %.s
nasm $(ASFLAGS) $< -o $@
%_test: %.c Makefile
@$(CC) $(CFLAGS) -MMD -MP -D TESTING $< -o $@
Re: Makefile wiki
There is nothing I could say, other than RTfineM...Civillian wrote:Edit: extra question, what does the $? do, in the linker call?
Every good solution is obvious once you've found it.
Re: Makefile wiki
Judging by what I read here: http://www.gnu.org/software/make/manual ... -Variables
$? isn't needed there in the makefile.
I also found that in order to compile the test drivers, the Makefile dependency needed to be removed and the compiler flags rewritten.
$? isn't needed there in the makefile.
I also found that in order to compile the test drivers, the Makefile dependency needed to be removed and the compiler flags rewritten.
Code: Select all
KERNNAME := kernel.bin
PROJDIRS := header include lib
SRCFILES := $(shell find $(PROJDIRS) -type f -name "*.c")
ASMFILES := $(shell find $(PROJDIRS) -type f -name "*.s")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES)) $(patsubst %.s,%.o,$(ASMFILES))
TESTFILES := $(patsubst %.c,%_test,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
TESTDEPFILES := $(patsubst %,%.d,$(TESTFILES))
WARNINGS := -Wall -Wextra -pedantic
CFLAGS := -std=c99 -Werror $(WARNINGS) -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -O2 -I ./include
TESTCFLAGS := -std=c99 $(WARNINGS) -nostdinc -m32 -O2 -I ./include
ASFLAGS := -f elf -Ox
LDFLAGS := -T linker.ld -m elf_i386
.PHONY: build clean check tests
build: $(KERNNAME)
$(KERNNAME): $(OBJFILES) linker.ld
ld $(LDFLAGS) -o $@ $(OBJFILES)
clean:
-@$(RM) -v $(wildcard $(OBJFILES) $(DEPFILES) $(TESTFILES) $(TESTDEPFILES) $(KERNNAME) $(shell find -type f -name "*~"))
check: tests
-@failed=0; file_count=0; \
for file in $(TESTFILES); do \
echo "Test: $$file"; \
./$$file; \
failed=`expr $$failed + $$?`; \
file_count=`expr $$file_count + 1`; \
done; \
echo "Tests failed: $$failed in $$file_count test files."
tests: $(TESTFILES)
-include $(DEPFILES) $(TESTDEPFILES)
%.o: %.c Makefile
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@
%.o: %.s
nasm $(ASFLAGS) $< -o $@
%_test: %.c
@$(CC) $(TESTCFLAGS) -MMD -MP -D TESTING $< -o $@