Nikita Sivukhin
Nikita Sivukhin

Reputation: 2605

Variable dependent target in makefile

I have a small project for testing and I want to link different implementations of a solution to test.

So, I create makefile that looks like this

CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp

all: instance

instance: instance.cpp .implementation.o
    $(CC) $(FLAGS) instance.cpp .implementation.o -o $@

.implementation.o: $(I_PATH)
    $(CC) $(CFLAGS) $(I_PATH) -o $@

clean:
    -rm .implementation*
    -rm instance

Here, I_PATH is a path to solution implementation. And I want to test different solution passing different implementation via command line arguments: make I_PATH=implementation2.cpp.

But, because of all my implementations compiled to the same object file .implementation.o, make can't understand that something changes and doesn't rebuild project.

Of course, I can call make clean before run make for a specific implementation. But this increase build time (I can run tests for one implementation many times) and not very comfortable.

I can fix this makefile to something like this:

CC=g++
FLAGS=-Wall -O2
CFLAGS=-c $(FLAGS)
I_PATH=implementation1.cpp
C_PATH := $(shell echo -n $(I_PATH) | md5sum | awk '{print ".implementation_" substr($$1, 0, 10) ".o";}')

all: force instance

force_relink: 
    touch -c $(C_PATH)

instance: instance.cpp $(C_PATH)
    $(CC) $(FLAGS) instance.cpp $(C_PATH) -o $@

$(C_PATH): $(I_PATH)
    $(CC) $(CFLAGS) $< -o $@

clean:
    -rm .implementation*
    -rm instance

Here I create I_PATH dependent object file(take hash of path to implementation) and in addition force re-linking instance.cpp with object file every time make runs.

But maybe there is some mechanism in make to fix this behavior? Or I can achieve the same goal with different approaches?

Upvotes: 0

Views: 585

Answers (1)

tripleee
tripleee

Reputation: 189307

Wouldn't it make more sense to give each compiled .o file a distinct name, and simply link to the compiled .o file you want?

instance: instance.cpp $(IMPL_O)
    $(CC) $(FLAGS) $^ -o $@  # propably no need to override default rule

Use make IMPL_O=implementation2.o to generate the example in your question.

This way, the name of each file truly reveals its identity, and you don't have to keep track of anything explicitly.

(Obviously, you could refactor the .o extension into the Makefile itself so you can just say IMPL=implementation2 or whatever.)

Upvotes: 1

Related Questions