views:

58

answers:

1

I have a make file of, more or less, the following structure that compiles C++ source code:

.PHONY: all
all: compile_obj_files my_binary

# This rule generates the object files. It works fine afaik.
.PHONY: compile_obj_files
compile_obj_files:
    $(MAKE) --file=child.makefile

# my_binary is a real binary file that I wish to build.
my_binary: $(wildcard *.o)
    $(CC) $(wildcard *.o) -o my_binary

On the first run this make file generated all the object files but $(wildcard *.o) returned an empty list. On the second run it compiled nothing, as expected, and $(wildcard *.o) indeed returned all the object files. It looks like $(wildcard *.o) is executed before all the object files are created, despite the fact that my_binary rule runs always after compile_obj_files. I sit looking helpless on this script without any idea what is wrong here (must be something silly). Can you think of anything?

+3  A: 

You should really not use $(wildcard ...) inside rules, but rather do something like

MYSRC:=$(wildcard *.c)
MYOBJ:=$(patsubst %.c, %.o, $(MYSRC))

%.o: %.c
        $(CC) -c $< -o $@

my_binary: $(MYOBJ)
        $(CC) $^ -o $@

This way you know that MYSRC and MYOBJ match. Also note the use of $< to denote the dependency of the current target and $@ to denote the target filename of the current target.

EDIT: Changed $< to $^ in the link step to include all object files, not just the last one.

EDIT: If you don't want to extract the source filenames from child.makefile, you should be able to do something like this:

.PHONY: all
all: 
    $(MAKE) --file=child.makefile
    $(MAKE) my_binary OBJS="$(wildcard *.o)"

my_binary: $(OBJS)
    $(CC) $< -o my_binary

The important part is that the value of OBJS is consistent when building my_binary. This way, you clearly split the build into two steps, and the list of object files is read before executing the second make.

JesperE
Thanks. I'm not sure I can implement this solution easily. My files are scattered in various directories thus it's hard to compute all the names. That's why it looked easier for me to just check all the compiled objects. I'll try to implement it, but nevertheless, why didn't my solution work? Isn't my wildcard expression supposed to be evaluated when the rule is solved?
FireAphis
+1, This was essentially what I would have said. Note that the ':=' makes it recalculate when used. If you instead used '=', it would only calculate the value once at the top.
T.E.D.
T.E.D., actually it's the other way around. Here's the quote from GNU Make manual: "Simply expanded variables are defined by lines using ':='. The value of a simply expanded variable is scanned once and for all (...) it contains their (variables') values as of the time this variable was defined." http://www.gnu.org/software/make/manual/html_node/Flavors.html
FireAphis
JasperE, why shouldn't I use $(wildcard) inside rules?
FireAphis
You don't want to expand `$(wildcard ...)` each time the rule is evaluated. In the rule's command you want to use automatic variables such as `$<` and `$^` to refer to the rule's dependencies.
JesperE
Edited post with another suggestion on how to solve the problem without having to know anything about the source files.
JesperE