Makefile wiki

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Makefile wiki

Post by Solar »

Civillian wrote:Judging by what I read here: http://www.gnu.org/software/make/manual ... -Variables
$? isn't needed there in the makefile.
Well, the $? was the right thing to do in the tutorial, because the command was to replace object files in a linker archive - in that case, you only need the newer object files, not all of them.

You copy&pasted that into a linker command... which requires a somewhat different handling.
I also found that in order to compile the test drivers, the Makefile dependency needed to be removed and the compiler flags rewritten.
Why would you need to remove the Makefile dependency? The variable $< is replaced with the first dependency; whether or not you have "Makefile" as second dependency shouldn't make a difference for the command (and, as I said, results in the test drivers being rebuilt when the Makefile changes). Works fine for me.

I don't see what you mean with "rewritten compiler flags".
Every good solution is obvious once you've found it.
User avatar
Civillian
Member
Member
Posts: 32
Joined: Tue Feb 21, 2012 3:26 pm

Re: Makefile wiki

Post by Civillian »

Solar wrote:Works fine for me.
For me, it gave a "no rule to make target." That version of the makefile is in the first $?-related post.
Solar wrote:I don't see what you mean with "rewritten compiler flags".
This is probably not the best way to do it, but I get linker warnings and corrupted executables if I don't.

Code: Select all

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
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Makefile wiki

Post by Solar »

8) I just realized that the $? copy&paste-error was mine, sorry.
Civillian wrote:For me, it gave a "no rule to make target." That version of the makefile is in the first $?-related post.
Well, it shouldn't, and it doesn't for me using a Makefile very similar to the one in the Wiki, is all I can say.
Solar wrote:I don't see what you mean with "rewritten compiler flags".
This is probably not the best way to do it, but I get linker warnings and corrupted executables if I don't.
Ah, I see - your test drivers needing different CFLAGS than the kernel proper. No surprise there. I'd daresay quite some portion of kernel code can't be tested in user space.
Every good solution is obvious once you've found it.
User avatar
Civillian
Member
Member
Posts: 32
Joined: Tue Feb 21, 2012 3:26 pm

Re: Makefile wiki

Post by Civillian »

Solar wrote:Well, it shouldn't, and it doesn't for me using a Makefile very similar to the one in the Wiki, is all I can say.
Rhetorical question: why did I put "Makefile" in a file named "GNUmakefile"?
Solar wrote:Ah, I see - your test drivers needing different CFLAGS than the kernel proper. No surprise there. I'd daresay quite some portion of kernel code can't be tested in user space.
I wonder if I should put back -fno-builtin.
As for untestable portions, I'm not worried. All my tests so far have failed: they didn't find any bugs.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Makefile wiki

Post by Solar »

Civillian wrote:Rhetorical question: why did I put "Makefile" in a file named "GNUmakefile"?
The question might be rhetoric, but I don't have the slightest idea what you're hinting at. (Edit: Clarified via PM.)
Civillian wrote:As for untestable portions, I'm not worried. All my tests so far have failed: they didn't find any bugs.
That's not a failure, that's a success in confidence. Also, if some future change breaks compatibility, you will be immediately aware of it. Moreover, if a bug is reported (or discovered), your existing test framework should make it easy to trigger the bug in test (instead of live running of your kernel, which is much harder to debug).
Every good solution is obvious once you've found it.
User avatar
Civillian
Member
Member
Posts: 32
Joined: Tue Feb 21, 2012 3:26 pm

Re: Makefile wiki

Post by Civillian »

The makefile is nearing completion. Now I increased its verbosity, because I'm uncomfortable with "no news".
The final thing missing would be NASM-generated dependencies. But that can wait...

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 -fno-builtin -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
	@echo -n "ld:"; \
	for file in $(OBJFILES); do \
		echo "\t $$file"; \
		done; \
	echo "\t -> " $@
	@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; \
	echo "---"; \
	for file in $(TESTFILES); do \
		echo "test:\t $$file"; \
		./$$file; \
		failed=`expr $$failed + $$?`; \
		file_count=`expr $$file_count + 1`; \
		done; \
	echo "\ttests failed: $$failed in $$file_count test files.\n"

tests: $(TESTFILES)

-include $(DEPFILES) $(TESTDEPFILES)

%.o: %.c GNUmakefile
	@echo "gcc:\t" $< "\t-> " $@
	@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@

%.o: %.s GNUmakefile
	@echo "nasm:\t" $< "\t-> " $@
	@nasm $(ASFLAGS) $< -o $@

%_test: %.c GNUmakefile
	@echo "gcc:\t" $< "\t-> " $@
	@$(CC) $(TESTCFLAGS) -MMD -MP -D TESTING $< -o $@
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: Makefile wiki

Post by Solar »

Civillian wrote:The final thing missing would be NASM-generated dependencies.
It appears that NASM has quite similar dependency-generating options as GCC (-MD, -MP et al.):

clicky
Every good solution is obvious once you've found it.
User avatar
Civillian
Member
Member
Posts: 32
Joined: Tue Feb 21, 2012 3:26 pm

Re: Makefile wiki

Post by Civillian »

Thanks for the link, which was more informative than the manpage.
Here's the NASM dependencies makefile, which seems to be working.

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))
ASMDEPFILES := $(patsubst %.s,%.s.dep,$(ASMFILES))
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 -fno-builtin -m32 -O2 -I ./include
ASFLAGS := -f elf -Ox -w+all
LDFLAGS := -T linker.ld -m elf_i386

.PHONY: build clean check tests

build: $(KERNNAME)

$(KERNNAME): $(OBJFILES) linker.ld
	@echo -n "ld:"; \
	for file in $(OBJFILES); do \
		echo "\t $$file"; \
		done; \
	echo "\t -> " $@
	@ld $(LDFLAGS) -o $@ $(OBJFILES)

clean:
	-@$(RM) -v $(wildcard $(OBJFILES) $(DEPFILES) $(TESTFILES) $(TESTDEPFILES) $(ASMDEPFILES) $(KERNNAME) $(shell find -type f -name "*~"))

check: tests
	-@failed=0; file_count=0; \
	echo "---"; \
	for file in $(TESTFILES); do \
		echo "test:\t $$file"; \
		./$$file; \
		failed=`expr $$failed + $$?`; \
		file_count=`expr $$file_count + 1`; \
		done; \
	echo "\ttests failed: $$failed in $$file_count test files.\n"

tests: $(TESTFILES)

-include $(DEPFILES) $(TESTDEPFILES) $(ASMDEPFILES)

%.o: %.c GNUmakefile
	@echo "gcc:\t" $< "\t-> " $@
	@$(CC) $(CFLAGS) -MMD -MP -c $< -o $@

%.o: %.s GNUmakefile
	@echo "nasm:\t" $< "\t-> " $@
	@nasm $(ASFLAGS) -MD $<.dep -MP $< -o $@

%_test: %.c GNUmakefile
	@echo "gcc:\t" $< "\t-> " $@
	@$(CC) $(TESTCFLAGS) -MMD -MP -D TESTING $< -o $@
User avatar
Civillian
Member
Member
Posts: 32
Joined: Tue Feb 21, 2012 3:26 pm

Re: Makefile wiki

Post by Civillian »

For my current needs, the makefile is complete, unless anyone spots bugs.
Otherwise, thank you Solar, and Cognition, for your contributions.
See you all later.

Edit:
Rewritten the check section. In my test drivers, I usually include more than one test, so the exit code in case of failure may be greater than 1.

Code: Select all

check: tests
	-@echo "--- TESTING BEGIN ---"; \
	for file in $(TESTFILES); do \
		./$$file; \
		exit_code=$$?; \
		if [ $$exit_code -gt 0 ]; then \
			echo -n "FAILS ($$exit_code)\t"; \
		else \
			echo -n " *OK*\t\t"; \
			fi; \
		echo "$$file"; \
		done; \
	echo "--- TESTING END ---"
Post Reply