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)
Related
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.
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.
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 .. .
I'm trying to write a make file for my C++ project
I have the following source structure
project folder content:
main.cpp
lib/
include/
src/
as the name says 'main.cpp' contain the main() function, include hold the *.h files and src hold *.cpp file (and in case other subfolders with other sources)
what I would like to achieve is a makefile that as target compile main.cpp and all his included sources recursivelly , without specify all the sources names or mantaining the make file adding a source every time I create or add it
any help or a good tutorial to solve this problem would be very appreciated
Not sure what flavour of Makefile you use, or what OS you're building, however here are some ideas for a GNU Make and a unix-like environment
Use a single make (instead of recursively invoking make on subdirectories).
Use prefix rules to generate *.cpp to *.o
Now consider an src.mk present on each source subdirectory that fills an SRC variable with the actual *.cpp on each directory:
SRC+= $(addprefix $(ROOT)/src/, \
Source1.cpp \
Source2.cpp \
)
... and in the Makefile you can have an
-include src.mk
OBJ=$(SRC:.cpp=.o)
executable: $(OBJ)
Now the next thing is to be able to generate the src.mk: you can have a prefix rule for that and rely on a shell script:
%/src.mk: %/
gensrc $(dir $#)
The gensrc is a shell script that adds -include subdir/src.mk for each subdir of the argument and creates SRC variable with the *.cppin the argument directory.
Hope this gives you some ideas.
bro!
If your main project architecture just like this:
fitBody
|
|__main.cpp
|__Makefile
|__build
|__lib
|__XYZ
|__include
|__fitbody.h
|__src
|__fitbody.cpp
[...]
Update Jan. 31 2022 PM 17:27
Just use this Makefile:
# (1)Compiler
CXX = clang++
# (2)Compile options
CXX_FLAGS = -Wall -Wextra -std=c++11 -g
# (3)Build task directory path
# I do care about out-of-source builds
BUILD_DIR ?= ./build
# (4)Source files directory path
SRC_DIRS ?= ./
SRC_DIRS_SRC ?= ./src
# (5)Library files directory path
LIBDIR :=
# (6)Add library files
LIBS := ./lib
# (7)Target file, excutable file.
TARGET ?= main
# (8)Source files(code), to be compiled
# Find source files we want to compile
# *expression must around by single quotos
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
SRCS_SRC := $(shell find $(SRC_DIRS_SRC) -name '*.cpp' -or -name '*.c' -or -name '*.s')
# (9)Object files
# String substituion for every C/C++ file
# e.g: ./src/bank.cpp turns into ./build/bank.cpp.o
OBJS := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS)))
OBJS_SRC := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS_SRC)))
# (10)Dependency files
# which will generate a .d file next to the .o file. Then to use the .d files,
# you just need to find them all:
DEPS := $(OBJS:.o=.d)
DEPS_SRC := $(OBJS_SRC:.o=.d)
# (11)Include files directory path
# Every folder in ./src find include files to be passed via clang
INC_DIRS := ./inc
# (12)Include files add together a prefix, clang make sense that -I or -L flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
LIBS_FLAGS := $(addprefix -L,$(LIBS))
# (13)Make Makefiles output Dependency files
# That -MMD and -MP flags together to generate Makefiles
# That generated Makefiles will take .o as .d to the output
# That "-MMD" and "-MP" To generate the dependency files, all you have to do is
# add some flags to the compile command (supported by both Clang and GCC):
CPP_FLAGS ?= $(INC_FLAGS) -MMD -MP
# (14)Link: Generate executable file from the object file
# make your target depend on the object files:
${BUILD_DIR}/${TARGET} : $(OBJS)
$(CXX) $^ -o $# $(LIBS_FLAGS)
# (15)Compile: Generate object files from source files
# $# := {TARGET}
# $< := THE first file
# $^ all the dependency
# C++ Sources
$(BUILD_DIR)/%.cpp.o : $(SRC_DIRS)/%.cpp
$(MKDIR_P) $(dir $#)
$(CXX) $(CPP_FLAGS) $(CXX_FLAGS) -c $< -o $#
$(BUILD_DIR)/%.cpp.o : $(SRC_DIRS_SRC)/%.cpp
$(CXX) $(CPP_FLAGS) $(CXX_FLAGS) -c $^ -o $#
.PHONY: all clean
all: ${BUILD_DIR}/${TARGET}
clean:
$(RM) $(DEPS) $(DEPS_MAIN) $(OBJS) $(OBJS_MAIN) ${BUILD_DIR}/${TARGET}
-include $(DEPS) $(DEPS_MAIN)
MKDIR_P ?= mkdir -p
I need a Makefile that will compile everything in the current directory and recursively down the tree, and preferably use the compiler's dependency thing (-M, etc.) so that whenever I type "make", as little as possible is recompiled.
Also, why is this not page 1 of the Makefile documentation?
While I would suggest using tools like cmake or alike, I understand that sometimes it is easier or better to use a plain old Makefile.
Here's a Makefile I've used on some projects, it creates dependency-files using gcc:
# Project Name (executable)
PROJECT = demoproject
# Compiler
CC = g++
# Run Options
COMMANDLINE_OPTIONS = /dev/ttyS0
# Compiler options during compilation
COMPILE_OPTIONS = -ansi -pedantic -Wall
#Header include directories
HEADERS =
#Libraries for linking
LIBS =
# Dependency options
DEPENDENCY_OPTIONS = -MM
#-- Do not edit below this line --
# Subdirs to search for additional source files
SUBDIRS := $(shell ls -F | grep "\/" )
DIRS := ./ $(SUBDIRS)
SOURCE_FILES := $(foreach d, $(DIRS), $(wildcard $(d)*.cpp) )
# Create an object file of every cpp file
OBJECTS = $(patsubst %.cpp, %.o, $(SOURCE_FILES))
# Dependencies
DEPENDENCIES = $(patsubst %.cpp, %.d, $(SOURCE_FILES))
# Create .d files
%.d: %.cpp
$(CC) $(DEPENDENCY_OPTIONS) $< -MT "$*.o $*.d" -MF $*.d
# Make $(PROJECT) the default target
all: $(DEPENDENCIES) $(PROJECT)
$(PROJECT): $(OBJECTS)
$(CC) -o $(PROJECT) $(OBJECTS) $(LIBS)
# Include dependencies (if there are any)
ifneq "$(strip $(DEPENDENCIES))" ""
include $(DEPENDENCIES)
endif
# Compile every cpp file to an object
%.o: %.cpp
$(CC) -c $(COMPILE_OPTIONS) -o $# $< $(HEADERS)
# Build & Run Project
run: $(PROJECT)
./$(PROJECT) $(COMMANDLINE_OPTIONS)
# Clean & Debug
.PHONY: makefile-debug
makefile-debug:
.PHONY: clean
clean:
rm -f $(PROJECT) $(OBJECTS)
.PHONY: depclean
depclean:
rm -f $(DEPENDENCIES)
clean-all: clean depclean