Reputation: 177
I would like the following makefile to be capable of compiling multiple executables:
CXX = clang++
CXXFLAGS = -g -Wall --std=c++11
OBJS = two_rung.o three_rung.o dumbinterp.o interp.o writeLadderMPO.o
PROG = two_rung three_rung dumbinterp interp
SOURCES = two_rung.cc three_rung.cc dumbinterp.cc interp.cc writeLadderMPO.cc
HEADS = writeLadderMPO.h
INCLUDES = -I $(HOME)/ITensor
LIBS = -L $(HOME)/ITensor/lib -litensor -lstdc++ -framework Accelerate
all: $(PROG)
$(PROG): $(OBJS)
$(CXX) $(INCLUDES) -o $(PROG) $(OBJS) $(LIBS)
%.o: %.cc $(HEADS)
$(CXX) $(INCLUDES) -c -o $(OBJS) $(SOURCES)
The executables are denoted by PROG
. When I try to make one of these executables, for example interp
, I get instead
Computer:folder username$ make interp
clang++ -I /Users/username/ITensor -c -o two_rung.o three_rung.o dumbinterp.o interp.o writeLadderMPO.o two_rung.cc three_rung.cc dumbinterp.cc interp.cc writeLadderMPO.cc
Which is to say, Make is just tossing all the files in when I call them as variables, which totally makes perfect sense. But I want it to behave like:
clang++ -I /Users/username/ITensor -c -o interp.o interp.cc
and then
clang++ -I /Users/username/ITensor -o interp interp.o -L $(HOME)/ITensor/lib -litensor -lstdc++ -framework Accelerate
How do I get Make to do this? Thanks!
Upvotes: 1
Views: 1541
Reputation: 29270
I don't know what make you have and what it supports, but if you are using GNU make, you could probably use static pattern rules and automatic variables ($@
: target, $^
: prerequisites, $<
: first prerequisite). You could also use some make functions (wildcard
and patsubst
) to automate the discovery of sources and deduce the list of object files. Something like:
CXX = clang++
CXXFLAGS = -g -Wall --std=c++11
SOURCES = $(wildcard *.cc)
OBJS = $(patsubst %.cc,%.o,$(SOURCES))
PROG = two_rung three_rung dumbinterp interp
HEADS = writeLadderMPO.h
INCLUDES = -I $(HOME)/ITensor
LIBS = -L $(HOME)/ITensor/lib -litensor -lstdc++ -framework Accelerate
all: $(PROG)
$(PROG): %: %.o writeLadderMPO.o
$(CXX) -o $@ $^ $(LIBS)
%.o: %.cc $(HEADS)
$(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $@ $<
The $(PROG): %: %.o...
rule is a static pattern rule. See the GNU make documentation for a complete description.
Note: I removed $(INCLUDES)
from the link recipe, it is useless. But I added $(CXXFLAGS)
in the compile recipe because it was probably missing.
Upvotes: 1
Reputation: 409356
To expand on my comments.
Consider the rule
$(PROG): $(OBJS)
$(CXX) $(INCLUDES) -o $(PROG) $(OBJS) $(LIBS)
This will be expanded by make
into
two_rung three_rung dumbinterp interp: two_rung.o three_rung.o dumbinterp.o interp.o writeLadderMPO.o
clang++ -I $(HOME)/ITensor -o two_rung three_rung dumbinterp interp two_rung.o three_rung.o dumbinterp.o interp.o writeLadderMPO.o -L $(HOME)/ITensor/lib -litensor -lstdc++ -framework Accelerate
Not quite what you had in mind I think.
Instead you need to specify each executable target and dependencies explicitly:
two_rung: two_rung.o writeLadderMPO.o
three_rung: three_rung.o writeLadderMPO.o
dumbinterp: dumbinterp.o writeLadderMPO.o
interp: interp.o writeLadderMPO.o
With the flag variables set up correctly then make
will link those correctly.
As for the compilation of the source files into object files, you have problems there too, where
%.o: %.cc $(HEADS)
$(CXX) $(INCLUDES) -c -o $(OBJS) $(SOURCES)
will be expanded to
%.o: %.cc writeLadderMPO.h
clang++ -I $(HOME)/ITensor -c -o two_rung.o three_rung.o dumbinterp.o interp.o writeLadderMPO.o two_rung.cc three_rung.cc dumbinterp.cc interp.cc writeLadderMPO.cc
That's not really how it work, you need to create each object file from each source file separately. Fortunately you can still use the same basic rule, but don't need to provide the command to create the object file:
%.o: %.cc $(HEADS)
That's almost it, no command needed. However then you also need to do e.g.
CXXFLAGS += $(INCLUDES)
before this rule.
Upvotes: 2