I’m currently working on a project in which there are about 20 c source files and about 8 binary targets. We’re finding the Makefile upkeep fairly difficult and error prone. The main issue is in recording which binaries depend on which object files, because automatic header dependency resolution seems fairly straightforward (but we haven’t yet implemented it).
This is an example of the way our makefile is currently set up. Two programs foo and bar. Foo needs to use functions exported from timestamp.c and bar needs to use functions exported from pretty_print.c which in turn uses timestamp functions to generate time-stamped strings.
foo bar:
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
foo: foo.o timestamp.o
foo.o: timestamp.h
bar: bar.o pretty_print.o timestamp.o
bar.o: pretty_print.h
pretty_print.o: pretty_print.h timestamp.h
timestamp.o: timestamp.h
Is there a better way to do this (apart from automatic generation of the foo.o and bar.o lines)? I feel as though there must be a better way than writing that bar depends on timestamp.o when it doesn’t include timestamp.h. This is the source of most mistakes actually. It is not until the linker can’t find symbol “create_timestamp” that we realise that pretty_print relies on functions from timestamp. Perhaps this is just the way it works?
Linking is still a relatively traditional part of the build process. Adding another source file is an infrequent and relatively heavyweight (create new source and header files, add to source control, add copyright boilerplate) task, so there hasn’t been a lot of pressure to automate the comparatively trivial subtask of adding one more object file to a couple of link recipes.
So in fact I would write this in an even more straightforward way:
If you really want to avoid worrying about which binary targets need which miscellaneous object files, you can divide the object files into the canonical ones corresponding to each binary target (
foo.o,bar.o, etc) and miscellaneous others, and put the latter into a miscellaneous linker library:Then linking each binary target (
foo,bar) will only pull in exactly the miscellaneous object files that it needs.