0

I have a simple project, whose folder structure is something like:

ls -R
.:
build  include  makefile  src

./build:

./include:
myfunc.h

./src:
main.cpp  myfunc.cpp

I want to compile the .cpp sources into .o object files, which should end into ./build folder. Using the GNUmake documentation and other sources (e.g. Proper method for wildcard targets in GNU Make), I wrote this makefile:

CXX := g++

CXXFLAGS += -I./include
CXXFLAGS += -Wall

OBJDIR := ./build
SRCDIR := ./src

PROGRAM = release

DEPS = myfunc.h

SRC = $(wildcard $(SRCDIR)/*.cpp)
OBJ = $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRC))

all: $(PROGRAM)

$(PROGRAM): $(OBJ)
    $(CXX) $(CXXFLAGS) -o $(PROGRAM) $(OBJ)

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
    $(CXX) $(CXXFLAGS) -c $< -o $@

.PHONY: clean

clean:
    rm $(PROGRAM) $(OBJ)

But I get the error message: make: *** No rule to make target 'build/main.o', needed by 'release'. Stop.. I tried a lot of different ways but I cannot manage to have my .o files end up in the ./build directory. Instead, everything works if I put them in the root directory of the project. I can also make it work by specifying a rule for each object file, but I'd like to avoid that. What am I missing?

(I am using GNUmake version 4.3)

  • You can use `make -d` to see lots of debug information, which might help you understand the problem. Or `make -p` to print the internal database. Or add phony targets to print the values of all variables. And add a command to print `$<` and `$@` when building the source files into object files. – Some programmer dude Apr 28 '22 at 08:26
  • 1
    Use `$(info $(SRC))` etc. to display the list of files which `wildcard` found (i.e. put this immediately after assignment). It looks like your files aren't where you think they are. – Vroomfondel Apr 28 '22 at 09:12
  • `$(info $(SRC))` outputs `./src/main.cpp ./src/myfunc.cpp`, while `$(info $(OBJ))` outputs `./build/main.o ./build/myfunc.o`. It looks correct to me, but somehow the rule to make the .o targets is not found – davideperrone Apr 28 '22 at 09:35

1 Answers1

2

The problem is here:

$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
    $(CXX) $(CXXFLAGS) -c $< -o $@

See the $(DEPS)? That expands to myfunc.h. The compiler knows where to find that file (or would if this recipe were executed), because you've given it -I./include, but Make doesn't know where to find it (so it passes over this rule).

Add this line:

vpath %.h include

P.S. If you want to be really clean, you can add a variable:

INCDIR := ./include

CXXFLAGS += -I$(INCDIR)

vpath %.h $(INCDIR)
Beta
  • 96,650
  • 16
  • 149
  • 150
  • Shouldn't the error message read "don't know how to make myfunc.h" in this case? – Vroomfondel Apr 28 '22 at 12:05
  • This solved the problem, thanks. I agree that the error message is somewhat misleading. – davideperrone Apr 28 '22 at 13:35
  • 1
    @Vroomfondel: Remember that Make has many implicit rules to choose from, any one of which it could use to build `main.o` *if only some prerequisite existed.* Think of the error message: `don't know how to build myfunc.h nor main.cc nor main.c nor main.o.tar nor oldrepo.gz nor...` – Beta Apr 30 '22 at 15:34