views:

440

answers:

3

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) ?

+2  A: 

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.

ankon
Well, I need the makefile to actually compile the .c and elsewhere in the makefile, there are rule to indicate how to convert .c to .o with options and stuff and I don't want to have to repeat all that logic inside the libmystuff.a target.
246tNt
+1  A: 

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.

Pavel Shved
Works great, just one problem tough: When I make the clean target, it builds the thing too ...
246tNt
@246tNt , you are right, and I don't have a solution to this problem :-(
Pavel Shved
+1  A: 

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.)

Beta
Oh, I wont nitpick on *that*! Rather, I'd do ... oh, never mind :)
Pavel Shved
Thanks, that works well and handles the 'clean' case better.
246tNt
I'm so owned X)
Pavel Shved
You've been in this forum half as long as I have and won four times the reputation, AND English isn't your native language, so try to fight back the bitter tears.
Beta
But knowing `make` is really the thing I'm proud of... was, actually. :-) Anyway, these discussions really improved my knowledge. Particularly, I should revamp my approach to recursive `make` invocation vs. including dummy makefiles. (And now I'll be shy trying to comment your posts in English.)
Pavel Shved
Oh, for the love of... Your English is fine (and if I tried commenting in Russian, nobody would be able to read it, including Russians). And I thought I knew all about Make until I started reading your answers.
Beta