Place object files in particular directory with make - c++

I've been looking into building cpp applications with make and looking at various sources online. While it works, I'm trying to build my object files and place those into a particular directory rather then have them go into the same src/ as my source files. Ideally, I would like them to go into the OUT_O_DIR location, but they're being generated and placed in the src/, which I don't want.
I want a structure like this:
.
|- Makefile
|- include/
| |- *.h
|- src/
| |- *.c
|- output/
| |- App
|- obj/
| |- *.o
My make version:
GNU Make 4.1
Built for x86_64-pc-linux-gnu
My Makefile:
OUT_O_DIR := $(OUT_DIR)/obj
PROJ = hello
SOURCE = $(wildcard src/*.cpp)
INC = $(wildcard include/*.h)
OBJS = $(SOURCE:.cpp=.o)
CFLAGS = -I include
CC = g++
.PHONY: directories
all : directories $(OUT_DIR)$(PROJ)
directories: $(OUT_DIR)
$(OUT_DIR)$(PROJ) : $(OBJS)
$(CC) -o $# $(OBJS)
.cpp.o: $(INC)
#echo $#
$(CC) -c $(CFLAGS) $< -o $#
clean :
rm -rf $(OUT_DIR)
$(OUT_DIR):
mkdir -p $(OUT_DIR)

The '.cpp.o' does not extend to cover multiple folders. Two options
Modify OBJS and rule to build object.
#OBJS = $(SOURCE:.cpp=.o)
OBJS = $(SOURCE:src/%.cpp=$(OUT_O_DIR)/%.o)
...
#.cpp.o: $(INC)
${OUT_O_DIR}/%.o: src/%.cpp $(INC)
$(CC) -c $(CFLAGS) $< -o $#
Or use vpath to specify the .cpp files are in src
#OBJS = $(SOURCE:.cpp=.o)
OBJS = $(SOURCE:src/%.cpp=$(OUT_O_DIR)/%.o)
vpath %.cpp src
${OUT_O_DIR}/%.o: %.cpp $(INC)
$(CC) -c $(CFLAGS) $< -o $#

Related

Makefile: no rule to make target: how to set the correct rules?

I have a project that I am trying to create a Makefile for. The folder structure looks like this:
|-- bin
|-- build
|-- Makefile
|-- src
| |-- some_files.cpp
| |-- some_files.h
| |-- ForestFactory
| |-- MMParSet
| |-- century
| |-- century_carbon.cpp
| |-- century_carbon.h
| `-- grass
`-- src_multithread
|-- __history
and I have tried to use this reference to create a Makefile.
The Makefile I have is
CC := g++
SRCDIR := src
BUILDDIR := build
TARGETDIR := bin
INSTALLBINDIR := /usr/local/bin
TARGET := bin/formind
# CPP files
SOURCES := $(shell find $(SRCDIR) -type f -name *.cpp)
# remove the src path and add the build path and the .o extension
OBJECTS := $(addprefix $(BUILDDIR)/,$(patsubst %.cpp,%.o,$(notdir $(SOURCES))))
CFLAGS := -std=c++11 -stdlib=libc++
INC := -I/usr/local/include -I $(SRCDIR) -I $(SRCDIR)/century -I $(SRCDIR)/grass -I $(SRCDIR)/MMParSet -I $(SRCDIR)/ForestFactory
$(TARGET): $(OBJECTS)
#mkdir -p $(TARGETDIR)
#echo " Linking..."
#echo " $(CC) $^ -o $(TARGET)"
$(CC) $^ -o $(TARGET)
$(BUILDDIR)/%.o: $(SRCDIR)/%.cpp
#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
When I try to make I get the following error message:
make: *** No rule to make target `build/century_carbon.o', needed by `bin/formind'. Stop.
The source files come from a nested set of subdirectories inside src. My understanding was that the OBJECTS variable should contain the complete paths of the final object files, so that I have something like
$SOURCES = src/century/century_carbon.cpp ... src/for_branching.cpp ... src/grass/grass_log.cpp ...
$OBJECTS = build/century_carbon.o ... build/for_branching.o ... build/grass_log.o ...
Is there something wrong in the way I wrote the compilation rules?
The problem is with the nested source directory century. If you add to the makefile:
info:
#echo " Info..."
#echo " SOURCES = $(SOURCES)"
#echo " OBJECTS = $(OBJECTS)"
then make info gives:
Info...
SOURCES = src/century/century_carbon.cpp src/some_files.cpp
OBJECTS = build/century_carbon.o build/some_files.o
This check shows that your construction of these macros is ok. And it also shows, as you report, that make will then tell us:
make: *** No rule to make target 'build/century_carbon.o', needed by 'bin/formind'. Stop.
If you add an additional rule, with the directory century specified:
$(BUILDDIR)/%.o: $(SRCDIR)/century/%.cpp
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
then your build will proceed.
An alternative solution is to use VPATH. Add the line:
VPATH = src:src/century
and also remove $(SRCDIR)/ from your rule, which now becomes:
$(BUILDDIR)/%.o: %.cpp
#mkdir -p $(BUILDDIR)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
Update: The above answer could be improved in two ways:
Use vpath rather than VPATH, for more precise control of the searches.
Automatically generate the argument for vpath / VPATH.
This is suprisingly simple: just replace my hard-coded VPATH line with:
vpath %.cpp $(sort $(dir $(SOURCES)))

Compiling multiple test files efficiently with Makefile

I have a C++ project with the following structure:
/Project
Makefile
/src (.cpp source files)
...
/include (.h header files)
...
/libs
...
/build (.o object files)
...
/tests (target .cpp files I want to compile)
test1.cpp
test2.cpp
test3.cpp
...
/bin (output directory for compiled files)
...
For the tests inside my test file, I would like to be able to
Compile them individually, e.g. "make test1", "make test2"
Compile them all at once
But I would like to be able to do this without needing to define new variables (e.g. TARGET1, TARGET2,...) for each new test file, nor add a bunch of new lines to my makefile for each new test file.
For example, right now I have something like:
CXX = g++
SRC_DIR = ./src
BUILD_DIR = ./build
LIB = -I libs
INC = -I include
SRCS = $(shell find $(SRC_DIR) -type f -name *.cpp)
OBJS = $(patsubst $(SRC_DIR)/%, $(BUILD_DIR)/%, $(SRCS:.cpp=.o))
TARGET1 ?= test1.cpp
TARGET2 ?= test2.cpp
TARGET3 ?= test3.cpp
all: $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)
$(TARGET1): $(OBJS)
$(CXX) ./tests/$(TARGET1).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET1)
$(TARGET2): $(OBJS)
$(CXX) ./tests/$(TARGET2).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET2)
$(TARGET3): $(OBJS)
$(CXX) ./tests/$(TARGET3).cpp $(LIB) $(INC) $^ -o ./bin/$(TARGET3)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
which does the job, but isn't very scalable. How could I do this scalably?
Make has some more tricks that you can use (not tested):
CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))
all: $(TARGETS)
$(TARGETS): $(BIN_DIR)/%: $(OBJS)
$(CXX) $(TEST_DIR)/$*.cpp $(LIB) $(INC) $^ -o $#
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
The main trick here is the static pattern rule for $(TARGETS): in the recipe $* expands as the stem of the pattern. The other tricks are a simpler use of patsubst and the use of wildcard instead of the less efficient shell find. Note that this last one works only if your source files are flat in src, not if they are organized in a hierarchy of sub-directories.
But this does not answer your most tricky request: a way to invoke make testX instead of make bin/testX. So, here is the most tricky part:
SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))
.PHONY: $(SHORTERTARGETS)
# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))
You can even use this foreach-eval-call to factorize other parts of your Makefile:
CXX = g++
SRC_DIR = src
BUILD_DIR = build
TEST_DIR = tests
BIN_DIR = bin
LIB = -I libs
INC = -I include
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJS = $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
TESTS = $(wildcard $(TEST_DIR)/*.cpp)
TARGETS = $(patsubst $(TEST_DIR)/%.cpp,$(BIN_DIR)/%,$(TESTS))
SHORTERTARGETS = $(patsubst $(TEST_DIR)/%.cpp,%,$(TESTS))
.PHONY: all $(SHORTERTARGETS)
all: $(TARGETS)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(INC) -c -o $# $<
# $(1): short target
define TARGETS_rule
$(1): $(BIN_DIR)/$(1)
$(BIN_DIR)/$(1): $(OBJS)
$(CXX) $(TEST_DIR)/$(1).cpp $(LIB) $(INC) $$^ -o $$#
endef
$(foreach t,$(SHORTERTARGETS),$(eval $(call TARGETS_rule,$(t))))
The most difficult to understand in this last version is the need of $$in the recipe (double expansion). But here the GNU make manual is your friend.

-I flag in the makefile does not result in a header file being found (gtest/gtest.h)

Previously I was struggling with creating a makefile in root directory that would deal with source files being in src folder and headers in include folder. Following this I wanted to add another folder tests where I would keep .cpp files with tests. Unfortunately I have problems with this.
The folder structure is:
.
|__makefile
|
|__/src
| |
| |__[regular .cpp files]
|
|__/include
| |
| |__[.h files]
| |
| |__/gtest
| |
| |__gtest.h
|
|__/tests
|
|__test_factorial.cpp
./tests/test_factorial.cpp:
#include "gtest/gtest.h"
#include "factorial.h"
// some tests
makefile:
CC = g++
CFLAGS = -Wall
INCLUDES = -I./include
LIBS = -lgtest -lpthread
SOURCEDIR = ./src/
SRCS = $(shell find ./src/ -name '*.cpp')
SRCS += $(shell find ./tests/ -name '*.cpp')
.PHONY: clean depend
SRCS := $(filter-out ./tests/main_tests.cpp, $(SRCS))
OBJS = $(SRCS:.cpp=.o)
OBJS := $(OBJS:./src%=.%)
release: $(OBJS)
$(CC) $(CFLAGS) -o app $(OBJS) $(LIBS)
VPATH = ./src:./tests
%.o: ./src/%.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c ./src/$*.cpp
%.o: ./tests/%.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c ./tests/$*.cpp
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CC) $(CFLAGS) $(INCLUDES) -MM $^ > ./.depend;
include .depend
When I execute make from the root directory all the files from /src compile fine (I end up having object files in the root directory for them) but I get an error for .cpp file from /tests directory:
g++ -c -o tests/test_factorial.o tests/test_factorial.cpp
tests/test_factorial.cpp:1:25: fatal error: gtest/gtest.h: No such file or directory
compilation terminated.
<builtin>: recipe for target 'tests/test_factorial.o' failed
make: *** [tests/test_factorial.o] Error 1
What might be important, the .depend file seems to have it all right:
test_factorial.o: tests/test_factorial.cpp include/gtest/gtest.h \
include/factorial.h
What is wrong with the makefile?
EDIT
I believe this fragment of the error:
<builtin>: recipe for target 'tests/test_factorial.o' failed
suggests that something is wrong in this part of the makefile:
%.o: ./src/%.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c ./src/$*.cpp
%.o: ./tests/%.cpp
$(CC) $(CFLAGS) $(INCLUDES) -c ./tests/$*.cpp
Why it's trying to do ./tests/test_factorial.o rather than ./test_factorial.o? Let me underline again that object files for ./src/*.cpp files end up in root directory, i.e. ./*.o, not ./src/*.o.
Your makefile is building
tests/test_factorial.o
from
tests/test_factorial.cpp
and that doesn't match the rule
%.o: ./tests/%.cpp
So it is instead using a builtin rule. (As an aside, the convention is to build c++ files using $(CXX) and $(CXXFLAGS) not $(CC)).
Try a rule pattern of
./tests/%.o: ./tests/%.cpp
The reason that your Makefile uses the name tests/test_factorial.o is because
OBJS = $(SRCS:.cpp=.o)
which (it should be obvious) makes the path to the .o file the same as the path to the .cpp.
You have a subsequent rule stripping the path src/
OBJS := $(OBJS:./src%=.%)
and no similar rule for tests/

Generating dependency files in separate folder

I am trying to create a makefile for a project with the following structure:
├──bin/
├──build/
│ ├──foo.d
│ └──bar.d
├──include/
│ └──foo.h
│
├──lib/
├──src/
│ ├──foo.cc
│ └──bar.cc
│
├──Makefile
Here is the makefile:
# Define the compiler and the linker.
CXX = g++
CC = g++
# Folders
srcdir = src
builddir = build
out = bin
# Define preprocessor, compiler, and linker flags.
CPPFLAGS = -I include -std=c++11
LDFLAGS = -g -Llib
# Phony targets
.PHONY: all clean test
# Targets
all : $(out)/bar
$(out)/bar : $(addprefix $(builddir)/,bar.o foo.o)
# Standard clean
clean :
rm -f $(builddir)/*.o $(builddir)/*.d
# Generate dependencies in *.d files
$(builddir)/%.d: $(srcdir)/%.cc
#set -e; rm -f $#; \
$(CPP) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,$(builddir)/\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$;
deps = $(patsubst $(srcdir)/%.cc,$(builddir)/%.d,$(wildcard $(srcdir)/*.cc))
include $(deps)
The dependency files contain the following:
foo.d
build/foo.o build/foo.d : src/foo.cc include/foo.h
bar.d (depends on foo)
build/bar.o build/bar.d : src/bar.cc include/foo.h
Is there any way to generate the .d files in the build/ directory, compile the object files into the very same folder then compile the bin/bar program? Any help appreciated.
EDIT:
The problem was that I was expecting
all : $(out)/foo
$(out)/foo : $(addprefix $(builddir)/,foo.o bar.o)
$(builddir)/%.o : $(srcdir)/%.cc
$(CXX) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
to magically compile the program foo (it works when all files are in the same folder).
Instead I had to specify the recipe:
all : $(out)/foo
$(out)/foo : $(builddir)/foo.o $(builddir)/bar.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $#
$(builddir)/%.o : $(srcdir)/%.cc
$(CXX) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
Drop all of the sed nonsense. gcc can generate everything in one go:
$(builddir)/%.o : $(srcdir)/%.cc
$(CPP) -c $< -o $# -MP -MMD -MF $(#:.o=.d)
That will in one go build build/foo.o and build/foo.d, where build/foo.d will have the autogenerated dependencies for build/foo.o.

cant make my makefile work

Folder structure of project:
|--particle-system
| |-- bin
| | |-- .o files
| |-- docs
| | |-- design.md
| | `-- TO_DO
| |-- Makefile
| |-- src
| | |-- .cpp files + .h files
| `-- test
I need to put all my .o files generated into the bin folder. Also cleanup should remove all .o files and the /bin folder.
My makefile:
# particle-system Makefile
EXE = particlesystem
OBJ_DIR = bin
CFLAGS = -g
CXXFLAGS = -Wall -Wextra -g -std=c++0x
LDFLAGS = -lSDL2 -lSDL2_image -lSDL2_ttf -lSDL2_mixer -lSDL2_gfx -lm
# c++ source files of the project
CXXFILES = $(shell find src -maxdepth 1 -type f -name '*.cpp')
CXXOBJ = $(CXXFILES:.cpp=.o)
ifdef V
MUTE =
VTAG = -v
else
MUTE = #
endif
all: $(EXE)
# build successful
$(EXE): $(CXXOBJ)
$(MUTE)$(CXX) $(CXXOBJ) -o $(EXE) $(LDFLAGS)
$(OBJ_DIR)/%.o: src/%.cpp
$(MUTE)$(CXX) $(CXXFLAGS) $(INCLUDE) $< -c -o $#
$(OBJ_DIR)/%.o: src/%.c
$(MUTE)$(CC) $(CFLAGS) $(INCLUDE) $< -c -o $#
run: all
$(MUTE)./$(EXE)
clean:
# Cleaning...
-$(MUTE)rm -f $(EXE) $(OBJECTS)
I dont know why this makefile isn't working. Please tell whats wrong here.
This line will cause the .o files to be created in the same directory as the source files:
CXXOBJ = $(CXXFILES:.cpp=.o)
Consequently, these lines have no effect, because there are no .o files in $(OBJ_DIR):
$(OBJ_DIR)/%.o: src/%.cpp
$(MUTE)$(CXX) $(CXXFLAGS) $(INCLUDE) $< -c -o $#
$(OBJ_DIR)/%.o: src/%.c
$(MUTE)$(CC) $(CFLAGS) $(INCLUDE) $< -c -o $#
Also, $(INCLUDE) isn't defined.
In this line, $(OBJECTS) isn't defined:
-$(MUTE)rm -f $(EXE) $(OBJECTS)