GuLearn
GuLearn

Reputation: 1864

No rule to make XXX error in GNU make

I'm new to Makefile. While trying to write a generic Makefile which could be used in most of my projects with least modification, I encountered a problem (simplified as the following):

My "project" looks like:

proj/
    src1.cpp
    subdir1/
        src2.cpp
    Makefile

Part of the Makefile:

OBJ := bin/src1.o bin/subdir1/src2.o
OBJ_DIR := bin/ bin/subdir1/
PROGRAMS := prog1
define compile_template =
$(1)/%.o: %.cpp
    mkdir -p $$(@D)
    $$(CXX) $$(CXXFLAGS) -c $$< -o $$@
endef

define PROGRAM_template =
$(1): $$(OBJ)
    $$(CXX) $$(LDFLAGS) $$^ -o $$@ $$(LDLIBS)
endef

$(foreach odir,$(OBJ_DIR),$(eval $(call compile_template,$(odir))))
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))

And the error is:

gmake: *** No rule to make target `bin/src1.o', needed by `proj1'.  Stop.

Another question is should I wrote my own Makefile or use automake etc if I only compile in particular machines (So I have control to the compiler, OS, ...)?

Upvotes: 0

Views: 622

Answers (1)

MadScientist
MadScientist

Reputation: 101051

The best way to debug issues like this (problems with eval) is to replace the $(eval ...) function with a call to $(info ...). This will print out the text that make is parsing and it's usually pretty obvious what your problem is. If you rewrite your eval lines to this:

$(foreach odir,$(OBJ_DIR),$(info $(call compile_template,$(odir))))
$(foreach prog,$(PROGRAMS),$(info $(call PROGRAM_template,$(prog))))

(and fixing your obvious syntax error, the space between : and = in the first line) you see:

bin//%.o: %.cpp
        mkdir -p $(@D)
        $(CXX) $(CXXFLAGS) -c $< -o $@
bin/subdir1//%.o: %.cpp
        mkdir -p $(@D)
        $(CXX) $(CXXFLAGS) -c $< -o $@
prog1: $(OBJ)
        $(CXX) $(LDFLAGS) $^ -o $@ $(LDLIBS)

From this you can see the prog1 depends on bin/src1.o and bin/subdir1/src2.o so make wants to build bin/src1.o. It looks through your rules, but in make's internal matching syntax bin//%.o does not match bin/src1.o because of the extra slash.

Change your assignment to remove the trailing slash and it should work better:

OBJ_DIR := bin bin/subdir1

Upvotes: 3

Related Questions