Can I configure my makefile in a way that it automatically compiles and links foo/bar.cpp if a target includes #include "foo/bar.hpp"?
Details: I have a makefile for a project structured like this:
src/
|-- program1/
| |-- main.cpp
| |-- makefile
|-- modules/
| |-- module1/
| | |-- foo.cpp
| | |-- foo.hpp
| |-- module1/
| | |-- bar.cpp
| | |-- bar.hpp
Currently my makefile for program1 contains a list of all the *.cpp files of all the modules it uses, which is kind of hard and error-prone to maintain and to keep in sync with my includes.
However, in my code, following the #include commands would provide an exact dependency-tree. For every *.hpp there is a corresponding *.cpp that I need to compile and link.
Can this process of compilation be automated via the makefile? May auto-dependencies help me out?
The makefile in question:
# compiler settings
CXX = g++
CXXFLAGS = -std=c++14
# object file generation path
tmpDir = .objs
# modules path
modPath = ../modules
# Names of modules and files to be compiled
names := \
main.o \
module1/foo.o \
module2/bar.o
# prepend tmpDir
names := $(addprefix $(tmpDir)/, $(names))
# Linking
main: $(names)
$(CXX) $(CXXFLAGS) -o main $^
# Rule for main file
$(tmpDir)/main.o: main.cpp
#mkdir -p $(tmpDir)
$(CXX) $(CXXFLAGS) -c main.cpp -o $# -I "$(modPath)"
# rules for module files
$(tmpDir)/%.o: $(modPath)/%.cpp
mkdir -p $(dir $#)
$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
rm -rf *.o main $(tmpDir)
I'd like to avoid to manually set names.
A common way to automate generating the file names is using a $(wildcard ...) or some $(shell ...) command to scan the directories.
Based on the Makefile you linked I think you can track the dependencies using GCC with the -MMD -MP flags something like this:
# compiler settings
CXX = g++
# use flags to generate dependency files
CXXFLAGS = -std=c++14 -MMD -MP
# object file generation path
tmpDir = .objs
# modules path
modPath = ../modules
# Names of modules and files to be compiled
names := main.o
names += $(patsubst $(modPath)/%.cpp,%.o,$(shell find $(modPath) -iname "*.cpp"))
# prepend tmpDir
names := $(addprefix $(tmpDir)/, $(names))
# there should be a dep file for every object file
deps := $(patsubst %.o,%.d,$(names))
all: main
# Linking
main: $(names)
$(CXX) $(CXXFLAGS) -o main $^
# Rule for main file
$(tmpDir)/main.o: main.cpp
#mkdir -p $(tmpDir)
$(CXX) $(CXXFLAGS) -c main.cpp -o $# -I "$(modPath)"
# rules for module files
$(tmpDir)/%.o: $(modPath)/%.cpp
mkdir -p $(dir $#)
$(CXX) $(CXXFLAGS) -c $< -o $#
# include the dependencies if they exist
-include $(deps)
clean:
rm -rf *.o main $(tmpDir) $(deps)
Every compile command that uses the -MMD -MP flags will generate a dependency file corresponding to the output file (except with a .d extension).
regarding: *Currently my makefile for program1 contains a list of all the *.cpp files of all the modules it uses, which is kind of hard and error-prone to maintain and to keep in sync with my includes.
However, in my code, following the #include commands would provide an exact dependency-tree. For every *.hpp there is a corresponding *.cpp that I need to compile and link.
Can this process of compilation be automated via the makefile? May auto-dependencies help me out?*
In the makefile, you could use the output of a call to the find command to obtain a list of all the (for instance) *.cpp files in the directories below the modules directory rather than hard-coding the list.
I refined Galik's answer a bit. Now it behaves much like what I was searching for.
Instead of defining names manually, I invoke a search for files. The results then filters to match only *.cpp files that have a *.hpp file with the same name. This ignores all files containing the tests:
# find *.hpp files
names := $(shell find $(modPath) -iname "*.hpp")
# replace extension .hpp -> .cpp
names := $(patsubst %,%.cpp,$(basename $(names)))
# filter nonexistent *.cpp files
names := $(wildcard $(names))
Related
I've been reading through posts about Makefiles that use subdirectories, but can't seem to put all the pieces together properly. I have the following file structure:
program
|
- src
|
- include
|
- build
|
- bin
|
- Makefile
All my sources (.cpp) are in program/src/, all my headers (.hpp) are in program/include, I want all my object files and dependency files put into program/build, and I want my binary placed into program/bin. The following is what I currently have in my Makefile:
CXX = g++
BIN_DIR = bin
TARGET = $(BIN_DIR)/coreint
BUILD_DIR = build
SRC_DIR = src
INC_DIR = include
CXXFLAGS = -Wall -g
# Get all source files
SRCS := $(shell find $(SRC_DIR) -name *.cpp)
# Get all object files by replacing src directory with build directory and replace extension
OBJS := $(subst $(SRC_DIR), $(BUILD_DIR), $(SRCS:%.cpp=%.o))
# Get all depend files by replacing extensions
DEPS := $(OBJS:.o=.d)
# Get all includes by searching include directory
INCS := $(shell find $(INC_DIR) -name *.hpp)
# Append -I to the front of each include
INCS := $(foreach d, $(INCS), -I$d)
# Using VPATH to find files in src/ include/ and build/
VPATH = $(SRC_DIR):$(INC_DIR):$(BUILD_DIR)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
# Build object files and put in build directory
$(BUILD_DIR)%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
# Place dependency files in build directory
# automatically generate dependency rules
$(BUILD_DIR)%.d: %.cpp
$(CXX) $(CXXFLAGS) -MF"$#" -MG -MM -MD -MP -MT"$#" -MT"$(OBJS)" "$<"
# -MF write the generated dependency rule to a file
# -MG assume missing headers will be generated and don't stop with an error
# -MM generate dependency rule for prerequisite, skipping system headers
# -MP add phony target for each header to prevent errors when header is missing
# -MT add a target to the generated dependency
.PHONY: clean all
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
When I run make, I get the following error:
make: *** No rule to make target `build/assign.o', needed by `bin/coreint'. Stop.
Where assign.o is the first file in the build directory. Thank you in advance.
I was simply missing a '/' after my BUILD_DIR:
# Build object files and put in build directory
$(BUILD_DIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
I'm currently trying to re-write a makefile for a project that I've inherited to make the source tree neater and easier to work with. At the moment the source tree is something like this:
Project/
----bin/
----build/
----include/
----main.h
----part1.h
----part2.h
----part3.h
----src/
----main.cpp
----part1.cpp
----Subdir/
----part2.c
----Subdir2/
----part3.cpp
What I want is a rule in my makefile that will find all of the .cpp and .c files in my src directory and compile them to a flat directory of objects in the build directory. At the moment I have the following in my makefile but this seems to miss a number of the cpp files:
BUILDDIR = build
$(BUILDDIR)/%.o : src/**/%.cpp | $(BUILDDIR)
$(BUILDDIR)/%.o : src/%.cpp | $(BUILDDIR)
$(CXX) $(CFLAGS) -c $< -o $# $(INCS)
$(BUILDDIR)/%.o : src/**/%.c | $(BUILDDIR)
$(BUILDDIR)/%.o : src/%.c | $(BUILDDIR)
$(CC) $(CFLAGS) -c $< -o $# $(INCS)
At the moment when I run make -n it seems that it has detected main.cpp and part1.cpp but none of the ones in subdirectories. Make then goes on to try and load the files according to later rules in the Makefile.
Due to the number of files in the project I'd rather not write a list of them manually but if it comes to that I might have to.
You can explicitly define directories with source files. For example:
DIRS = src src/subdir1 src/subdir2
SEARCHC = $(addsuffix /*.c ,$(DIRS))
SEARCHCPP = $(addsuffix /*.cpp ,$(DIRS))
SRCS = $(wildcard $(SEARCHC))
SRCS += $(wildcard $(SEARCHCPP))
And to let make find your sources files add to your Makefile:
vpath %.c $(DIRS)
vpath %.cpp $(DIRS)
I am also using special target to check my Makefile:
help:
#echo 'Sources:'
#echo $(SRCS)
Make's wildcard function could be of use to you here.
See also
Sources from subdirectories in Makefile
I have a (fairly simple) makefile adapted from here that I am attempting to use to build a project on Ubuntu. The project tree is fairly simple: Makefile is in the root project directory, and there are src/, include/, build/, and bin/, where source code, header files, object files, and executables are stored, respectively.
When I run make from the root directory of the project, I get the following error message:
Linking...
g++ src/Main.cpp src/Foo.cpp -o bin/runner
src/Main.cpp:1:19: fatal error: Foo.hpp: No such file or directory
#include "Foo.hpp"
^
compilation terminated.
src/Foo.cpp:1:19: fatal error: Foo.hpp: No such file or directory
#include "Foo.hpp"
^
compilation terminated.
make: *** [bin/runner] Error 1
All that's currently in the project is Main.cpp. which calls two test functions Foo() and Bar() from Foo.cpp, which references a header file Foo.hpp. Here is the makefile:
CC := g++ # This is the main compiler
SRCDIR := src # Directory for source code
BUILDDIR := build # Directory containing all object files, which are removed on "make clean"
TARGET := bin/runner # bin/runner contains the main executable for project
# bin/ contains all other executables in the project (such as tests)
SRCEXT := cpp # File extension of source code
# Look for all the source files in SRCDIR with the file extension specified above
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
# Name all object files the same root name as the source files from which they came, but add a .o extension to the end
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
# The -g flag specifies that debugging information should be produced in the native format of the OS
CFLAGS := -g -Wall
# Various flags for libraries that might need to be linked
INC := -I include # Ensures that all header files (in the include/ folder) are accessible for build
# Show the components that are currently being compiled/linked
# Also, this is the main procedure for make: The TARGET is built from the objects, and
# object files are built from source
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET)"; $(CC) $^ -o $(TARGET)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c -o $# $<
# Directives for "make clean" which cleans all object files out of the build/ folder
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
# Destroys everything in the build/ and bin/runner/ folders. Does not clean test executables.
.PHONY: clean
What am I missing here in order to get the header files to be properly linked?
EDIT: Here is the new makefile, and the current output:
# This is the main compiler
CC := g++
# Directory for source code
SRCDIR := src
# Directory containing all object files, which are removed on "make clean"
BUILDDIR := build
# bin/runner contains the main executable for project
# bin/ contains all other executables in the project (such as tests)
TARGET := bin/runner
# File extension of source code
SRCEXT := cpp
# Ensures that all header files (in the include/ folder) are accessible for build
INC := -I/include
# Look for all the source files in SRCDIR with the file extension specified above
# SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
SOURCES := $(wildcard $(SRCDIR)/*.$(SRCEXT))
# Name all object files the same root name as the source files from which they came, but add a .o extension to the end
# OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
OBJECTS := $(addprefix $(TARGET)/, $(notdir $(SOURCES:.cpp=.o)))
# The -g flag specifies that debugging information should be produced in the native format of the OS
CFLAGS := -g -Wall
# Various flags for libraries that might need to be linked
LIB := #-pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt
# Show the components that are currently being compiled/linked
# Also, this is the main procedure for make: The TARGET is built from the objects, and
# object files are built from source
$(TARGET): $(OBJECTS)
#echo " Linking..."
$(CC) $^ -o $(TARGET)
# #echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
# Directives for "make clean" which cleans all object files out of the build/ folder
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
# Tests
# tester:
# $(CC) $(CFLAGS) test/tester.cpp $(INC) $(LIB) -o bin/tester
# Spikes
# ticket:
# $(CC) $(CFLAGS) spikes/ticket.cpp $(INC) $(LIB) -o bin/ticket
# Destroys everything in the build/ and bin/runner/ folders. Does not clean test executables.
.PHONY: clean
Output:
[scott]> make
make: *** No rule to make target `bin/runner/Foo.o', needed by `bin/runner'. Stop.
tl;dr
Don't put end-of-line comments on variable assignments in make. It doesn't work the way you might expect.
Explanation
Your makefile isn't running the steps you expect it is.
You shouldn't be seeing Linking... for the compilation step.
make shouldn't be attempting to create the target from the source .cpp files.
You should be seeing your INC and CFLAGS values on the compilation line (but you are getting linking output so obviously aren't seeing them).
That's why your header can't be found by the way, your linking line doesn't have -I on it anywhere.
The reason that's happening is because make is applying the wrong rule.
make is applying the wrong rule because your variables are being set incorrectly.
Your variables are being set incorrectly because your variables have values you don't expect.
The makefile you started from had errors the author wasn't aware of.
make is not always very smart.
When you write
FOO := some value # comment
you expect FOO to have the value some value but make sees things differently.
make gives it the value some value since it can't tell the difference between the space between some and value and the space after value and before the comment.
So when you run your shell command (with *.$(SRCEXT) unquoted) the shell just ignores the trailing spaces). (Try quoting *.'$(SRCEXT)' and see what you get.)
However when you then try to $(SOURCES:=.$(SRCEXT)=.o) make doesn't drop the spaces and you have actually written $(src/Main.cpp src/Foo.cpp:=cpp =.o) which, you may notice, is a pattern that doesn't actually match.
As a result $(OBJECTS) gets the unmodified value of $(SOURCES) and "confuses" the $(TARGET): $(OBJECTS) line later causing make to skip your compilation target.
(Oh, also, that's why your linking line has a million spaces between g++ and the first source file.)
Oh, also, you don't need to shell out for find there unless your src/ directory has sub-directories of its own (and even then not with some make magic) because $(wildcard $(SRCDIR)/*.$(SRCEXT)) will work just fine (and also would have failed earlier I believe given this problem).
Define an environment variable that has . (current working directory) first, then ./include (not just include subdirectory but as ,/include and rest of the INCLUDE dirs that you might already have because of the compiler or other software requirement)
set INCLUDE :=.:./include:$INCLUDE
Alternately, use:
INC := -I. -I./include
gcc -I option is as: -I dir
Adds the directory dir to the list of directories to be searched for header files. Directories named by '-I' are searched before the standard system include directories. If the directory dir is a standard system include directory, the option is ignored to ensure that the default search order for system directories and the special treatment of system headers are not defeated
I'm new to linux and new to makefiles so I'm a little stumped at this point. I've been staring the make manual for an hour now and figured I would just ask:
I want to create a makefile for a relatively small project, whose source files are in proj/src/, and within subdirectories of that location. I have written a makefile at proj/makefile and want to use it to gather up all the source files, find their dependencies, and compile the result into proj/build/. Here is what I've written:
# here are my files and directories (there are also header files that are not
# listed here, but these are referred to from within the .cpp files with
# respect to the proj/src directory)
# proj/makefile
# proj/src/
# proj/src/main.cpp
# proj/src/dir1/
# proj/src/dir1/source1.cpp
# proj/src/dir2/
# proj/src/dir2/source2.cpp
# proj/build/
srcDir = src/
buildDir = build/
# This is a list of all the object files (can I get this programatically?)
objects = main.o source1.o source2.o
all: prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MM -I $(srcDir)
clean:
rm -rf *o $(buildDir)/prog
This is far from functional but I wanted to give it ago before asking. Running this gives
make: * No rule to make target main.o', needed byprog'. Stop.
So presumably my attempt at automatically writing the object files failed. If someone could give me some direction that would be great, I'm hoping that between the comments and code you can make out the intention.
EDIT: I have now tried the following:
SHELL := /bin/bash
srcDir = src
buildDir = bin
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
-include $(sources:%.cpp=%.d)
# This is a list of all the object files (can I get this programatically?)
all: prog
prog: $(objects)
g++ $(objects) -o $(buildDir)/prog
# Here I want to compile all source (.cpp) files from src/ and all of its subdirectories, and to find the dependencies I want to call g++ -MM to automatically generate the list:
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MMD -MP -c -I $(srcDir)
clean:
rm -rf *o $(buildDir)/hello
But when I run this I get the following error:
g++ -MMD -MP -I src
g++: fatal error: no input files
compilation terminated.
make: *** [src/core/Cell.o] Error 1
It wants to build main.o from main.cpp, but there is no main.cpp at the top level. You could specify the full paths of the object files, if they are to be built alongside the source files:
objects = $(srcDir)/main.o $(srcDir)/dir1/source1.o $(srcDir)/dir2/source2.o
can I get this programatically?
I do it using gnumake's shell function:
SHELL := /bin/bash
sources := $(shell find $(srcDir) -name *.cpp)
objects := $(sources:%.cpp=%.o)
to find the dependencies I want to call g++ -MM to automatically generate the list
Use -MMD to generate dependency files as well as compiling. It's also a good idea to specify -MP here - that makes sure the dependencies are correctly updated when you remove a header. Given the variables defined above, you can include the dependency files with
-include $(sources:%.cpp=%.d)
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