Out-of-source build doesn't match rule for object files - c++

I'm trying to set up a Makefile for out-of-source builds of a C++ project, based on a template I found on this blog post. However, for some reason, the pattern-matching target $(BUILD_DIR)/$.cpp.o: doesn't seem to be working, because I get errors like "No rule to make target 'build/somefile.cpp.o'."
Here is my Makefile, with some of the unnecessary details removed. Note that the SRCS variable is built up from other variables because eventually I want to support different targets using different sets of source files, but for now SRCS has only one definition and could be defined in one line.
CXX = g++
RM = rm -f
MKDIR_P ?= mkdir -p
SRC_DIR := ./src
BUILD_DIR := ./build
CPPFLAGS := -std=c++14 -g3 -O0 -Wall
LFLAGS := -L"./libraries/mutils"
INCLUDES := -I"$(SRC_DIR)/" -I"./libraries/"
LIBS := -lmutils -lpthread
OBJS = $(SRCS:$(SRC_DIR)/%=$(BUILD_DIR)/%.o)
DEPS = $(OBJS:.o=.d)
COMMON_SRCS := sourcefile1.cpp sourcefile2.cpp sourcefile3.cpp sourcefile4.cpp
COMMON_SRCS := $(addprefix $(SRC_DIR)/,$(COMMON_SRCS))
COMMON_SRCS += $(shell find $(SRC_DIR)/util -name *.cpp)
SIM_SRCS := $(shell find $(SRC_DIR)/simulation -name *.cpp)
SIM_SRCS += $(SRC_DIR)/SimulationMain.cpp
$(BUILD_DIR)/%.cpp.o: %.cpp
$(MKDIR_P) $(dir $#)
$(CXX) $(CPPFLAGS) $(INCLUDES) -c $< -o $#
SRCS = $(COMMON_SRCS) $(SIM_SRCS)
build/simulation: $(OBJS)
$(CXX) $(LFLAGS) $(OBJS) -o $# $(LIBS)
.PHONY: clean
clean:
$(RM) -r $(BUILD_DIR)
-include $(DEPS)
If I try to run this with make build/simulation, I get *** No rule to make target 'build/sourcefile1.cpp.o', needed by 'build/simulation'. Stop. This is the first file in the OBJS list, so it seems like Make expanded all the variables but then couldn't match a single object file to a rule. What could be going wrong here?
My first thought was that the problem is the ./ in BUILD_DIR, and Make can't match build/sourcefile1.cpp.o to the rule ./build/%.cpp.o : %.cpp, but I get the exact same error if I remove the ./ from BUILD_DIR and SRC_DIR.

What's going wrong
The issue is caused by this line:
$(BUILD_DIR)/%.cpp.o: %.cpp
% will be sourcefile1 according to the left-hand side, so expanded line looks like this and the pattern gets ignored:
$(BUILD_DIR)/sourcefile1.cpp.o: sourcefile1.cpp
You need to get src/sourcefile1.cpp on the right to make this rule work.
How to fix it
You can either change the line to:
$(BUILD_DIR)/%.cpp.o: $(SRC_DIR)/%.cpp
Or make paths of object files include src/ (i.e., don't delete $(SRC_DIR) part from their path):
OBJS = $(SRCS:%=$(BUILD_DIR)/%.o)
Both solutions should be equivalent, they just adjust different parts of the rule.

Related

Makefile target with wildcard is not working

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)
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)

Problems building a generic Makefile with dependency tracking

I have the following project structure: a folder called "src" with all the .cpp, a folder called "include" with the .h, a folder called "build" for the .o (object files), another folder called "dep" for the .d files (dependencies) and finally another folder called "bin" for the executables.
Given that, I have done this makefile to carry out the build process
OPTIONS := -O2 -Wall
EXE_NAME = example.exe
BIN_PATH = bin/
BUILD_PATH = build/
DEP_PATH = dep/
INCLUDE_PATH = include/
SRC_PATH = src/
################################################################################
# get project files
ALL_CPP := $(shell find $(SRC_PATH) -type f -name "*.cpp")
ALL_H := $(shell find $(INCLUDE_PATH) -type f -name "*.h")
ALL_O := $(subst $(SRC_PATH),$(BUILD_PATH),$(subst .cpp,.o,$(ALL_CPP)))
ALL_D := $(subst $(SRC_PATH),$(DEP_PATH),$(subst .cpp,.d,$(ALL_CPP)))
all: $(BIN_PATH)$(EXE_NAME)
#linking
$(BIN_PATH)$(EXE_NAME): $(ALL_O)
g++ $(OPTIONS) -o $# $(ALL_O)
# generic build rule
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
g++ $(OPTIONS) -c $< -o $(BUILD_PATH)$# -I$(INCLUDE_PATH) -MMD -MF $(DEP_PATH)$(#:.o=.d)
.PHONY: clean
clean:
rm $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
-include $(ALL_D)
But whenever I try to execute it, this error pops out:
make: *** No rule to make target 'build/file.o', needed by 'bin/example.exe'. Stop.
Which does not make sense, as there is a rule for building targets that end in ".o".
What might be going on here?
First, you should avoid using subst since it substitutes every instance of one set of text with another. Safer is to use patsubst:
ALL_O := $(patsubst $(SRC_PATH)%.cpp,$(BUILD_PATH)%.o,$(ALL_CPP))
ALL_D := $(patsubst $(SRC_PATH)%.cpp,$(DEP_PATH)%.d,$(ALL_CPP))
Second, your command line is wrong: $# already contains the path so you don't want to use $(BUILD_DIR)$#. You want just $# by itself. You'll have a similar problem for .d.
But I don't see any way to get the error you show (no rule to make target 'build/file.o') given the makefile you provide. Either there's something different about your makefile than what you have here or something mysterious is happening.
You can add the -d option to make to get some debug info.
Thanks to all who replied. As many of you suggested, the error I provided does not appear in the makefile version I posted, and that is because I did some code cleaning before posting which ironically end up solving the error (I had no idea the changes I made would be important). More precisely, I am sure the problem was with the line
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
Which in the original makefile was
$(BUILD_PATH)%.o: %.cpp
I have also tried without the $(BUILD_PATH), which gave no luck, that's why I thought that line was not important.
I did some of the changes you suggested and the final working version of the Makefile is as follows
OPTIONS := -O2 -Wall -Wno-sign-compare -Wno-unused-parameter
EXE_NAME = example
BIN_PATH = bin/
BUILD_PATH = build/
DEP_PATH = dep/
INCLUDE_PATH = include/
SRC_PATH = src/
################################################################################
# get project files
ALL_CPP := $(shell find $(SRC_PATH) -type f -name "*.cpp")
ALL_H := $(shell find $(INCLUDE_PATH) -type f -name "*.h")
ALL_O := $(subst $(SRC_PATH),$(BUILD_PATH),$(subst .cpp,.o,$(ALL_CPP)))
ALL_D := $(subst $(SRC_PATH),$(DEP_PATH),$(subst .cpp,.d,$(ALL_CPP)))
all: $(BIN_PATH)$(EXE_NAME)
#linking
$(BIN_PATH)$(EXE_NAME): $(ALL_O)
#echo ' -> linking'
#g++ $(OPTIONS) -o $# $(ALL_O)
#echo Finished!
# generic build rule
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
#echo ' -> building:' $<
#g++ $(OPTIONS) -c $< -o $# -I$(INCLUDE_PATH) -MMD -MF $(subst $(BUILD_PATH),$(DEP_PATH),$(#:.o=.d))
.PHONY: clean
clean:
#echo Removed files: $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
#rm $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
-include $(ALL_D)

-I flag in the makefile does not result in a header file being found

I have a file ./src/test.cpp:
#include "test.h"
void Hi() {
std::cout << "Hi, indeed..." << std::endl;
}
test.h is located in ./include folder.
This is my makefile:
CC = g++
CFLAGS = -Wall
INCLUDES = -I./include
SRCS = $(shell find ./src/ -name '*.cpp')
.PHONY: clean depend
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
release: $(OBJS)
$(CC) $(CFLAGS) -o app_name $(OBJS)
VPATH = ./src
../%.o: %.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c $*.cpp
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^ > ./.depend;
include .depend
As a result I get an error:
g++ -c -o test.o ./src/test.cpp
./src/test.cpp:1:18: fatal error: test.h: No such file or directory
compilation terminated.
<builtin>: recipe for target 'test.o' failed
make: *** [test.o] Error 1
Also the file .depend is completely empty.
How to resolve the issue? The makefile is in root directory:
./
makefile
./src/
test.cpp
main.cpp
./include/
test.h
What G.M. is trying to say is that you have defined a pattern rule that knows how to build a target matching a pattern ../%.o. But, when you ask make to build objects, they are of the form ./xxx.o; e.g., after:
SRCS = $(shell find ./src/ -name '*.cpp')
suppose SRCS contains ./src/foo.cpp. Now after this:
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
OBJS will contain the value ./foo.o (by the way, a simpler way to get this behavior is to use the patsubst function: $(patsubst ./src/%.cpp,./%.o,$(SRCS))).
So, make will try to build the file ./foo.o. Since there's no explicit rule for this it will look for an implicit rule.
It sees your pattern rule, but that says how to build ../%.o which does not match the object file make wants to build ./foo.o, so your rule is ignored.
Then make will go look for some other implicit rules and it will find the built-in rule that knows how to build a .o file from a .cpp file, and it will use that. That rule doesn't use your variable $(INCLUDES), so your compile fails.
You need to either fix your OBJS settings to create filenames like ../foo.o instead of ./foo.o, if you really want your object files to appear in the parent directory, or else change your pattern rule to build %.o not ../%.o.

Generic makefile showing no rule to make target error

I wrote a makefile to compile and link all the files in my project. Right now i only have 2 cpp files: src/main.cpp and src/DBEngine/benchmark/ssb/ssb_main.cpp.
My makefile content is :
CPP_FILES := $(wildcard src/*.cpp) $(wildcard src/DBEngine/benchmark/ssb/*.cpp)
OBJ_FILES := $(addprefix bin/obj/,$(notdir $(CPP_FILES:.cpp=.o)))
DEBUG_OBJ_FILES := $(addprefix bin/debug/,$(notdir $(CPP_FILES:.cpp=.o)))
CC_FLAGS := -I${PWD}
main.out: $(OBJ_FILES)
g++ -o $# $(OBJ_FILES)
bin/obj/%.o: src/%.cpp
g++ -c -o $# $< (CC_FLAGS) -w
But when i do a make it gives the error :
make: *** No rule to make target bin/debug/ssb_main.o, needed by main.out. Stop.
Short version: your pattern rule is expanded as follows for the object files in DBEngine
bin/obj/ssb_main.o: src/ssb_main.cpp
You can see how that won't work I'm sure.
You can add another pattern rule to fix it
bin/obj/%.o: src/DBEngine/benchmark/ssb/%.cpp
g++ -c -o $# $< $(CC_FLAGS) -w
A simpler method however is to mirror your source and build trees and use vpath, make sure there is a directory called DBEngine/benchmark/ssb in the makefile directory as well, and use the following:
CPP_FILES := $(wildcard src/*.cpp) $(wildcard src/DBEngine/benchmark/ssb/*.cpp)
OBJ_FILES := $(CPP_FILES:src/%.cpp=%.o)
CPPFLAGS := -I${PWD}
CXXFLAGS := -w
vpath %.cpp src
main: $(OBJ_FILES)
The built-in rules will handle the rest.
Side notes: -I${PWD} is superfluous, and -w is usually a bad idea.
In the compiling rule you have specified that the source files are in the 'src' directory. But from your description it seems that the ssb_main.cpp file is in the 'src/DBEngine/benchmark/ssb/' folder, so make does not find the dependency to compile ssb_main.o.
You can use variable VPATH to specify the folders where make should look for your source files.
Since you have sub-folder is your src folder you can try to use
CPP_FILES := $(shell ls -pR ./src | grep -v /)
It will list all cpp files under src and its sub-folders excluding . and .. .

Single top-level makefile with source subdirectories

Firstly, apologies for my ignorance. I'm sure the answer to my question exists in one of the many existing makefile threads here. However, I have been unable to find one that concisely and clearly answers my specific question without obfuscating the answer with details that aren't relevant to my particular situation.
My code directory has a single top-level source file containing main. The rest of the source files are organised in subdirectories according to logical divisions in the system. The code contains no relative paths in the includes. This means that everything works perfectly if all the code is in a single directory using the following, simple makefile:
CC=g++
CFLAGS=-c
LDFLAGS=
SOURCES=Main.cpp Source1.cpp Source2.cpp Source3.cpp Etc.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=executable
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
Until now I have been building my code using the NetBeans IDE. This has helped preserve my make ignorance by generating some vast and overly complicated makefiles on my behalf. Now the time has come to distribute my code for public use so I'm looking to produce a makefile will enable me to distribute the code with the directory structure I have.
Can you help?
Regards,
Enthusastic Amateur.
Take a look at this:
# Source directories separated by space
# Example ./ src1/ src2/
SRCDIR = ./ src/
# Directory where object files will be placed
OBJDIR = obj/
# Include directories separated by space
# Example: include1/ include2/
INCDIR = include/
# Directory where binary file will be placed
BINDIR = bin/
# Name of the result file
TARGET = app
# Compiler
CXX = g++
# Retrive list of the source files
SRC = $(wildcard $(addsuffix *.cpp,$(SRCDIR)))
# Generate list of the object files
OBJ = $(addprefix $(OBJDIR), $(patsubst %.cpp, %.o, $(notdir $(SRC))))
VPATH = $(SRCDIR)
# Compilation flags
CXXFLAGS = -std=c++11 -pthread
$(TARGET) : $(OBJ)
#echo Linking...
#mkdir -p $(BINDIR)
#$(CXX) $(CXXFLAGS) -o $(BINDIR)$# $(OBJ)
$(OBJDIR)%.o : %.cpp
#echo Compiling $< in $#...
#mkdir -p $(OBJDIR)
#$(CXX) $(CXXFLAGS) $(addprefix -I,$(INCDIR)) -c -o $# $<
clean :
#$(RM) -r $(OBJDIR)
#$(RM) -r $(BINDIR)
Here you can provide multiple source directories.
And "everything works perfectly" as well if the code is in multiple directories, using the same makefile you already have. No changes needed.