OSDev.org
https://forum.osdev.org/

Makefile troubleshooting (and proper practice)
https://forum.osdev.org/viewtopic.php?f=13&t=30892
Page 1 of 1

Author:  Mikumiku747 [ Mon Oct 10, 2016 3:44 am ]
Post subject:  Makefile troubleshooting (and proper practice)

Hello everyone, I think this should be the correct place to post this, but let me know if it belongs somewhere else. I use a pretty standard linux-style build system to compile my OS kernel (GNU cc, as, make, etc.) which includes a makefile for the kernel. I was having a bit of trouble with make, and was wondering if people know why this is happening or what I can do to fix the problem. For reference, the full makefile is here.

My makefile isn't too complex for the most part, the top half of it contains mostly definitions of stuff like paths, tools, and command options. In order to save myself having to add a new recipe every time I add a new file, the makefile "generates" a list of files it needs to build using the wildcard and patsubst commands in make, here's a snippet of how I do that:
Code:
KERN_C_ARCH_SOURCES := $(wildcard $(KERN_ARCH_SRC)/*.c)
KERN_C_ALL_SOURCES := $(wildcard $(KERN_ALL_SRC)/*.c)
KERN_C_ARCH_OBJS := $(patsubst $(KERN_ARCH_SRC)/%.c, obj/%.o, $(KERN_C_ARCH_SOURCES))
KERN_C_ALL_OBJS := $(patsubst $(KERN_ALL_SRC)/%.c, obj/%.o, $(KERN_C_ALL_SOURCES))

These definitions search a directory for all the C files, and then generate a list of all the object files that those C files need to be compiled to. There's two lists, one for stuff in the architecture dependent sources, and one for stuff in the architecture independent sources.

Once these lists of files are created, I use some recipes to compile them, like so:
Code:
obj/%.o: $(KERN_ARCH_SRC)/%.c obj
   $(KERN_CC) $(KERN_CC_OPTS) $(KERN_C_INCLS) -c $< -o $@
obj/%.o: $(KERN_ALL_SRC)/%.c obj
   $(KERN_CC) $(KERN_CC_OPTS) $(KERN_C_INCLS) -c $< -o $@

This shouldn't be super complicated. The final link of the kernel requires all the files in the object file list, so this recipe should match those and compile them all. The process for assembly files is pretty similar, it just uses GNU as instead of gcc. Again, there's a link to the full makefile at the top if you want to see the whole thing.

So, if you have a i686-elf cross compiler, you might want to try actually downloading the repo and running "make bin/i686-elf-kernel.bin" to get it to compile just the kernel binary. Hopefully it should work the first time you try it (I can't guarantee it, I've only tested it on my own PCs), but if you run it again, you'll notice that instead of saying "nothing to be done", it goes ahead and makes everything again. This is unintended behaviour from my point of view, and while it's fine to recompile everything now when there's only about 15-20 object files to do, it's pretty quick. But later on, if I had 2000 object files to make, this would be awfully slow, and kind of defeat the purpose of using make. So, that's my first question, why is it making everything again? Is something weird happening with last modified time stamps, or is there a critical flaw in the design of my makefile. I think that it probably has something to do with the way I generate lists of files to be built, but I can't think of another way to do it, and from my understanding of how make works, it should be properly excluding files with no changes. Which leads into my second question.

My second question is, what's the considered "Good practice" when I have a project like this. Specifically, I don't want to edit a "List of files to be built" every time I add a new file to my project, that was how I did it before, and it got very tedious, very quickly, and was highly prone to mistakes (I would spend ages looking for typos and bugs when the linker couldn't find stuff, only to realise it wasn't being compiled in the first place). What are some other methods of coming up with dependencies at run-time? My current method works in terms of getting the job done, but it seems to have problems figuring out what work actually needs to be done. I'm happy to just hear about the way other people's makefiles work as well, it would be interesting to see how other people do their build systems.

- Mikumiku747

Author:  iansjack [ Mon Oct 10, 2016 5:04 am ]
Post subject:  Re: Makefile troubleshooting (and proper practice)

I suspect that your problem lies in the two rules:
Code:
bin:
   mkdir -p bin
obj:
   mkdir -p obj

Try removing them, and all dependencies on "bin" and "obj" from the makefile. You really shouldn't need rules to recreate an existing directory structure.

Author:  MichaelFarthing [ Mon Oct 10, 2016 5:11 am ]
Post subject:  Re: Makefile troubleshooting (and proper practice)

Also, it looks as if you remove them at the end, in which case the .o file goes and so must be rebuilt whether the .c file has changed or not (or am I missing something here)?

Author:  Mikumiku747 [ Mon Oct 10, 2016 6:01 am ]
Post subject:  Re: Makefile troubleshooting (and proper practice)

iansjack wrote:
I suspect that your problem lies in the two rules:
Code:
bin:
   mkdir -p bin
obj:
   mkdir -p obj

Try removing them, and all dependencies on "bin" and "obj" from the makefile. You really shouldn't need rules to recreate an existing directory structure.


Yep, that worked indeed, thanks for the help :). If it's not too much hassle, can you explain why these cause problems? I don't see how they should, since they should just see that the folder exists and realise that the dependency is satisfied. Or is it messing with the time stamps in some way?

- Mikumiku747

Author:  iansjack [ Mon Oct 10, 2016 6:14 am ]
Post subject:  Re: Makefile troubleshooting (and proper practice)

I believe that make considers all targets, except some pre-defined ones, to be files and this is causing the problem.

Have a look at "phony targets": https://www.gnu.org/software/make/manua ... rgets.html

Author:  Boris [ Mon Oct 10, 2016 10:59 am ]
Post subject:  Re: Makefile troubleshooting (and proper practice)

I generate my makefiles using scripts.
Each generated rule has a mkdir -p command.
Yup, I have to call the script each time I add/remove a file.
But that way I'm sure to never re-compile something that was already up to date.

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/