Makefile to archive/link together auto-generated source files
-
06-07-2019 - |
Question
Basically, I have a file 'blah.txt'. That files gets parsed by a 'compiler' and from it will generate N output .c files. I want a makefile that will from that .txt file generate the c files then compile all of them and archive them in a libmystuff.a
I tought of something like this :
all: dogen libmystuff.a
dogen: source.txt
mycompiler $^
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $@ $^
.PHONY: dogen
But obviously that doesn't work because the dependencies are evaluated at the start and at that point the *.c just doesn't yield anything yet since they don't exist.
Does anyone see how to accomplish that (without listing all the generated *.c explicitely) ?
Solution
Pavel Shved is right(*), you must rerun Make. Here is a trick I'm rather proud of. It will handle dependencies on objects that may not yet exist, and won't run unnecessarily.
SOURCES = $(wildcard *.c) OBJECTS = $(SOURCES:.c=.o) all: libmystuff.a ifeq ($(MAKELEVEL),0) libmystuff.a: source.txt mycompiler $^ @$(MAKE) -s $@ else libmystuff.a: $(OBJECTS) $(AR) rcs $@ $^ endif
(*) My old nemesis, we meet again.
EDIT:
If some other make calls this make... I hadn't thought of that. But I think this will solve it:
SOURCES = $(wildcard *.c) OBJECTS = $(SOURCES:.c=.o) all: libmystuff.a libmystuff.a: source.txt mycompiler $^ @$(MAKE) -s phonyLib .PHONY: phonyLib phonyLib: $(OBJECTS) $(AR) rcs libmystuff.a $^
(Yes, I know, if you feel an urge to build a file called "phonyLib" you won't be able to do it with this makefile, but let's not be perverse.)
OTHER TIPS
Use sentry "makefile" to force make to re-read makefile and substitute correct list at *.c
:
include sources-sentry
sources-sentry: source.txt
mycompiler $^
touch $@
libmystuff.a: $(addsuffix .o, $(shell ls *.c))
$(AR) rcs $@ $^
include
directive is used to include other makefiles (just like C's #include
). It has a nice pecularity that if makefile it includes is a target itself, make
program first considers it as a target and tries to update. If it is not up-to-date, make invokes the commands needed to update it and then re-reads makefile, substituting all the variables again.
Thus, if source.txt changed since the last time you processed it (the time being recorded as timestamp of sources-sentry file), the sources will be updated and make will be re-invoked, the *.c
being substituted to the updates set of c-files.
If your .c files are only produced by the .txt, then you can let the libmystuff.a depend on the txt, and evaluate the $(shell ls *.c) in the rule body instead.