ramgorur
ramgorur

Reputation: 2162

makefile picks the same source file again and again for different objects

I am trying to write a makefile, suppose I have 4 source files in a directory src/app/:

src/app/file1.cpp
src/app/file2.cpp
src/app/file3.cpp
src/app/file4.cpp

and I want to create different object files (i.e. file1.o, file2.o etc.) into another directory called obj/. In the makefile, I am defining the variables like this:

$(SRC) := $(wildcard src/app/*.cpp)
$(OBJ) := $(addprefix obj/,$(notdir $(SRC:.cpp=.o)))

and my commands are like this:

all: $(OBJ)

$(OBJ): $(SRC)
    $(CC) $(CFLAGS) -I/src/app/app.h -c $< -o $@

so when I run make, I see these operations:

g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file1.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file2.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file3.o
g++ -g -Wall -I/src/app/app.h -c src/app/file1.cpp -o obj/file4.o

You can see, the object files have different names but the source file is the same. How do I fix it ?

Please note that I can't use %.o: %.cpp since I have other targets in my makefile for different purposes.

Upvotes: 0

Views: 309

Answers (3)

Mark Galeck
Mark Galeck

Reputation: 6405

If you can't use

obj/%.o: src/app/%.cpp

then the second simplest way is to add $(OBJ): to the front:

$(OBJ): obj/%.o: src/app/%.cpp

It's called "static pattern rules" - look it up in the GNU Make manual.

Upvotes: 3

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154045

The $< variable picks up the first dependency. It is used with generic targets which have variable targets and produce different results. The compile target would match a pattern as target and have a generic dependency. The first target doesn't change in your case.

Your constraint of not being able to use a generic rule is entirely defeating the purpose of the $< variable. A somewhat naive work-around is to translate the destination name back into the source, e.g.,

$(OBJ): $(SRC)
    $(CC) $(CFLAGS) -I/src/app/app.h -c $(@:%.o=%.cpp) -o $@ 

The problem with that approach is that no all object files depend on all source files. As a result, every time one of the source files is changed all object files are produced. For tiny projects and source that may be viable. On anything which I'd consider a real project neither of these conditions holds.

My understanding on your statement on not being able to use pattern rules is that you already have rules for the same pattern but you need to build some targets with some special rules. A work around for that situation is to build targets with a custom suffix which actually build something different and just use a marker file to prevent unnecessary rebuilds. For example:

all: $(OBJ:%=%.custom)

%.o.custom: %.cpp
    $(CC) $(CFLAGS) -W -I/src/app/app.h -c $< -o $(@:%.custom=%) && touch $@

Upvotes: 0

ramgorur
ramgorur

Reputation: 2162

I have found a way to solve this (thanks to Zereges for the idea):

$(RGAOBJ): $(RGASRC)
    $(CC) $(CFLAGS) -I/src/app/app.h -c \
        $(addprefix src/app/,$(notdir $(@:.o=.cpp))) -o $@

I think there is a better way to do.

So any other pointer will be helpful.

Upvotes: 0

Related Questions