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
Related
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)
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))
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 $#
Following this tutorial...
I have 2 source files and 1 header file. I want to have them in separate directories like in the tutorial.
So I set this project up:
.
├── include
│ └── hellomake.h
├── Makefile
└── src
├── hellofunc.c
└── hellomake.c
Makefile:
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
The error I generate says:
gcc -o hellomake -I../include
gcc: fatal error: no input files
compilation terminated.
make: *** [hellomake] Error 4
What's happening?
Your tutorial promotes old and bad practices, you should avoid it IMHO.
In your rule here:
$(ODIR)/%.o: %.c $(DEPS)
You're telling make to look for sources in the current directory while they actually reside in the src directory, thus this pattern is never used and you have no suitable one.
Make sure you organize your project directory like this :
root
├── include/
│ └── all .h files here
├── lib/
│ └── all third-party library files (.a/.so files) here
├── src/
│ └── all .c files here
└── Makefile
Then let's take the process step by step, using good practices.
Firstly, don't define anything if you don't need to. Make has a lot of predefined variables and functions that you should use before trying to do it manually. In fact, he has so many that you can compile a simple file without even having a Makefile in the directory at all!
List your source and build output directories:
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin # or . if you want it in the current directory
Name your final target, that is, your executable:
EXE := $(BIN_DIR)/hellomake
List your source files:
SRC := $(wildcard $(SRC_DIR)/*.c)
From the source files, list the object files:
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
# You can also do it like that
OBJ := $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC))
Now let's handle the flags
CPPFLAGS := -Iinclude -MMD -MP # -I is a preprocessor flag, not a compiler flag
CFLAGS := -Wall # some warnings about bad code
LDFLAGS := -Llib # -L is a linker flag
LDLIBS := -lm # Left empty if no libs are needed
(CPP stands for C PreProcessor here, not CPlusPlus! Use CXXFLAGS for C++ flags and CXX for C++ compiler.)
The -MMD -MP flags are used to generate the header dependencies automatically. We will use this later on to trigger a compilation when only a header changes.
Ok, time to roll some recipes now that our variables are correctly filled.
It is widely spread that the default target should be called all and that it should be the first target in your Makefile. Its prerequisites shall be the target you want to build when writing only make on the command line:
all: $(EXE)
One problem though is Make will think we want to actually create a file or folder named all, so let's tell him this is not a real target:
.PHONY: all
Now list the prerequisites for building your executable, and fill its recipe to tell make what to do with these:
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
(CC stands for C Compiler.)
Note that your $(BIN_DIR) might not exist yet so the call to the compiler might fail. Let's tell make that you want it to check for that first:
$(EXE): $(OBJ) | $(BIN_DIR)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(BIN_DIR):
mkdir -p $#
Some quick additional notes:
$(CC) is a built-in variable already containing what you need when compiling and linking in C
To avoid linker errors, it is strongly recommended to put $(LDFLAGS) before your object files and $(LDLIBS) after
$(CPPFLAGS) and $(CFLAGS) are useless here, the compilation phase is already over, it is the linking phase here
Next step, since your source and object files don't share the same prefix, you need to tell make exactly what to do since its built-in rules don't cover your specific case:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Same problem as before, your $(OBJ_DIR) might not exist yet so the call to the compiler might fail. Let's update the rules:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
Ok, now the executable should build nicely. We want a simple rule to clean the build artifacts though:
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR) # The # disables the echoing of the command
(Again, clean is not a target that needs to be created, so add it to the .PHONY special target!)
Last thing. Remember about the automatic dependency generation? GCC and Clang will create .d files corresponding to your .o files, which contains Makefile rules for us to use, so let's include that in here:
-include $(OBJ:.o=.d) # The dash silences errors when files don't exist (yet)
Final result:
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/hellomake
SRC := $(wildcard $(SRC_DIR)/*.c)
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
CPPFLAGS := -Iinclude -MMD -MP
CFLAGS := -Wall
LDFLAGS := -Llib
LDLIBS := -lm
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
the make utility, with no specific 'target' will make the first target in the file.
The first target is usually named 'all'
For the posted file, will make the object files and will not continue to make the executable when the target is not given in the command line
Suggest the following:
SHELL := /bin/sh
# following so could define executable name on command line
# using the '-D' parameter
#ifndef $(NAME)
NAME := hellomake
#endif
# use ':=' so macros only evaluated once
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CFLAGS := -g -Wall -Wextra -pedantic
LFLAGS :=
ODIR := obj
IDIR := ../include
LIBS :=
LIBPATH := ../lib
DEPS := $(wildcard $(IDIR)/*.h)
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
.PHONY: all
all: $(NAME) $(OBJS)
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $< -I$(DEPS)
$(NAME): $(OBJS)
$(CC) $(LFLAGS) -o $# $^ -L$(LIBPATH) -l$(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o
rm -f $(NAME)
however, in your proposed project,
not every source file needs every header file
so should use either gcc or sed to generate the dependency files
then use makefile rules similar to the following,
which may need a little 'tweaking' for your project
because the include files are not in the same directory
as the source files:
DEP := $(SRCS:.c=.d)
#
#create dependency files
#
%.d: %.c
#
# ========= START $< TO $# =========
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# ========= END $< TO $# =========
#
# compile the .c files into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $# =========
$(CC) $(CCFLAGS) -c $< -o $# -I$(IDIR)
# ========= END $< TO $# =========
#
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependencies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
The simple Makefile definitions seem OK to me as they appear in your question. Try specifying the compiler options before the file names:
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
hellomake: $(OBJ)
gcc $(CFLAGS) -o $# $^
You need to run make from the source directory.
When you got this error"
*gcc: fatal error: no input files
compilation terminated.*
", that means you do not have object files,
just check out that line "${OBJS} := " in Makefile.
Hi, bro!
If your project "helloFunc" 's architecture are just liking this:
helloFunc
|
|__Makefile
|__build
|__include
| |__hellomake.h
|__src
|__hellofunc.cpp
|__hellomake.cpp
your Makefile should be just like this:
# This is a Makefile for separated multiple sources to build with VSCode on mac
# Thanks, Job Vranish.
# (https://spin.atomicobject.com/2016/08/26/makefile-c-projects/)
# Reference: Makefile Tutorial
# (https://makefiletutorial.com/)
# Reference: #yagiyuki from Qiita
# (https://qiita.com/yagiyuki/items/ff343d381d9477e89f3b)
# Reference: simonsso from Github
# (https://github.com/simonsso/empty-cpp-project/blob/master/Makefile)
# Reference: Chinese Website blogger CDNS
# (https://blog.csdn.net/qq_22073849/article/details/88893201)
# (1)Compiler
# clang++
CXX = clang++
# (2)Compile options
# -Wall -Wextra -std=c++11 -g
CXX_FLAGS = -Wall -Wextra -std=c++11 -g
# (3)Build task directory path
# I do care about out-of-source builds
# ./build
BUILD_DIR ?= ./build
# (4)Source files directory path
# ./src
SRC_DIRS ?= ./src
# (5)Library files directory path
LIBDIR :=
# (6)Add library files
LIBS :=
# (7)Target file, excutable file.
# main
TARGET ?= main
# (8)Source files(code), to be compiled
# Find source files we want to compile
# *expression must around by single quotos
# ./src/bank.cpp ./src/main.cpp
SRCS := $(shell find $(SRC_DIRS) -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
# ./build/bank.cpp.o ./build/main.cpp.o
OBJS := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS)))
# (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)
# (11)Include files directory path
# Every folder in ./src find include files to be passed via clang
# ./include
INC_DIRS := ./include
# (12)Include files add together a prefix, clang make sense that -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# (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 object file
# make your target depend on the objects files:
${BUILD_DIR}/${TARGET} : $(OBJS)
$(CXX) $(OBJS) -o $#
# (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 $#
#(16)Delete dependence files, object files, and the target file
.PHONY: all clean
all: ${BUILD_DIR}/${TARGET}
clean:
$(RM) $(DEPS) $(OBJS) ${BUILD_DIR}/${TARGET}
-include $(DEPS)
MKDIR_P ?= mkdir -p
Changing that Makefile to your needed Linux version:
# (1)Compiler
# g++
CXX = g++
# (2)Compile options
# -Wall -Wextra -std=c++11 -g
CXX_FLAGS = -Wall -Wextra -std=c++11 -g
# (3)Build task directory path
# I do care about out-of-source builds
# ./build
BUILD_DIR ?= ./build
# (4)Source files directory path
# ./src
SRC_DIRS ?= ./src
# (5)Library files directory path
LIBDIR :=
# (6)Add library files
LIBS :=
# (7)Target file, excutable file.
# main
TARGET ?= main
# (8)Source files(code), to be compiled
# Find source files we want to compile
# *expression must around by single quotos
# ./src/bank.cpp ./src/main.cpp
SRCS := $(shell find $(SRC_DIRS) -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
# ./build/bank.cpp.o ./build/main.cpp.o
OBJS := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS)))
# (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)
# (11)Include files directory path
# Every folder in ./src find include files to be passed via clang
# ./include
INC_DIRS := ./include
# (12)Include files add together a prefix, gcc make sense that -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# (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 object file
# make your target depend on the objects files:
${BUILD_DIR}/${TARGET} : $(OBJS)
$(CXX) $(OBJS) -o $#
# (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 $#
#(16)Delete dependency files, object files and the target file
.PHONY: all clean
all: ${BUILD_DIR}/${TARGET}
clean:
$(RM) $(DEPS) $(OBJS) ${BUILD_DIR}/${TARGET}
-include $(DEPS)
MKDIR_P ?= mkdir -p
What you need to notice is that your "Makefile" file is the same directory of the include files and sources files,
so you need to change your "IDIR:=../include" to "IDIR:=./include" in your "Makefile".
END!
Here's what i'm using in my windows setup:
CC = g++
CFLAGS = -Wall -std=c++20
SRCDIR = src
HEADDIR = include
OBJDIR = build
BINDIR = bin
# where the executable will be stored
EXECUTABLE := $(BINDIR)/main
# list of all source files
SOURCES := $(wildcard $(SRCDIR)/*.cpp)
# list of all header files
INCLUDES := $(wildcard $(HEADDIR)/*.h)
# from the list of all source files, create a list of all object files
OBJECTS := $(SOURCES:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
# all: clean $(EXECUTABLE)
all: $(EXECUTABLE)
# Link: Generate executable file from object file
$(EXECUTABLE): $(OBJECTS)
#echo LINKING..... $(CC) -o $# $(OBJECTS)
#$(CC) -o $# $(OBJECTS)
#echo RUNNING: $(EXECUTABLE)
#$(EXECUTABLE)
# Compile: Generate object files from source files
# $# := {EXECUTABLE}
# $< := THE first file
# $^ all the dependency
# C++ Sources
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp | makedirs
#echo COMPILING... $(CC) $(CFLAGS) -c "$<" -o "$#"
#$(CC) $(CFLAGS) -c $< -o $#
# `|` is order-only-prerequisites
# https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html
makedirs:
# check if the file exists; if not, create it
# mkdir -p $(OBJDIR) in linux
#if not exist "$(OBJDIR)" mkdir $(OBJDIR)
#if not exist "$(BINDIR)" mkdir $(BINDIR)
#Delete dependence files, object files, and the EXECUTABLE file
clean:
#echo CLEANING UP
# check if the directories exist; if so, delete them
#if exist "$(OBJDIR)" rmdir /s /q $(OBJDIR)
#if exist "$(BINDIR)" rmdir /s /q $(BINDIR)
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