Diffycue
Diffycue

Reputation: 177

Compiling multiple executables with make

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

Answers (2)

Renaud Pacalet
Renaud Pacalet

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

Some programmer dude
Some programmer dude

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

Related Questions