how do you make a *good* makefile?

Programming, for all ages and all languages.
User avatar
Love4Boobies
Member
Member
Posts: 2111
Joined: Fri Mar 07, 2008 5:36 pm
Location: Bucharest, Romania

Re: how do you make a *good* makefile?

Post by Love4Boobies »

Solar wrote:
However, I'm not entirely sure how this is supposed to work. I can only think of a hack: redirecting stdout to a file (as -M outputs to the screen) and then including that. Can anyone give a proper example how this can be used?
Makefile?
Oops #-o Thanks, it works like a charm :)
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
User avatar
Steve the Pirate
Member
Member
Posts: 152
Joined: Fri Dec 15, 2006 7:01 am
Location: Brisbane, Australia
Contact:

Re: how do you make a *good* makefile?

Post by Steve the Pirate »

Solar wrote:For an out-of-tree build, you'd have to copy the makefile into the build directory first. For the "usual" out-of-tree builds you know from e.g. the GNU tools, you start with ../<sourcetree>/configure, which creates the Makefile in the current (build) directory.
OK, after a bit of investigationing ( :D ) I've got it half working, but I haven't got the whole multiple directories thing going. Here's the really simple makefile, which would be in /src/build (where the objects will go):

Code: Select all

test: main.o lib/test.o
        g++ $(LDFLAGS) -o test main.o lib/test.o 

%.o: ../%.cc
        g++ $(CXXFLAGS) -c $< -o $@
Running a 'make main.o' works fine. It compiles it, and the object file ends up in the right place. Trying to build lib/test.o fails though...

EDIT: OK, if I put a rule like 'lib/%.o: ../lib/%.cc', it does work. It is a big improvement already, but is there a way to do it without having a rule for each directory?
My Site | My Blog
Symmetry - My operating system.
User avatar
Steve the Pirate
Member
Member
Posts: 152
Joined: Fri Dec 15, 2006 7:01 am
Location: Brisbane, Australia
Contact:

Re: how do you make a *good* makefile?

Post by Steve the Pirate »

Well, I had a crack at making a big new kernel makefile, and it all seems to work!

How's this:
Old Busted
New Hotness

It puts the kernel binary, disk image and initrd archive all in the build folder. All the object files go either in the top of the build directory (if they are in the top of the kernel source folder), or in a folder in build that corresponds to its folder in the source tree. So kernel/lib/string.cc becomes build/lib/string.o.
My Site | My Blog
Symmetry - My operating system.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: how do you make a *good* makefile?

Post by FlashBurn »

I didn´t want to start a new thread for my makefile problem.

I have a working makefile, but I want to seperate my src dir and my build dir. So that I have the srcs in some "src" dir and the object files in a "build" dir (here is also my makefile). My makefile does work if I run it in the src dir (w/o the PREFIX var), but doesn´t work in my build dir.

This is my makefile:

Code: Select all

CC = i586-elf-gcc
LD = i586-elf-ld
CFLAGS = -O2 -Wall -nostartfiles -nodefaultlibs -nostdlib -fno-builtin -march=i586 -I $(PREFIX)include
LDFLAGS = -nostdlib -T $(PREFIX)loader.ld
PREFIX = ../src/
SRCS = loader.c printf.c hardware.c memory.c string.c iso9660.c fs.c fat.c fat12.c fat16.c fat32.c cfg.c module.c elf.c idt.c pic.c pit.c kbd.c apic.c
OBJS = $(SRCS:%.c=%.o)
DEPENDFILE = .depend

all: dep loader iso

dep: $(SRCS:%=$(PREFIX)%)
	$(CC) -M $(SRCS:%=$(PREFIX)%) -I $(PREFIX)include > $(DEPENDFILE)

-include $(DEPENDFILE)

loader: loader_stub.o $(OBJS)
	$(LD) loader_stub.o $(OBJS) -o osloader $(LDFLAGS)
	
loader_stub.o: smp_startup.o loader_16bit.o $(PREFIX)loader.asm
	nasm -O3 $(PREFIX)loader.asm -f elf -o loader_stub.o
	
loader_16bit.o: $(PREFIX)loader_16bit.asm
	nasm -O3 $(PREFIX)loader_16bit.asm -f bin -o loader_16bit.o

smp_startup.o: $(PREFIX)smp_startup.asm
	nasm -O3 $(PREFIX)smp_startup.asm -f bin -o smp_startup.o

iso:
	cp osloader ../../../cd-rom

clean:
	-rm -f osloader
	-rm -f *.o
	-rm -f *.s
	-rm -f $(DEPENDFILE)
I have the dirs like this: a dir "loader" with the subdirs "build" and "src" and this makefile is in the dir "build" and it also gets called from there. When I´m doing this I get the following error: "no rule to make target loader.o"! Creating the ".depend" file is working and it looks like it should. If I copy and paste the loader.o rule it works for this object file. But it should work for all object files. The only thing that I changed from my working makefile are the things with the $(PREFIX) var.

I hope you can help me with this.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: how do you make a *good* makefile?

Post by Solar »

You don't have a rule for .o files.

Code: Select all

%.o: %.c Makefile
        @$(CC) $(CFLAGS) -c ${PREFIX}$< -o $@
There are several other points I would improve (like, not having to edit the Makefile when I add a source file), but this rule should get you going.
Every good solution is obvious once you've found it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: how do you make a *good* makefile?

Post by FlashBurn »

Thanks for your help, but I found a solution myself. I only needed to add "VPATH = $(PREFIX)" and it works now.

I want to edit the makefile every time I add a source file, because I have some .c files which should not get compiled and linked.

I don´t know if I´m right, but with your solution it would not work, if I changed a header file that only the files get recompiled which include this header file!?

Also what are the other points you would improve my makefile? I´m always open for learning new things and making things better!
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: how do you make a *good* makefile?

Post by Solar »

FlashBurn wrote:I want to edit the makefile every time I add a source file, because I have some .c files which should not get compiled and linked.
Put them in a different directory?

In PDCLib (my project), I explicitly excluded all .c files on the top directory level from compilation, which allows me to have e.g. "test.c" and "test2.c" in my working dir without screwing up my make process.
I don´t know if I´m right, but with your solution it would not work, if I changed a header file that only the files get recompiled which include this header file!?
Dependencies are cumulative, i.e. the dependencies from your DEPFILE would still apply. My rule states the .c file as dependency so that I can use the implicit variables $@ and $< in the command line.
Also what are the other points you would improve my makefile? I´m always open for learning new things and making things better!
Don't define CC or LD within your Makefile. They are for the user to override. Use ${CC} instead of 'gcc', but don't define it; 'make' will use a sensible default if it isn't defined, or use whatever the user did set to override it. See the 'make' manual for a list of these variables, and their defaults. I would even consider not defining CFLAGS and LDFLAGS either, as they are similarily used for user overrides.

Your targets 'dep' and 'loader' don't create a file of the same name, but '.depend' and 'osloader', respectively. That means those files get re-made every time, no matter if they're outdated or not. Use 'depend.d' (or something else) as both dependency file name and Makefile target, and either rename the 'loader' target to 'osloader', or the file 'osloader' to 'loader'.

Add '.PHONY: all iso clean' to state that those three targets should always be re-made, even if an up-to-date file of that name already exists. (Try 'touch clean', and your 'make clean' won't get executed unless you remove that file 'clean' again. ;-) )

Try to replace:

Code: Select all

loader_16bit.o: $(PREFIX)loader_16bit.asm
   nasm -O3 $(PREFIX)loader_16bit.asm -f bin -o loader_16bit.o

smp_startup.o: $(PREFIX)smp_startup.asm
   nasm -O3 $(PREFIX)smp_startup.asm -f bin -o smp_startup.o
with:

Code: Select all

%.o: $(PREFIX)%.asm
        nasm -O3 $(PREFIX)$< -f bin -o $@
Not sure if it works for your $PREFIX magic, but that way you can state generic rules, instead of repeating them for every file.
Every good solution is obvious once you've found it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: how do you make a *good* makefile?

Post by FlashBurn »

Thanks for your tips, I try if I can use them. The last one isn´t possible (I think so), because I need that these 2 files are assembled before the loader.asm, because their binaries are included into this loader.asm.

One thing I don´t really get and these are the things you said about CC and so on. I define them because otherwise the standard CFLAGS/LDFLAGS and CC are used and this doesn´t work because I´m on windows (cygwin) and I use a crosscompiler. I think I saw a makefile which also did this, but it checks on which os it is running on and then sets these vars.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: how do you make a *good* makefile?

Post by Solar »

FlashBurn wrote:The last one isn´t possible (I think so), because I need that these 2 files are assembled before the loader.asm, because their binaries are included into this loader.asm.
Doesn't matter. The dependencies of loader_stub.o require smp_startup.o and loader_16bit.o to be present; 'make' is smart enough to see there are corresponding .asm files and a .asm - to - .o rule available, and will build the required object files using that rule.
One thing I don´t really get and these are the things you said about CC and so on. I define them because otherwise the standard CFLAGS/LDFLAGS and CC are used and this doesn´t work because I´m on windows (cygwin) and I use a crosscompiler. I think I saw a makefile which also did this, but it checks on which os it is running on and then sets these vars.
It's a personal thing. I'd leave CC and CFLAGS out of the Makefile and would set them in my environment. But then, I'm a pedant. ;-)
Every good solution is obvious once you've found it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: how do you make a *good* makefile?

Post by FlashBurn »

The make that I use isn´t smart enough to do the things you thought it would do ;) I just tested it.

I come across a new problem now. I used the same style makefile for my kernel and it works as long as I´m in the src dir, but if I´m in the build dir make errors because it can´t find a rule for making ".depend", but the makefile is the same as the one which works, except for the prefix magic. Maybe you have a tip what this could be? If not its no problem, because I´m still working on completing my loader.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: how do you make a *good* makefile?

Post by Solar »

Sorry, haven't delved into seperate build directories myself. All I could do is reading the make manual, and I guess you can do that just as well as I. ;-)
Every good solution is obvious once you've found it.
FlashBurn
Member
Member
Posts: 313
Joined: Fri Oct 20, 2006 10:14 am

Re: how do you make a *good* makefile?

Post by FlashBurn »

I did, but as always there are some tricks which haven´t to be in the manual ;) But thanks, I have a working makefile for a separate build dir and the problems with the kernel makefile can wait.
Post Reply