I am learning how to use make. Recently I wrote a makefile to compile one of my projects, which structure is: src (which contains file.cpp and main.cpp) and include (which contains file.h) folders and the makefile, which is written as follows:
TARGET_EXEC := main
CC := g++
BUILD_DIR := .
SRC_DIR := src
OBJ_DIR := obj
SRC := $(shell find $(SRC_DIR) -name '*.cpp')
OBJ := $(SRC:%=$(OBJ_DIR)/%.o)
DEPS := $(OBJ:.o=.d)
INC_DIR := $(shell find $(SRC_DIR) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIR))
CPPFLAGS := $(INC_FLAGS) -MMD -MP
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJ)
$(CC) $(OBJ) -o $# $(LDFLAGS)
$(OBJ_DIR)/%.cpp.o: %.cpp
# mkdir -p $(dir $#)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm -r $(OBJ_DIR) main
-include $(DEPS)
Now I want to add a new folder (test) in which I'll host a tests.cpp code with doctest code. In this case I would like to obtain two executables: main and tests (not only main as before), one for the main and one for the testing. I tried everything, but I don't understand how to modify the previous makefile in order to implement the new test folder informations.
EDIT 1
I tried adding Andreas suggestions and also an all command to create both the executables:
TARGET_EXEC := main
TEST_EXEC := tests
CC := g++
BUILD_DIR := .
SRC_DIR := src
OBJ_DIR := obj
TEST_DIR := test
SRC := $(shell find $(SRC_DIR) -name '*.cpp')
OBJ := $(SRC:%=$(OBJ_DIR)/%.o)
DEPS := $(OBJ:.o=.d)
INC_DIR := $(shell find $(SRC_DIR) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIR))
CPPFLAGS := $(INC_FLAGS) -MMD -MP
all: $(BUILD_DIR)/$(TARGET_EXEC) $(BUILD_DIR)/$(TEST_EXEC)
$(BUILD_DIR)/$(TARGET_EXEC): $(SRC_DIR)/$(TARGET_EXEC).o $(OBJ)
$(CC) $(OBJ) -o $# $(LDFLAGS)
$(BUILD_DIR)/$(TEST_EXEC): $(TEST_DIR)/$(TEST_EXEC).o $(OBJ)
$(CC) $(OBJ) -o $# $(LDFLAGS)
$(OBJ_DIR)/%.cpp.o: %.cpp
# mkdir -p $(dir $#)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
.PHONY: clean all
clean:
rm -r $(OBJ_DIR) main
-include $(DEPS)
Now two executables main and tests are created, but they do the same things (same of the previous main), so it is wrong. When compile my output is:
g++ -Isrc -MMD -MP -c src/osmanip.cpp -o obj/src/osmanip.cpp.o
g++ -Isrc -MMD -MP -c src/main.cpp -o obj/src/main.cpp.o
g++ obj/src/osmanip.cpp.o obj/src/main.cpp.o -o main
g++ obj/src/osmanip.cpp.o obj/src/main.cpp.o -o tests
I think that the error may be in:
$(OBJ_DIR)/%.cpp.o: %.cpp
# mkdir -p $(dir $#)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
What do you think?
EDIT 2
Ok, I think that I found a solution:
TARGET_EXEC := main
TEST_EXEC := tests
CC := g++
BUILD_DIR := .
SRC_DIR := src
OBJ_DIR := obj
TEST_DIR := test
SRC := $(shell find $(SRC_DIR) -name '*.cpp')
TEST := $(shell find $(TEST_DIR) -name '*.cpp')
OBJ := $(SRC:%=$(OBJ_DIR)/%.o)
TEST_OBJ := $(TEST:%=$(OBJ_DIR)/%.o)
DEPS := $(OBJ:.o=.d)
INC_DIR := $(shell find $(SRC_DIR) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIR))
CPPFLAGS := $(INC_FLAGS) -MMD -MP
.PHONY: clean all
all: $(BUILD_DIR)/$(TARGET_EXEC) $(BUILD_DIR)/$(TEST_EXEC)
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJ)
$(CC) $(OBJ) -o $# $(LDFLAGS)
$(BUILD_DIR)/$(TEST_EXEC): $(TEST_OBJ)
$(CC) $(TEST_OBJ) -o $# $(LDFLAGS)
$(OBJ_DIR)/%.cpp.o: %.cpp
# mkdir -p $(dir $#)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
clean:
rm -r $(OBJ_DIR) main tests
-include $(DEPS)
With this makefile the compilation is good (I think), since the obj/src and obj/test folder are created. main executable is compiled correctly and works. Also tests executable is compiled (correclty I think), but I get another error, not related to makefile:
g++ -Isrc -MMD -MP -c src/osmanip.cpp -o obj/src/osmanip.cpp.o
g++ -Isrc -MMD -MP -c src/main.cpp -o obj/src/main.cpp.o
g++ obj/src/osmanip.cpp.o obj/src/main.cpp.o -o main
g++ -Isrc -MMD -MP -c test/tests.cpp -o obj/test/tests.cpp.o
g++ obj/test/tests.cpp.o -o tests
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [makefile:29: tests] Error 1
I think this is due to the fact that my test/tests.cpp file is
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest/doctest.h"
#include <string>
I didn't give it any command for the moment. I implemented doctest without main and in fact it tells me that main function is missing (because it is implemented into the src/main.cpp file). I tried looking at this answer, but I didn't solve this problem.
Do you know how to correctly compile the doctest test.cpp file? Thanks.
EDIT 3
Thanks to Jarod42 answer I solved also this very last issue related to doctest. Now all seems working perfectly.
Many thanks to sll you guys! It is my first post on Stack Overflow and I alrealy love this site.
Have tried humble beginnings? Here is where I would start and build on, key being to separate the main.o from OBJ so that tests can have its main from tests.o:
# Adding include directories (weird way of doing it but ok)
CPPFLAGS := $(addprefix -I,$(shell find src -type d))
# object files
OBJ := src/file1.o src/file2.o
# main
main: src/main.o $(OBJ)
# the test program
tests: test/tests.o $(OBJ)
(Notice this relies on built-in recipes, should work out-of-the-box.)
From there you can re-introduce the other concepts step by step:
Out-of-tree build.
Overrated (at least for GNU Make for which it's all manual).
Glob source files.
If you know what files you have, best not glob.
Dependency file generation and inclusion.
Keep folders and such in variables.
Related
For my c++ code I need a custom processor macro that will be defined during compilation. According to what I have read I concluded in the following Makefile:
CC := g++
# Folders
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
# Targets
EXECUTABLE := app
TARGET := $(TARGETDIR)/$(EXECUTABLE)
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -Dcustom_macro -g -c -Wall -std=c++14
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
$(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo " Cleaning...";
$(RM) -r $(BUILDDIR) $(TARGET)
The build is successful but when I run my app the code inside #ifdef custom_macro #endif is not executed but only when I change it to #ifndef .
I also tried to set -Dcustom_macro=1 but I had the same behavior.
I also tried to insert this with the CPPFLAGS macro as following :
CC := g++
# Folders
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
# Targets
EXECUTABLE := app
TARGET := $(TARGETDIR)/$(EXECUTABLE)
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g -c -Wall -std=c++14
CPPFLAGS := -Dcustom_macro
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
$(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo " Cleaning...";
$(RM) -r $(BUILDDIR) $(TARGET)
But nothing changed. The parameters that are passed to make according to compiler are:
The parameteres that are passed to make are the following:
g++ -Dcustom_macro -g -c -Wall -std=c++14 -I include -c -o build/main.o src/main.cpp
Does anyone has any idea what I'm doing wrong?
Seems like you missed a space before macro name
CPPFLAGS := -D custom_macro
I have a problem with the dependencies in my Makefile.
There is no problem with the compilation, it compiles perfectly the good *.cc and *.hh but unfortunately, it does not re-compile the dependencies, thus there is no update in the executable.
Here is my makefile:
EXEC ?= program
SRCS = $(shell find -name *.cc)
DEP = $(SRCS:.cc=.d)
OBJDIR = objs
OBJS = $(SRCS:./%.cc=$(OBJDIR)/%.o)
CXX = g++
CFLAGS = -std=c++14 $(addprefix "-I", $(shell find -type d))
## Clean rule
.PHONY: clean
clean:
rm -rf $(OBJDIR)
rm -f $(EXEC)
$(EXEC) : $(OBJS)
#echo "Linking: $#"
$(CXX) $(OBJS) -o $#
-include $(DEP)
$(OBJDIR)/%.o : ./%.cc ./%.hh
#mkdir -p $(#D)
#echo "Compiling: $<"
#$(CXX) -c $(CFLAGS) -MT $# -MMD -MP -o $# $<
It is probably something related to the flag used by g++ but I do not manage to find the solution;
Thanks in advance for the help that you can provide on this issue,
If you do not specify the filename for the generated dependency files, it is going to be ${#:%.o=%.d} (compiler logic). I.e. your dependency files are in $(OBJDIR) and not in ./ where your makefile expects them to be.
Two alternative solutions:
DEP := $(OBJS:%.o=%.d).
#$(CXX) -c $(CFLAGS) -MT $# -MMD -MP -MF $(<:%.cc=%.d) -o $# $<
On OS X Mavericks i am trying to build a project using the following Makefile:
CC=g++
EXECUTABLE=minigi
SRC_DIR=src
INTERM_DIR=obj
INCLUDES=-I $(SRC_DIR) -I /usr/local/Cg/examples/OpenGL/glew/include/
LIBS=-L/usr/local/lang/NVIDIA_GPU_Computing_SDK/sdk/C/common/lib/linux/ -lpng -stdc++ -lGL -lGLU -lGLEW -lSDLmain -lSDL -lgomp
CFLAGS_COMMON=$(INCLUDES)
CFLAGS=$(CFLAGS_COMMON) -O3 -DNDEBUG -fopenmp
#CFLAGS=$(CFLAGS_COMMON) -g -O0 -D_DEBUG
SOURCE_FILES=$(shell find $(SRC_DIR) -iname '*.cpp')
DEP_FILES=$(SOURCE_FILES:$(SRC_DIR)/%.cpp=./$(INTERM_DIR)/%.dep)
OBJ_FILES=$(SOURCE_FILES:$(SRC_DIR)/%.cpp=./$(INTERM_DIR)/%.o)
all: $(EXECUTABLE)
clean:
rm -rf obj $(EXECUTABLE)
.PHONY: clean all
.SUFFIXES:
.SUFFIXES:.o .dep .cpp .h
$(INTERM_DIR)/%.dep: $(SRC_DIR)/%.cpp
mkdir -p `dirname $#`
printf `dirname $#`/ > $#
$(CC) $(CFLAGS_COMMON) $< -MM | sed -r -e 's,^(.*)\.o\s*\:,\1.o $# :,g' >> $#
ifneq ($(MAKECMDGOALS),clean)
-include $(DEP_FILES)
endif
$(INTERM_DIR)/%.o: $(SRC_DIR)/%.cpp
mkdir -p $(INTERM_DIR)
$(CC) $(CFLAGS) -c $< -o $#
$(EXECUTABLE): $(OBJ_FILES)
$(CC) $^ $(LIBS) -o $#
However, when I type make I get the following error:
obj/app/sdl_gl_appliacation.dep:1: *** missing separator. Stop.
The file obj/app/sdl_gl_application.dep looks as follows:
-n obj/app/
As I know very little about makefiles (and did not write the posted one) every help would be appreciated.
P.S.
I modified the line printf dirname $#/ > $# . In the original file there was an echo -n but that is not working on OS X.
Well, let's clean this up a little bit.
The way the dependencies are handled really is ugly, GCC can do it for you automatically.
EXECUTABLE := minigi
SRC_DIR := src
OBJ_DIR := obj
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
OBJ_FILES := $(SRC_FILES:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
DEP_FILES := $(OBJ_FILES:.o=.d)
LDLIBS := -lpng -lstdc++ -lGL -lGLU -lGLEW -lSDLmain -lSDL -lgomp
LDFLAGS := -L/usr/local/lang/NVIDIA_GPU_Computing_SDK/sdk/C/common/lib/linux/
CPPFLAGS := -MMD -MP -DNDEBUG -fopenmp -I $(SRC_DIR) -I /usr/local/Cg/examples/OpenGL/glew/include/
CXXFLAGS := -O3
.PHONY: all clean
all: $(EXECUTABLE)
clean:
$(RM) -r $(OBJ_DIR) $(EXECUTABLE)
$(EXECUTABLE): $(OBJ_FILES)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
$(OBJ_DIR):
mkdir $#
ifeq "$(MAKECMDGOALS)" ""
-include $(DEP_FILES)
endif
Some quick notes :
You're using C++, so you should use $(CXX) instead of $(CC) which is used for C code.
Along with this, you should use $(CXXFLAGS) instead of $(CFLAGS).
$(CPPFLAGS) is meant for preprocessor flags (-I, -D, or -fopenmp which is a compile-time flag).
-MMD -MP preprocessor flags will auto-generate dependency files when compiling. Learn more.
$(LDFLAGS) is meant for linker flags such as -L flags.
$(LDLIBS) is meant for linker libs such as -l flags
Avoid using the $(shell ) function since it will be executed every time the variable is expanded when assigned with the = operator instead of the := operator. $(wildcard ) is more suited for the job of listing files.
Currently, whenever I do make my makefile tells me
make: `some/obj/file.o' is up to date.
regardless of whether I've edited any of the files involved in generating that object file. How do I make it detect changes? Here is a simple makefile that reproduces the problem:
SHELL := /bin/bash
src := src
sources := $(shell find $(srcDir) -name "*.cpp")
objects := $(sources:%.cpp=%.o)
-include $(sources:%.cpp=%.d)
all: prog
prog: $(objects)
g++ $(objects) -o /a.out
%.o: %.cpp
$(CXX) $(CXXFLAGS) -MMD -MP -c $< -I $(srcDir) -o $#
clean:
find $(srcDir) -type f -iname "*.o" -delete
find $(srcDir) -type f -iname "*.d" -delete
currently I have to run make clean everytime to get it to recompile, which obviously isn't ideal!
EDIT: Here is my attempt based on Chnossos's answer:
EXE := a.out
SRCDIR := src
SRC := $(shell find $(srcDir) -name "*.cpp")
DIR := .obj
OBJ := $(SRC:%.cpp=$(DIR)/%.o)
DEP := $(OBJ:.o=.d)
CXXFLAGS += -std=c++11
CXXFLAGS += -I /home/arman/lib/eigen-eigen-6b38706d90a9
CXXFLAGS += -I /home/arman/lib/boost_1_55_0
CXXFLAGS += -I /home/arman/lib/lodepng/
CXXFLAGS += -L /home/arman/lib/boost_1_55_0/stage/lib
CPPFLAGS += -MMD -MP
.PHONY: all clean
-include $(DEP)
all: $(EXE)
$(EXE): $(OBJ)
$(CXX) $(OBJ) -o $#
$(DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $< -I $(SRCDIR)
clean:
$(RM) -f $(DIR)
I am now getting the following error:
src/core/file1.cpp:839:1: fatal error: opening dependency file .obj/./src/core/file1.d: No such file or directory
Note that I have the following directory structure:
/prog/makefile -> The makefile
/prog/dir1/ -> some cpp/hpp files
/prog/dir2/ -> more cpp/hpp files
/prog/ ->there are some cpp/hpp files here too
I have many folders (more than just dir1 and dir2) so I'd like to not have to specify them each time.
EXE := a.out
SRC := $(wildcard *.cpp)
OBJ := $(SRC:.cpp=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP -I.
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(OBJ) $(DEP)
-include $(DEP)
You can also with a little efforts compile your .o and .d files into a hidden folder like this :
EXE := a.out
SRC := $(wildcard *.cpp)
DIR := .obj
OBJ := $(SRC:%.cpp=$(DIR)/%.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP -I.
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(DIR)/%.o: %.cpp | $(DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
$(DIR):
#mkdir $#
clean:
$(RM) -r $(DIR)
-include $(DEP)
EDIT: Here is my attempt for your edit :
Some quick note, the $(LDLIBS) is here for your -l flags, whereas $(LDFLAGS) is meant for -L flags.
SRCDIR := src
OBJDIR := .obj
EXE := a.out
SRC := $(shell find $(SRCDIR) -name "*.cpp")
OBJ := $(SRC:$(SRCDIR)/%.cpp=$(OBJDIR)/%.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD -MP
CPPFLAGS += -I$(SRCDIR)
CPPFLAGS += -I$(HOME)/lib/eigen-eigen-6b38706d90a9
CPPFLAGS += -I$(HOME)/lib/boost_1_55_0
CPPFLAGS += -I$(HOME)/lib/lodepng/
CXXFLAGS := -std=c++11
LDFLAGS += -L$(HOME)/lib/boost_1_55_0/stage/lib
LDLIBS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
.SECONDEXPANSION:
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp | $$(#D)/
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $# -c $<
%/:
mkdir -p $#
clean:
$(RM) -r $(OBJDIR)
-include $(DEP)
Tell me if something is missing.
-M family of gcc options (-MM, -MMT) generate the makefile fragments you need. A standard technique is
DEPS := $(SOURCES:.c=.d)
.c.d:
$(CC) -o $< -MM $(CFLAGS)
-include $(DEPS)
So I can compile my code (fftw_ex.c) directly with:
login$ gcc -o -g fftw_ex fftw_ex.c -I$TACC_FFTW3_INC -L$TACC_FFTW3_LIB -lfftw3
However, my professor prefers that we use a Makefile. I am just learning how to use Makefile and make, and I'm having trouble creating the Makefile. So far, this is what I have:
# RULES
EXEC := fftw_ex
SRC := $(wildcard *.c)
OBJ := $(patsubst %.c,%.o,%(SRC))
# OPERATIONS
CC := gcc
CFLAGS := -O3 -I$TACC_FFTW3_INC
LDFLAGS := -L$TACC_FFTW3_LIB
LDLIBS := -lfftw3
$(EXEC): $(OBJ)
$(CC) $(LDFLAGS) $(LDLIBS) -o -g $# $^
%.o: %.c
$(CC) $(CFLAGS) -c $<
# PHONY TARGETS
.PHONY: clean
clean:
#echo Cleaning...;rm -rf *.o fftw_ex
I know there's a problem with the SRC line, as i'm getting the error message:
make: *** No rule to make target `%(SRC)', needed by `fftw_ex'. Stop.
Any help to get this to work would be appreciated.
1)To resolve:
No rule to make target `%(SRC)'
replace %(SRC) in
OBJ := $(patsubst %.c,%.o,%(SRC))
with $(SRC)
2)In line:
$(CC) $(LDFLAGS) $(LDLIBS) -o -g $# $^
you have mistake: -o -g, should be -g -o