0

I've got a general-purpose makefile that I've successfully used for small (personal) projects before, as below:

#Makefile to compile a folder's contents into a program.

PROGNAME := MyProgram

LIBRARIES := 

CXX := g++ --std=c++11
INCLUDES := -Isrc -Ihdr
VPATH := src:hdr

CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(patsubst src/%.cpp,obj/%.o,$(CPP_FILES))

$(PROGNAME): $(OBJ_FILES)
    $(CXX) $(INCLUDES) $(LIBRARIES) $^ -o $@ $(ROOTFLAGS)

#Automatically generate dependencies (-MM), change the target to be the
# object file (-MT) and output it to the dependency file (-MF).
%.d: src/%.cpp
    $(CXX) $(INCLUDES) -MM -MT '$(patsubst src/%.cpp,obj/%.o,$<)' $< -MF $@

obj/%.o: src/%.cpp %.d hdr/%.h
    echo $@
    $(CXX) $(INCLUDES) -o $@ -c $< $(ROOTFLAGS)

.PHONY: clean

clean:
    rm obj/*.o $(PROGNAME)

This is designed for the following directory structure:

ParentFolder/
    Makefile
    hdr/
        file1.h
        ...
    src/
        file1.cpp
        ...
    obj/

I gave the makefile to a colleague and they found it didn't work - after some investigation, the cause of the problem seems to be that they had a source file called main.cpp in src/, which when running make would give the following error:

make: *** No rule to make target `obj/main.o', needed by `MyProgram'.  Stop.

If I rename main.cpp to something else (e.g. test.cpp) then the makefile works as expected.

What is the cause of this behaviour? I've looked through the GNU Make Manual but did not find anything regarding special treatment of files called main.* (in fact, some of the examples use it).

While trying to fix the problem, I found that defining an explicit rule for main.o meant that it would be found - therefore, I presume it's an interaction with the main name and pattern-based rules, but I have not been able to find what that may be.

Wheels2050
  • 879
  • 2
  • 9
  • 17

1 Answers1

1

The trouble is that this rule:

obj/%.o: src/%.cpp %.d hdr/%.h
    echo $@
    $(CXX) $(INCLUDES) -o $@ -c $< $(ROOTFLAGS)

requires a corresponding header file. I suspect that there is no hdr/main.h, and Make has no way to build one, so when it is searching for a way to build obj/main.o it considers this rule, rejects it, and finds no other.

I suggest you add another pattern rule (after this one) to handle source files without matching header files:

obj/%.o: src/%.cpp %.d
    echo $@
    $(CXX) $(INCLUDES) -o $@ -c $< $(ROOTFLAGS)

(P.S. Your dependency handling is a little odd and appears to be vestigial -- you generate dependency files and never use them. We can help you with that, once you're building main.o correctly.)

Beta
  • 96,650
  • 16
  • 149
  • 150
  • Ah, thanks very much! Adding the rule fixes the problem - as it turns out, when I renamed `main.cpp` to `test.cpp`, another file was looked at first that started with s, which failed compilation, therefore I never saw the "no matching rule" error for `test.o` and thought that the problem was fixed. I'd be happy for help with the dependency files. I thought I was using them correctly, but perhaps not. – Wheels2050 Mar 27 '14 at 04:08
  • I should add that I adapted my Makefile from one found [here](http://stackoverflow.com/questions/313778/generate-dependencies-for-a-makefile-for-a-project-in-c-c) – Wheels2050 Mar 27 '14 at 04:14