Compile multiple **changed** source files at once in GNU make
I know there have been several questions with similar titles but none seem to provide an answer to what I need (correct me if I'm wrong).
Consider this makefile:
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $@ $(OBJECTS)
file1.o: file1.cpp file1.h
file2.o: file2.cpp file2.h file1.h
file3.o: file3.cpp
.cpp.o:
$(CXX) $(CXXFLAGS) -c -o $@ $<
If I change file1.h, the following is run:
g++ -c -o file1.o file1.cpp
g++ -c -o file2.o file2.cpp
g++ -o myprog file1.o file2.o file3.o
What I would like to have is:
g++ -c file1.cpp file2.cpp
g++ -o myprog file1.o file2.o file3.o
(I know I can't specify object output directory with GCC, but this I can live with; it should be possible to work around with some cd
commands.)
In nmake, this is done with a double-colon inference rule (so-called called "batch-mode rule"). Basically, it groups the inference rules (e.g.开发者_如何转开发 ".obj.cpp:") for multiple targets and invokes the compiler for all dependencies instead of once per file. The $<
variable gets the list of dependencies instead of just the first one.
Right now we're using parallel building (make -j) but it has its own issues, and VC++ compiler works much better in one-invocation mode so I'd prefer using that.
I don't see why you want this effect, but here's how to get it (in GNUMake):
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
$(EXECUTABLE): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $?
$(CXX) -o $@ $(OBJECTS)
EDIT:
I'm surprised that that solution works -- there's something wrong with my idea of what Make does -- but I don't think it'll work in your case, with header dependencies, without the following kludge. (There are one or two other approaches that might work, if this doesn't pan out.)
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) -o $@ $(OBJECTS)
file1.cpp: file1.h
file2.cpp: file2.h file1.h
$(SOURCES):
@touch $@
$(OBJECTS): $(SOURCES)
$(CXX) $(CXXFLAGS) -c $?
@touch $(OBJECTS)
You can make GNUmake do what you want by collecting the files to be rebuilt in the build rule and then actually building them when you link:
SOURCES=file1.cpp file2.cpp file3.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=myprog
all: $(EXECUTABLE)
.PHONY: build_list
build_list:
-rm -f build_list
$(OBJECTS): %.o: %.cpp | build_list
echo $< >> build_list
$(EXECUTABLE): build_list $(OBJECTS)
if [ -r build_list ]; then $(CXX) $(CXXFLAGS) -c `cat build_list`; fi
$(CXX) -o $@ $(OBJECTS)
file1.o: file1.h
file2.o: file2.h file1.h
精彩评论