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.
The file name of the target of the rule. If the target is an archive member, then ' $@ ' is the name of the archive file. In a pattern rule that has multiple targets (see Introduction to Pattern Rules), ' $@ ' is the name of whichever target caused the rule's recipe to be run. $%
Use the command `make' to recompile the source files that really need recompilation. Make the changes in the header files. Use the command `make -t' to mark all the object files as up to date. The next time you run make, the changes in the header files do not cause any recompilation.
The order of rules is not significant, except for determining the default goal: the target for make to consider, if you do not otherwise specify one. The default goal is the target of the first rule in the first makefile. If the first rule has multiple targets, only the first target is taken as the default.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With