I am working on a project where I constantly need to create new c++ executables. They all rely on some common headers and sources files, so I am wondering how to simplify the compilation and Makefile writing.
The best I have come up with so far is something like this:
file1: $(BUILDDIR)/$#.o $(COMMON_OBJECTS) $(COMMON_LIBS)
$(CCCOM) $(CCFLAGS) $(BUILDDIR)/$#.o $(COMMON_OBJECTS) -o $(BINDIR)/$# $(LIBFLAGS)
and then I have to copy this target for each executable I want to add. Ideally I want to define this rule once for arbitrary target and then simply call make any_file_name.
Is something like that possible?
How do people organize c++ project with lots of executables? (I am new to c++ and coming from python that is a very natural thing)
You could make it so that each executable corresponds to a single .cpp file in a directory (e.g. executables/foo.cpp, executables/bar.bpp), and then work from there -- this will save you from having to touch the Makefile every time you add another one.
You should, probably, also set up your project to create a shared library, which the (light-weight) executables link to. (The executables effectively just doing some command-line parsing, and offloading the actual work to library functions.) This way, you will not end up with the code from those $(COMMON_OBJECTS) being replicated in every executable.
To simplify everything I'm assuming you have sources file1.cpp, file2.cpp and so on, and all your files reside in the same directory. Then Makefile fragment below will do what you want:
all: $(basename $(wildcard file?.cpp))
file%: file%.cpp
To make everyhing:
make all
To make file1:
make file1
To make file1 and file2:
make file1 file2
Here is an example makefile with automatic header dependency generation for you:
BUILD := debug
BUILD_DIR := ${BUILD}
CXX := g++
cppflags.debug :=
cppflags.release := -DNDEBUG
cppflags := ${cppflags.${BUILD}} ${CPPFLAGS}
cxxflags.debug :=
cxxflags.release := -O3
cxxflags := ${cxxflags.${BUILD}} ${CXXFLAGS}
ldflags := ${LDFLAGS}
ldlibs := ${LDLIBS}
exes := # Executables to build.
### Define executables begin.
exes += exe1
exe1.obj := exe1.o
exes += exe2
exe2.obj := exe2.o
### Define executables end.
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CXX} -o $# ${ldflags} $^ ${ldlibs}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : %.cc | $${#D}
${CXX} -o $# -c ${cppflags} ${cxxflags} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
Usage example:
$ cat exe1.cc
#include <iostream>
int main() { std::cout << "Hello, world!\n"; }
$ cat exe2.cc
#include <iostream>
int main() { std::cout << "Hello, world!\n"; }
$ make
mkdir -p debug
g++ -o debug/exe1.o -c -MD -MP exe1.cc
g++ -o debug/exe1 debug/exe1.o
g++ -o debug/exe2.o -c -MD -MP exe2.cc
g++ -o debug/exe2 debug/exe2.o
$ make BUILD=release
mkdir -p release
g++ -o release/exe1.o -c -DNDEBUG -O3 -MD -MP exe1.cc
g++ -o release/exe1 release/exe1.o
g++ -o release/exe2.o -c -DNDEBUG -O3 -MD -MP exe2.cc
g++ -o release/exe2 release/exe2.o
$ make clean
rm -rf debug
$ make BUILD=release clean
rm -rf release
Related
I am quite new to Make. I am attempting to write a Makefile to build a medium-sized Linux C/C++ application as below.
Making a simple Makefile by having all source files in one location and explicitly listing the source files works ok for me but I would like it to be more generic.
I have all my source files (C and C++) in the src folder in different subdirectories. I have header files inside an inc and inc/common folder, and then libs inside a lib folder.
The Makefile is run on the same level :
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
CXX := /bin/arm-linux-gnueabi-g++
EXE := $(BIN_DIR)/runfile
SRC := $(shell find $(SRC_DIR) -name *.cpp -or -name *.c)
OBJ := $(patsubst $(SRC_DIR)/%,$(OBJ_DIR)/%,$(addsuffix .o,$(basename $(SRC))))
CPPFLAGS := -Iinc -Iinc/common -MMD -MP
CXXFLAGS := -std=c++11 -Wall
LDFLAGS := -Llib
LDLIBS :=
.PHONY: all clean
all: $(EXE)
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(OBJ:.o=.d)
I get lots of errors such as below when I run it, including problems opening dependency files. I think i'm almost there, but can't see my error exactly :
compilation terminated.
/bin/arm-linux-gnueabi-g++ -Iinc -Iinc/common -MMD -MP -std=c++11 -Wall -c -o obj/main.d.o
cc -Llib obj/main.d.o -o obj/main.d
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: relocations in generic ELF (EM: 40)
/usr/bin/ld: obj/main.d.o: error adding symbols: file in wrong format
I don't see how the output you show can be generated from the makefile you show here but anyway.
This is not right:
$(OBJ_DIR)/%.o: $(SRC) | $(OBJ_DIR)
A pattern rule is a template that tells make "if you want to build a target that matches this pattern, then you can build it from the prerequisites that match this pattern".
Here you are listing ALL your source files as a prerequisite for EVERY object file. Suppose SRC is set to foo.c bar.c biz.c baz.c, then this expands to:
obj/%.o : foo.c bar.c biz.c baz.c | obj
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
You're telling make that every single .o target depends on ALL the source files, not just the one for that object file. Further, the automatic variable $< always expands to the first prerequisite, which here will always be foo.c. So, you're compiling foo.c four times, creating each of the object files.
The very first important rule when debugging makefiles is to look carefully at the output (command lines) that make prints. If they are not right, then your makefile is not right. If you do that you'll see all the compile lines are compiling the same source, like:
g++ -c foo.c -o obj/foo.o
g++ -c foo.c -o obj/bar.o
g++ -c foo.c -o obj/biz.o
g++ -c foo.c -o obj/baz.o
That clearly cannot work and it's why you get link errors trying to link together all these object files: they all have the same content.
You need this:
$(OBJ_DIR)/%.o : $(SRC_DIR)/%.cpp
#mkdir -p $(#D)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $#
which tells make how to build an object file from a single source file.
You also need to create the actual output directory that the object file will go into. Just creating $(OBJ_DIR) is not enough, if the object file appears in a subdirectory.
I am attempting to create a single top-level recursive makefile, idea being once the makefile is created, it will require little maintenance when files are added or removed from the project.
The issue that I am having is when there are files with the same name but reside in different directories, GNU make will use the .cpp file from the first directory is sees throughout the rest of the build and when the linker runs, it complains about multiple definitions of a function because the .o files that are generated are all based off of the same source file.
The code I am reference below is not the code of my actual project but it exhibits the same issues I am having when trying to build my main project. Here is the layout of my top-level directory with source code residing in subdirectories.
otter#ubuntu:~/work/temp/maketest$ tree
.
├── exec
│ └── main.cpp
├── hello
│ ├── hello.cpp
│ └── hello.h
├── makefile
└── world
├── hello.cpp
└── hello.h
This example is pretty simple - hello/hello.cpp prints "Hello" and world/hello.cpp prints "World!!". main.cpp calls each function to print "HelloWorld!!"
Here is each file.
exec/main.cpp
#include <iostream>
#include "../hello/hello.h"
#include "../world/hello.h"
int main()
{
print_hello();
print_world();
return 0;
}
hello/hello.cpp
#include "hello.h"
void print_hello()
{
std::cout << "Hello";
}
world/hello.cpp
#include "hello.h"
void print_world()
{
std::cout << "World!!\n";
}
Here is my makefile
#Specify modules to include in the build - corresponds to source code locations.
MODULES := exec \
world \
hello
CXX := g++
RM := rm -rf
#Create a list of the source directories
SRC_DIR := $(addprefix ./,$(MODULES))
#Create a variable for the build output directory
BUILD_DIR := $(addprefix ./build/,$(MODULES))
#C++ Compiler flags
CPPFLAGS := -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c
#Flags for generating dependency files.
DEPFLAGS := -MMD -MP -MT "$$#" -MF "$$(#:%.o=%.d)"
#Creates a list of all the source files that we wish to include in the build
CPP_SRCS := $(foreach sdir, $(SRC_DIR), $(wildcard $(sdir)/*.cpp))
#Creates a list of all the object files that we need to build based off source files
OBJ_TARGET := $(foreach sdir, $(MODULES), $(wildcard $(sdir)/*.cpp))
OBJS := $(patsubst %.cpp, ./build/%.o, $(OBJ_TARGET))
#Specify directories to search
vpath %.cpp $(SRC_DIR) $(BUILD_DIR)
#"function" that contains the rule to make the .o files that exist within a source director and sub-directory
define make-goal
$1/%.o: %.cpp
#echo 'Building file: $$<'
#echo 'Invoking: Linux G++ Compiler'
$(CXX) $(CPPFLAGS) "$$<" -o "$$#" $(DEPFLAGS)
#echo 'Finished building: $$<'
#echo ' '
endef
.PHONY: all checkdirs clean build/HelloWorld
all: checkdirs build/HelloWorld
build/HelloWorld: $(OBJS)
#echo 'Building Target: $#'
#echo 'Invoking: G++ Linker'
$(CXX) -L/usr/local/lib $^ -o $#
#echo 'Finished building target: $#'
#echo ' '
clean:
-$(RM) $(BUILD_DIR)
#Makes sure that the output directory exists
checkdirs: $(BUILD_DIR)
#Creates the output directory, build, if it doesn't exist
$(BUILD_DIR):
#mkdir -p $#
#This is the important "recursive" part - this will loop through all source directories and call 'make-goal', which contains the rule to make the associated .o file.
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
And when I attempt to build this small project, I get the following. Notice ./world/hello.cpp is used twice when building .o files - the first time is output to build/world/hello.o and the second time to /build/hello/hello.o and then the linker fails because the .o files are the same.
Building file: ./exec/main.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./exec/main.cpp" -o "build/exec/main.o" -MMD -MP -MT "build/exec/main.o" -MF "build/exec/main.d"
Finished building: ./exec/main.cpp
Building file: ./world/hello.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/world/hello.o" -MMD -MP -MT "build/world/hello.o" -MF "build/world/hello.d"
Finished building: ./world/hello.cpp
Building file: ./world/hello.cpp
Invoking: Linux G++ Compiler
g++ -std=c++0x -O0 -g3 -Wall -fmessage-length=0 -c "./world/hello.cpp" -o "build/hello/hello.o" -MMD -MP -MT "build/hello/hello.o" -MF "build/hello/hello.d"
Finished building: ./world/hello.cpp
Building Target: build/HelloWorld
Invoking: G++ Linker
CPP_SRCS: ./exec/main.cpp ./world/hello.cpp ./hello/hello.cpp
g++ -L/usr/local/lib build/exec/main.o build/world/hello.o build/hello/hello.o -o build/HelloWorld
build/hello/hello.o: In function `print_world()':
/home/otter/work/temp/maketest/./world/hello.cpp:4: multiple definition of `print_world()'
build/world/hello.o:/home/otter/work/temp/maketest/./world/hello.cpp:4: first defined here
build/exec/main.o: In function `main':
/home/otter/work/temp/maketest/./exec/main.cpp:7: undefined reference to `print_hello()'
collect2: error: ld returned 1 exit status
makefile:46: recipe for target 'build/HelloWorld' failed
make: *** [build/HelloWorld] Error 1
So does anyone know why ./world/hello.cpp is used twice when building the .o files? Even though the .cpp files have the same name, they are in different directories and I would think make would be smart enough to treat them as different files and not re-use the first file every time is sees subsequent files with the same name.
I'm not sure why your approach isn't working -- I'll try to solve that later if I have time -- but there's a much easier approach:
build/HelloWorld: $(OBJS)
#echo 'Building Target: $#'
#echo 'Invoking: G++ Linker'
$(CXX) -L/usr/local/lib $^ -o $#
#echo 'Finished building target: $#'
#echo ' '
$(OBJS): build/%.o: %.cpp
#echo building $# from $<
mkdir -p $(dir $#)
$(CXX) $(CPPFLAGS) $< -o $#
EDIT: user657267 found why your approach wasn't working.
I have the makefile given below. When I do make I get the following error
cc -c -o timing.o timing.c
test_c.c:5:17: fatal error: test.h: No such file or directory
#include "test.h"
I have manually verfied that test.h is present in ../include path. I am not sure why this is not finding the header file.It would be great if someone could help.Also I would expect g++ instead of cc
# Makefile template for shared library
CXX = g++ # C++ compiler
CXXFLAGS = -fPIC -Wall -Wextra -O2 -g -I../include #CXX flags
LDFLAGS = -lboost_system -shared # linking flags
RM = rm -f # rm command
TARGET_LIB = libtest.a # target lib
C_SRCS := test_a.c test_b.c
CPP_SRCS := test_c.cpp test_d.cpp
OBJS := $(C_SRCS:.c=.o) $(CPP_SRCS:.cpp=.o)
.PHONY: all
all: ${TARGET_LIB}
$(TARGET_LIB): $(OBJS)
$(CXX) $(CXXFLAGS) ${LDFLAGS} -o $# $^
.PHONY: clean
clean:
-${RM} ${TARGET_LIB} ${OBJS}
~
You have not written a rule for building timing.o from timing.c, so Make uses the default rule it has for that.
But that rule uses CFLAGS, not CXXFLAGS. The CXXFLAGS variable appears in the rule for building object files from C++ sources.
So modify CFLAGS instead of CXXFLAGS, and it should work.
I have been creating a library. When I compile it as a static library, it works fine. Now I want to turn it into a shared library. The library is created and in the proper place, but when I try to compile the client code, the linking phase says that it can't find the library.
I already tried to rename it to al or dylib but that doesn't help either. When I put the -v flag on the linking, I can see that my library path is there. I also tried different paths. I used a relative path, but even with a full path it doesn't find it.
The Makefile from the library:
.SUFFIXES:
.SUFFIXES: .o .cpp
.SUFFIXES: .o .d
CC := g++
LNK:= g++
CXXFLAGS_RELEASE = -fPIC -shared -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -fPIC -shared -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
HDIR:= include
INCLUDE_PATHS:= -Iinclude -Iinclude/interfaces -Iinclude/support
CPP_FILES := propertyfile/propertyfile.cpp \
propertyfile/propertyitem.cpp \
propertyfile/propertyfactory.cpp \
helper/string_helper.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
LIBS:=
TARGET:= libsupport.so
all: $(TARGET)
$(TARGET): $(OBJ)
$(LNK) -o $(TARGET) $(OBJ) -shared
#cp $(TARGET) ../lib
#cp -r include ..
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
And here is the Makefile for the application:
.SUFFIXES:
.SUFFIXES: .o .cpp
CC := g++
LD := g++
CXXFLAGS_RELEASE = -O2 -Wall -fmessage-length=0
CXXFLAGS_DEBUG = -g -Wall -fmessage-length=0 -D _DEBUG
CXXFLAGS = $(CXXFLAGS_DEBUG)
OBJDIR:= obj
SRCDIR:= src
INCLUDE_PATHS:= -Iinclude -I../include
LIBS:= -L /cygdrive/d/src/c/lib -lsupport
CPP_FILES := nohupshd.cpp \
daemon.cpp \
task.cpp
OBJ := $(patsubst %.cpp,$(OBJDIR)/%.o, $(CPP_FILES))
SRC := $(patsubst %.cpp,$(SRCDIR)/%.o, $(CPP_FILES))
TARGET:= nohupshd
all: $(TARGET)
$(TARGET): $(OBJ)
$(LD) -o $(TARGET) $(OBJ) $(LIBS)
clean:
rm -f $(OBJ) $(ASM) $(TARGET)
-include $(patsubst %.cpp,$(OBJDIR)/%.d, $(CPP_FILES))
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp $(OBJDIR)/%.d
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -c $< -o $# $(INCLUDE_PATHS)
$(OBJDIR)/%.d: $(SRCDIR)/%.cpp
#mkdir -p `dirname $#`
$(CC) $(CXXFLAGS) -MM -MT $# -MF $(OBJDIR)/$*.d -c $< $(INCLUDE_PATHS)
After some experimenting I found a solution on how to compile a shared library under cygwin.
Apparently the compiler is looking for a DLL file even though it is inside cygwin. so the first step is to add your path, where the library is going to be to the PATH variable.
export PATH=$PATH:/cygdrive/d/src/c/lib
Apparently when linking against a shared library, the linker seems to look for a DLL file by default. I don't know why, because inside cygwin I would expect it to look for a .so file just like on other UNIX systems.
However, there are two solutions to this, which both work.
First, you can create a link to your .so library with the name .dll
ln -s /cygdrive/d/src/lib/libsupport.so libsupport.dll
In this case the makefile doesn't have to be changed and -lsupport will find the library while linking. I prefer this solution.
Second, you can specify the linker option with the full name.
LIBS:= -L /cygdrive/d/src/c/lib -l:libsupport.so
then you don't have to create a link.
So the crucial thing seems to be that the shared library must be in the PATH under cygwin. Using LD_LIBRARY_PATH doesn't help in that case as you can link the executable, but when trying to run it, it will not find it.
ldd nohupshd.exe
libsupport.so => not found
UPDATE: For some reason when I checked with ldd, my library was suddenly gone from the list. I found out that cygwin uses the name to differentiate between MS Windows and Unix shared libraries. So in order to make it work, the name of the library must be cyg.so to make it work, otherwise the exectuable seems to be some Windows build. In this case you don't need to create the link named x.dll as the shared library stays inside the Unix environment.
$(LNK) -o cyg$(TARGET).so $(OBJ) -shared
When using eclipse for debugging, the path to the shared library must also be in the windows path environment variable. Otherwise the debug session immediately terminates without an error.
This is my current makefile.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cpp object.cpp foo.cpp
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cpp.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.d: %.cpp
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
It works perfectly with one exception. If the directory is already clean (no *.d, *.o) and I run 'make clean', it re-creates the dependencies, then immediately deletes them:
[user#server proj]$ make
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
g++ -Wall -O3 -c main.cpp -o main.o
g++ -Wall -O3 -c object.cpp -o object.o
g++ -Wall -O3 -c foo.cpp -o foo.o
g++ -Wall -O3 main.o object.o foo.o -o testcpp
[user#server proj]$ make clean
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$ make clean
g++ -M -Wall -O3 foo.cpp > foo.d
g++ -M -Wall -O3 object.cpp > object.d
g++ -M -Wall -O3 main.cpp > main.d
rm -f main.o object.o foo.o main.d object.d foo.d testcpp
[user#server proj]$
I don't understand why the second 'make clean' would re-generate the dependency files. How can I avoid this? This isn't a big deal for this contrived example, but for a large project, it can be quite time-consuming.
Thanks.
It's because the .d files are being -included unconditionally. As far as make knows, they could add dependencies or commands to the clean target. All included files are built first for this reason, otherwise you might get an incorrect or failed build. To disable this, you want to conditionally include the dependency files:
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
An alternative solution is to generate the dependency files using touch and have them replaced by actual data as a side-effect of compilation. This is how automake does its dependency tracking, as it makes one-time builds faster. Look into the -MD and -MMD options to gcc if you want to go this route. Use a pattern rule like:
%.d:
#touch $#
To initially create the dependency files.
If you want to skip the include for multiple targets, you can use the filter function.
MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc
# Include only if the goal needs it
ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),)
-include $(DEPS)
endif
It wants to regenerate the dependency files because it always tries to regenerate all of the makefiles, including -include'd makefiles, before doing anything else. (Well, actually, for me it doesn't do that - I have GNU Make 3.81 - so maybe it's a bug in your version that was fixed, or an optimization that mine has and yours doesn't. But anyway.)
The easiest way around this is to write your rules so they generate the .d files as a side effect of regular compilation, rather than giving explicit rules to generate them. That way, when they're not there, Make doesn't know how to generate them so it doesn't try (in a clean tree, the .cpp.o rules are enough, you don't need the header file dependencies). Look at an Automake-generated makefile -- a simple one -- to see how it's done.
The leading - in -include means that make won't complain if the dependencies are missing and can't be remade, but it doesn't mean it won't try to make them first (and, in this case, succeed) -- after all, anything interesting or important could be in the included files, whence the let's-try-making them attempt. I don't think there's a way to stop that.
For docs on include and -include, see here.