Ganesh
Ganesh

Reputation: 33

How to get prerequisites with respect to the target in Makefile (GNU Make)?

Is there a way to get the prerequisite corresponding to a target in the Makefile (GNU Make)?

For instance, consider the following Makefile:

CXX = g++
CFLAGS = -Wall
MODULE_NAME = myRenderer
BUILD_DIR = bin

SOURCE_FILES = renderer/tracer.cpp renderer/lights/DiffuseLight.cpp renderer/materials/ScatterUtils.cpp
OBJECT_FILES = $(patsubst %,$(BUILD_DIR)/%, $(notdir $(SOURCE_FILES:.cpp=.o)))

$(BUILD_DIR)/$(MODULE_NAME): $(OBJECT_FILES)
    $(CXX) -o $@ $^

$(OBJECT_FILES): $(SOURCE_FILES)
    @mkdir -p "$(BUILD_DIR)"
    $(CXX) $(CFLAGS) -I. -c $< -o $@

when I run make, I can see that the following commands get executed:

g++ -Wall -I. -c renderer/tracer.cpp -o bin/tracer.o
g++ -Wall -I. -c renderer/tracer.cpp -o bin/DiffuseLight.o
g++ -Wall -I. -c renderer/tracer.cpp -o bin/ScatterUtils.o
g++ -o bin/myRenderer bin/tracer.o bin/DiffuseLight.o bin/ScatterUtils.o

And obviously, this fails to build the executable as it's using only the first prerequisite i.e. renderer/tracer.cpp to generate all the object files because I am using the $< automatic variable in the recipe command for the $(OBJECT_FILES) target.

I wish to know how to fix my Makefile to be able to execute these commands:

g++ -Wall -I. -c renderer/tracer.cpp -o bin/tracer.o
g++ -Wall -I. -c renderer/lights/DiffuseLight.cpp -o bin/DiffuseLight.o
g++ -Wall -I. -c renderer/materials/ScatterUtils.cpp -o bin/ScatterUtils.o
g++ -o bin/myRenderer bin/tracer.o bin/DiffuseLight.o bin/ScatterUtils.o

I cannot seem to find the right automatic variable or a way to fetch the right source file to build a given object file.

Upvotes: 0

Views: 1580

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 28920

As suggested by Matt you have (at least) two options:

  1. A compilation rule:

    # $(1): source file
    define MY_RULE
    $$(patsubst %.cpp,$$(BUILD_DIR)/%.o,$$(notdir $(1))): $(1)
        @mkdir -p "$$(BUILD_DIR)"
        $$(CXX) $$(CFLAGS) -I. -c $$< -o $$@
    endef
    $(foreach f,$(SOURCE_FILES),$(eval $(call MY_RULE,$(f))))
    

    Note the $$ used to escape the first expansion (see The eval Function for a detailed explanation).

  2. The vpath directive:

    vpath %.cpp $(dir $(SOURCE_FILES))
    
    $(BUILD_DIR)/%.o: %.cpp
        @mkdir -p "$(BUILD_DIR)"
        $(CXX) $(CFLAGS) -I. -c $< -o $@
    

Upvotes: 1

Related Questions