问题
I have a makefile which runs a binary to generate the cpp files. I then compile the cpp files and generate .o files for each cpp file.
The problem is when the makefile is first invoked, the folder is empty because the binary is not invoked yet and
CPP_FILES=$(wildcard $(MY_DIR)/inc/output/*.cpp)
will be an empty variable.
So I changed the line to
CPPFILES=$$(wildcard $(MY_DIR)/inc/output/*.cpp)
OBJFILES=$$(patsubst $(MY_DIR)/*.cpp,$(MY_DIR)/*.o,$(CPPFILES))
and
//ran the binary to generate the cpp files
.SECONDEXPANSION:
libEXP.so:$(CPPFILES),$(OBJFILES)
$(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) $@
The secondary expansion fails saying shell cannot find wildcard command.
What am I doing wrong??
回答1:
The problem you have is make always works from the ultimate target BACKWARDS to the sources, then starts building and resolving prerequisites back forward again. Make starts with the library, then sees what its prerequisites are, then sees what the prerequisites are for those, then the prerequisites of THOSE, etc. etc.
So, when make expands the $(OBJFILES)
value even if you delay it with second expansion, it's still the case that the .cpp files have not been created yet.
You have to explain to make that there is a rule that can generate the .cpp file. Once make understands that, it will invoke your rule for you. You will not be able to use wildcard to determine the .cpp files to be built, though, unless you want to do something like first build all the .cpp files then recursively invoke make.
Edit:
You asked why second expansion didn't work. I mentioned this in my first paragraph but probably wasn't clear enough. Make goes through two stages of processing. First it reads makefiles, second it runs through the rules and build things. The secondary expansion step delays resolution until that second step... but that's not going to help you in this case.
You ask make to build libEXP.so. To do that it needs to expand the prerequisites of libEXP.so so it knows what the target depends on. THIS is when the second expansion is performed, but here we haven't built any .cpp files yet, because we don't know we need them, so the wildcard expands to nothing. Make won't create those .cpp files until it knows it needs them, and it can't know it needs them until it already has them so it can generate the list of .o files for prerequisites of libEXP.so. This is obviously not going to work :)
回答2:
To make it explicit: you shouldn't use $(wildcard )
on generated files. If you want a "list of all generated files", $(wildcard )
will give you that list only by luck (if all the files have already been generated).
If there is a 1-to-1 correspondence between the generator file and the generated file, then you can use $(wildcard)
on the generator files and transform the result.
Using Google's protocol buffers as an example (it can generate .cc files from .proto files)
PROTOSS := $(wildcard *.proto)
GENERATED_SOURCES := ${PROTOSS:.proto=.cc}
GENERATED_HEADERS := ${PROTOSS:.proto=.h}
回答3:
Leave CPPFILES
and OBJFILES
as usual recursive variables:
CPPFILES = $(wildcard $(MY_DIR)/inc/output/*.cpp)
OBJFILES = $(CPPFILES:%.cpp=%.o)
And to defer the expansion of it use double dollars as follows:
.SECONDEXPANSION:
libEXP.so: $$(OBJFILES)
$(CC) $(CFLAGS) -I(INC) -L(LIBS) -shared -o $(OBJFILES) $@
But I guess that the problem is that the expansion occurs before you run the cpp files generator. How do you invoke it? Is it a rule or something else?
回答4:
I encountered this situation. I tried several layers of indirection (using a canned sequence that called a canned sequence that used wildcard
), but the make always evaluated the wildcard before executing the recipe that generated the files. My solution was to write a Perl script to gather the list of files and execute the operation I needed to perform on them, and then to call the script from the makefile. I only wish I'd done that earlier. I had been thinking that I wanted to avoid introducing an extra file, but in general, it's so much easier to work with a script than a nontrivial makefile recipe that it would have saved a lot of time to do that from the beginning.
回答5:
Another option is to use a for-loop in bash:
target: prereqs
for file in files/*; do \
... \
done
来源:https://stackoverflow.com/questions/9744865/how-to-force-revaluation-of-variables-in-makefile