1

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!

3
  • You need to set up each program and its dependencies separately. Also, I assume not all programs depends on all object files? Commented Jul 26, 2017 at 5:51
  • @Someprogrammerdude Could you be more specific about what that entails? Thanks! Also, yes, each program only depends on its corresponding .o file. Commented Jul 26, 2017 at 5:52
  • Furthermore, your creation of object file, don't put any commands there, instead let make use implicit rules for that. Just add INCLUDES to CXXFLAGS and make should do the right thing (which you don't do). Commented Jul 26, 2017 at 5:53

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you; this is essentially what I was doing before and my hope was that there existed a less cumbersome method where I wouldn't have to muck around in the makefile with every new program (I have many more than are I've kept in the post). I guess this is too much to ask for?
@Diffycue You're using macOS and I don't know how much its "native" make programs differs from the more common GNU make program. But if it have functions then there probably is a $(foreach ...) or similar function, which could be used to generate the executable rules. I haven't searched thoroughly, so I don't have a link to the macOS make documentation, but you should probably find it and read it for such functions and experiment with them.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.