0

Here is a little problem that I've encountered:

I have the following project layout:

.
├── Makefile
├── README.md
├── inc
│   └── include.hpp
├── out
│   ├── debug
│   └── release
└── src
    └── main.cpp

And the following Makefile (which was copied from this post, and edited a little bit by me, to adequate to my project):

# Compiler flags
CXX     := g++
CXXFLAGS    := -Wall -Werror -Wextra


# Project files
SRC_DIR     := src
SRCS        := $(wildcard $(SRC_DIR)/*.cpp)
INC_DIR     := inc
INCLUDES    := -I $(INC_DIR)
OBJS        := $(SRCS:.cpp:=.o)
EXE     := <ProgramName>
BUILD_DIR   := out

# Debug build settings
DBGDIR      := $(BUILD_DIR)/debug
DBGEXE      := $(DBGDIR)/$(EXE)
DBGOBJS     := $(addprefix $(DBGDIR)/, $(OBJS))
DBGCXXFLAGS := -g -O0 -DDEBUG

# Release build settings
RELDIR      := $(BUILD_DIR)/release
RELEXE      := $(RELDIR)/$(EXE)
RELOBJS     := $(addprefix $(RELDIR)/, $(OBJS))
RELCXXFLAGS := -O3 -DNDEBUG

.PHONY: all clean debug prep release remake

# Default build
all: prep release

# Debug rules
debug: $(DBGEXE)

$(DBGEXE): $(DBGOBJS)
    $(CXX) $(CXXFLAGS) $(DBGCXXFLAGS) -o $(DBGEXE) $^

$(DBGDIR)/%.o: $(SRC_DIR)/%.cpp
    @echo $@ 
    $(CXX) -c $(CXXFLAGS) $(DBGCXXFLAGS) -o $@ $<

# Release rules
release: $(RELEXE)

$(RELEXE): $(RELOBJS)
    $(CXX) $(CXXFLAGS) $(RELCXXFLAGS) -o $(RELEXE) $^

$(RELDIR)/%.o: $(SRC_DIR)%.cpp
    $(CXX) -c $(CXXFLAGS) $(RELCXXFLAGS) -o $@ $<

# Other rules
prep:
    @mkdir -p $(DBGDIR) $(RELDIR)

remake: clean all

clean:
    @rm -rf $(RELEXE) $(RELOBJS) $(DBGEXE) $(DBGOBJS)
    @echo "Cleaned!"

Produces the following error:

make: *** No rule to make target 'out/release/src/main.cpp', needed by 'out/release/<ProgramName>'.  Stop.

Where is the issue? And when does make assume that the directory of the source files is in '/out/release'? I'm still a noob writing makefiles, I've always been a little bit lazy and used Visual Studio even when targeting linux.

Any help is vastly appreciated!!

1 Answers1

0

You have a couple of small errors.

OBJS        := $(SRCS:.cpp:=.o)

You have an extra colon. As written, you change all instances of .cc:, but there are none, so OBJS is src/main.cpp.

You probably meant this:

OBJS        := $(SRCS:.cpp=.o)

But this gives src/main.o. You probably did not intend to keep the path. You can correct that with another line:

OBJS := $(notdir $(OBJS))

Then here:

$(RELDIR)/%.o: $(SRC_DIR)%.cpp
    ...

You are missing a slash. The correct line is

$(RELDIR)/%.o: $(SRC_DIR)/%.cpp
    ...

The rule as written searches for a file that doesn't exist.

You can detect such errors yourself -- and correct them as you develop the makefile -- with diagnostics like this:

$(info OBJS is $(OBJS))
$(info RELOBJS is $(RELOBJS))

Write a small makefile that works perfectly, then add complexity a little at a time, testing at every step, and never add to code that doesn't work.

Beta
  • 96,650
  • 16
  • 149
  • 150