Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pass a target name to dependency list in makefile

Tags:

makefile

I am trying to write a makefile to build a set of c++ programs in the same directory that have independent source code, but similar compilation rules and shared dependencies (common headers).

/path/to/project/
    peformance.h
    vector.h
    pqvm.cpp
    quantum/
        quantum-tbb.h
        quantum-sequential.h
        ...
    tests/
        grainsize.cpp
        kronecker.cpp
        sigma-z.cpp
        ...
        Makefile

I want to compile the sources in the tests folder, each source to a corresponding executable. Below is the makefile I am trying to use; there seems to be a problem in the line $(TARGETS): %.o.

I want to refer to the current target's name (e.g. grainsize) and have it depend on its corresponding object file (e.g. grainsize.o), neither %.o nor [email protected] seem to work. I could change the line to $(TARGETS): $(OBJECTS) but then every target would depend on all the objects, triggering a lot of unnecessary recompilation on each change.

So basically: how do I correctly refer to a target name in its dependency list? I am aware of this related question: Passing target name to a dependency in makefile, but I can't see how it would apply to this problem.

CXX     = g++
SOURCES = $(wildcard *.cpp)
DEPS    = ../performance.h $(wildcard ../quantum/*.h) ../vector.h
TARGETS = $(basename $(SOURCES))
OBJECTS = $(addsuffix .o, $(TARGETS))

INCPATH = -I../../local/include
LIBPATH = -L../../local/lib
LIBS    = -lpfm -lpapi -ltbb
OFLAGS  = -Wall -O2
DFLAGS  = -g3
CFLAGS  = -march=native $(OFLAGS) $(DFLAGS) $(INCPATH) $(LIBPATH) -fopenmp

UNAME   = $(shell uname)
ifeq ($(UNAME), Linux)
  LIBS += -lrt
endif

.PHONY: all

all: $(TARGETS)

#for each target: link its object file to the libraries and produce an executable binary
#this does not work as expected
$(TARGETS): %.o
    $(CXX) $(CFLAGS) [email protected] $(LIBS) -o $@

#compile each target to its object file
#this works as expected
%.o: %.cpp $(DEPS)
    $(CXX) -c $(CFLAGS) -o $@ $<

This is the error message on the command line:

$ make
make: *** No rule to make target `%.o', needed by `grainsize'.  Stop.
like image 267
kmoerman Avatar asked Apr 28 '13 11:04

kmoerman


1 Answers

The problem is that this:

$(TARGETS): %.o
    ...

is not a pattern rule; there is a % in the prerequisite list, but not in the target. So Make interprets the % literally, and there's no such file as %.o.

Try this:

$(TARGETS): % : %.o
    $(CXX) $(CFLAGS) $^ $(LIBS) -o $@

This is a static pattern rule. Also, I've changed [email protected] (which would work but is a kludge) to $^ (which means "all of the prerequisites", and is more robust and easier on the eyes).

like image 189
Beta Avatar answered Sep 22 '22 17:09

Beta