Recursive makefile for c++ source - c++

I've been struggling with makefiles for a while now, since I don't really get how they work...
My directory structure is as followed:
--bin/
--build/
--includes/
--src/
----classes/
------somefiles.hpp
------somefiles.cpp
----states/
------somestates.hpp
----main.cpp
----few-other-files.cpp
--Makefile
--.gitignore
Which worked fine with my makefile, until I started adding those subdirs, classes and states
I can't seem to find how to include those subdirs in my makefile which is:
CC := g++
SRCDIR := src
BUILDDIR := build
TARGET := bin/game
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g -Wall
LIB := -lsfml-audio -lsfml-graphics -lsfml-network -lsfml-system -lsfml-window
INC := -I includes -I /usr/local/include -L /usr/local/lib
$(TARGET): $(OBJECTS)
#echo "Linking..."
#echo "$(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo "$(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo "Cleaning..."
#echo "$(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
.PHONY: clean
Problem: Fatal error: can't create build/classes/stateManager.o: No such file or directory
Normally, the problem is that it can't build the directory. But I thought the mkdir -p would solve that.
Any help is greatly appreciated.

Replace:
mkdir -p $(BUILDDIR)
with
mkdir -p $(#:D)
Another way is to let make treat directories as targets and have them automatically created for you, so that you do not have to clutter your recipes with mkdir -p invocations:
.SECONDEXPANSION:
# Make the object file depend on its directory using order-only dependency.
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT) | $$(dir $$#)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
# Let make create the directories for your targets.
%/:
mkdir -p $#
# Do not remove the directories because they are "intermediate" targets.
.PRECIOUS : %/

Related

Preprocessor macro definition via a Makefile does not work properly in c++

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

How to add cap_net_raw capability via a Makefile to c++ executable file on linux

I have created a c++ that runs on Linux and on of its functionalities is to ping on a provided host. The ping has been based on relevant Poco libraries. However in order to run successfully on linux the produced c++ executable file should have the cap_net_raw capability set by giving
setcap cap_net_raw=ep /bin/C++_APP
I have also used the following Makefile based on an example I found by googling.
CC := g++
# Folders
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
# Targets
EXECUTABLE := C++_APP
TARGET := $(TARGETDIR)/$(EXECUTABLE)
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -c -Wall
INC := -I include -I /usr/local/include
LIB := -L /usr/local/lib -lPocoFoundation -lPocoNet -lPocoUtil
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
.PHONY: clean
I added the following command as the last build command
#echo "Setting Capabilities"; sudo setcap cap_net_raw=ep $(TARGETDIR)/$(EXECUTABLE)
However I got the following error:
Failed to set capabilities on file `bin/NPT' (Invalid argument) The
value of the capability argument is not permitted for a file. Or the
file is not a regular (non-symlink) file
On the other hand when I give the command after the build of the c++ executable everything works fine. What am I doing wrong?
You added the command at the wrong place. You need to add it after the executable is made, not before. Try this:
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
#echo " Setting Capabilities"; sudo setcap cap_net_raw=ep $(TARGET)

Modify the makefile to include subdirectories

I'm working with a small program in c++ to learn the makefile.
The program has 2 source files (main.cpp and classf.cpp) and one header file (classf.h). All files are included in the project directory which is called "testmake". This is the generated makefile by eclipse on windlows:
CXXFLAGS = -O2 -g -Wall -fmessage-length=0
OBJS = main.o classf.o
LIBS =
TARGET = createPddl.exe
$(TARGET): $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
all: $(TARGET)
clean:
rm -f $(OBJS) $(TARGET)
I would like to modify the makefile to accept new sub-directories, e.g, when I add a folder called "testmake/src" and move the file main.cpp inside it, folder called "testmake/csource" and move the classf.cpp inside it, and create a folder called "testmake/cheader" and move the classf.h inside it.
This makefile was genereated automatically by eclipse, and does not accept any changes. There for i have created manually a make file which is working with any c++ project that has a structure as tree.
I actually use this Makefile in general
CC := g++ # This is the main compiler
SRCDIR := src
BUILDDIR := build
TARGETDIR :=bin/
TARGET := pddlcrate
DATADIR := data
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g # -Wall
#LIB := -pthread -lmongoclient -L lib -lboost_thread-mt -lboost_filesystem-
mt -lboost_system-mt
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGETDIR)$(TARGET) $(LIB)"; $(CC) $^ -o
$(TARGETDIR)$(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c - o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
for any c++ project with this tree structure
$ tree .
├── Makefile
├── bin
>exefile
├── include
> *.h files
├── obj
> *.o files
├── src
>*.cpp

How to compile/link a unittest in a Linux Makefile correctly?

On a Linux system I want to compile and link an unittest using the gtest framework. I am using the following Makefile:
CC := g++ # This is the main compiler
SRCDIR := src
BUILDDIR := build
TARGET := bin/myapp
TEST := tester
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
CFLAGS := -g
LIB := -pthread -L lib -L /usr/local/lib -lsqlite3 -lboost_thread -lcrypto
INC := -I include
$(TARGET): $(OBJECTS)
#echo " Linking..."
#echo " $(CC) $^ -g -o $(TARGET) $(LIB)"; $(CC) $^ -o $(TARGET) $(LIB)
$(BUILDDIR)/%.o: $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(BUILDDIR)
#echo " $(CC) $(CFLAGS) $(INC) -c -o $# $<"; $(CC) $(CFLAGS) $(INC) -c -o $# $<
clean:
#echo " Cleaning...";
#echo " $(RM) -r $(BUILDDIR) $(TARGET)"; $(RM) -r $(BUILDDIR) $(TARGET)
# Tests
$(TEST): $(OBJECTS)
#echo " Compiling test..."
$(CC) $(CFLAGS) test/tester.cpp $(INC) -c -o build/$(TEST).o
#echo " Linking test..."
$(CC) $(CFLAGS) $(INC) -pthread test/tester.cpp /usr/lib/libgtest.a $(LIB) -L build build/tester.o -o bin/$(TEST)
.PHONY: clean
The compilation of the main application (myapp) works just fine, but I get into trouble compiling/linking the test file located in the test directory.
When I do NOT include any other library (from src or include, respectively) then the following line
$(CC) $(CFLAGS) -pthread test/tester.cpp /usr/lib/libgtest.a $(INC) -o bin/$(TEST)
just works perfect and creates a runnable executable. However, when I try to include some library from my project in tester.cpp like e.g.
#include "MyClass.h"
(which is defined as MyClass.h in include and as MyClass.cpp in src) then, with the above Makefile, I get various undefined reference errors (in what I have labelled as the 'compile' stage for 'tester').
I am not sure if I should compile the file tester.cpp first and then link all the libraries, or if I should do everything in one step? I do not know how to do either.
Any advice on fixing this Makefile above is appreciated...
OBJECTS := $(patsubst $(SRCDIR)/%.$(SRCEXT),$(BUILDDIR)/%.o,$(SOURCES))
OBJECTS := $(filter-out $(BUILDDIR)/main.o, $(OBJECTS))
$(TARGET): $(OBJECTS) $(BUILDDIR)/main.o
#echo " Linking..."
$(CC) $^ -o $# $(LIB)
tester: bin/$(TEST)
bin/$(TEST): build/$(TEST).o $(OBJECTS)
#echo " Linking test..."
$(CC) $(INC) -pthread $^ /usr/lib/libgtest.a $(LIB) -L build -o $#
P.S. Please don't edit the question like that, after you have answers. If you want to make a change (that doesn't render the existing answers meaningless), add new test to the bottom of the question, preferably with "EDIT:".

How do I ensure my makefile detects changes in my header and cpp 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)