How to conditionally include a file into Makefile? - c++

Consider the following Makefile:
# <include global configuration Makefile>
INCL = -I../include \
-I<whatever>
CPPFLAGS=$(DEFS) $(INCL)
CXXFLAGS = -O0 -g -Wall -fmessage-length=0
SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o)
all: $(OBJS)
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $# $<
depend: .depend
.depend: $(SRCS)
$(CPP) $(CPPFLAGS) -M $^ > $#
clean:
rm -f $(OBJS)
rm .depend
-include .depend
This Makefile creates an #include dependency chain using the g++ -M command, and includes it. This can be a rather long process. The problem is that this file is generated even if make clean is called, when this file would be deleted anyway. Is ther a way to conditionally include this file, and not bother creating it if the clean target is run?

Something like this:
ifneq ($(MAKECMDGOALS),clean)
-include .depend
endif
See the make manual page on Goals for more information
Edit: -include cannot be tab indented, otherwise it is ignored.

You can do such dependencies for free (i.e., at no runtime cost) during the compile. When you run clean, the dependencies are naturally not remade. See the section Combining Compilation and Dependency Generation in Paul Smith's Advanced Auto-Dependency Generation paper.

Related

C++ Makefile on "complex" tree structure

I have found a lot of related questions, but I was still not able to make my own Makefile.
This makefile is using Mingw64 on Windows, and I want it to run on *nix, currently Debian, but I would like to be able to make it run on Alpine too, as it's used in a Docker container.
The project tree structure is something like :
./
src/
main.cpp
Server.cpp <- use asio and Utils/Split.h
Server.h <- use asio
Utils/
Split.h
lib/
asio/include/ <- asio library (without boost, header only)
Makefile <- That is what I am trying to do right now
Dockerfile
I tried multiple things, here is my latest Makefile (that obviously, does not work) :
NAME := GameServer
CXX := g++
CXXFLAGS := -std=c++2a -DASIO_STANDALONE
SRC_DIR := ./src
LIBS := -I lib/asio-1.18.1/include \
-I lib/rapidjson-1.1.0/include \
-I src
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
SRCS := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS := $(SRCS:%.cpp=%.o)
.PHONY: all
all: $(NAME)
$(NAME): $(OBJS)
$(CXX) -o $# $^
$(OBJS): $(SRCS)
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
Note: the code (.cpp, .h) is valid, it's coming from an already-running project, but built on Visual Studio (compiled with MSVC).
Here are the two functions done my mingw32-make :
g++ -c -o src/Server.o src/main.cpp -I lib/asio/include -I src
g++ -o Server src/main.o src/Server.o
First line : It should builds the .o from the .cpp and adds the include to asio. I added -I src to add src/Utils, but I guess that's not the way of doing it ?
Second line : It should (link ?) the two .o in a single file : the executable.
The errors I am getting with this makefile are :
src/Server.o:main.cpp:(.text+0x36): multiple definition of 'main', src/main.o:main.cpp:(.text+0x36): first defined here (and this, for every .o)
src/main.o:main.cpp:(.text+0x4b): undefined reference to 'Server::Server()' (and this, for every Server methods main calls, even some from asio)
They appears when the second g++ line starts (g++ -o Server src/main.o src/Server.o)
So here are my questions :
What am I doing wrong ?
Is there a better way of trying to make a development environment on Windows and still be able to copy the project in a Docker container (and then compile it with the gcc image) to build it with the same Makefile ?
Sorry if I forgot to mention some details, I am new with Mingw and its environment.
Thank you
Edit : Corrected version :
NAME := GameServer
CXX := g++
CXXFLAGS := -std=c++1z
SRC_DIR := ./src
LIBS := -lwsock32 -lws2_32 \
-I lib/asio-1.18.1/include \
-I lib/rapidjson-1.1.0/include \
-I src
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
SRCS := $(call rwildcard,$(SRC_DIR),*.cpp)
OBJS := $(SRCS:%.cpp=%.o)
.PHONY: all
all: $(NAME)
$(NAME): $(OBJS)
$(CXX) -o $# $^ $(LIBS)
$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
Consider the rule...
$(OBJS): $(SRCS)
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
This tells make that all items in $(OBJS) depend on all items in $(SRCS). But the command...
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
...always compiles the first dependency as identified by $<. It just so happens that in your case $< is src/main.cpp.
Instead you should probably use a pattern rule such as...
$(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)
You can also limit the scope of that rule to only those targets specified by $(OBJS) with a full static pattern rule...
$(OBJS): $(SRC_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $# $< $(LIBS)

Makefile with different source folder for test target

I am very new to C++ makefiles and I have the makefile below which I mostly copied from somewhere on the internet. My contribution to the makefile is the "test" target, which is the problem.
My code is organized in include (for headers), src (for sources) and test (for test sources) directories. For the standard target I want to build all files in the src folder which also includes the main.cpp file. To make the test build I want to build all files in the src folder except main.cpp and additionally all files in the test folder. I hoped that my test target would achieve that, but it fails. It just build the files from the standard target.
How can I correct my mistakes.
Thank you
The makefile I use:
APP=myappname
SRC_DIR=src
INC_DIR=include
OBJ_DIR=obj
BIN_DIR=bin
TEST_SRC_DIR=test
MAIN_CPP_NAME=main.cpp
CC=g++
LD=g++
CFLAGS=-O2 -c -Wall -std=c++17
LFLGAS=
DFLAGS=-g3 -O0 -DDEBUG
INCFLAGS=-I$(INC_DIR)
SOURCES=$(wildcard $(SRC_DIR)/*.cpp)
HEADERS=$(wildcard $(INC_DIR)/*.hpp)
OBJECTS=$(SOURCES:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
DEPENDS=$(OBJ_DIR)/.depends
.PHONY: all
all: $(BIN_DIR)/$(APP)
.PHONY: debug
debug: CFLAGS+=$(DFLAGS)
debug: all
.PHONY: test
test: SOURCES=$(wildcard $(SRC_DIR)/*.cpp)
test: SOURCES=$(filter-out $(SRC_DIR)/$(MAIN_CPP_NAME), $(SOURCES))
test: OBJECTS=$(SOURCES:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
test: TEST_SOURCES=$(wildcard $(TEST_SRC_DIR)/*.cpp)
test: OBJECTS+=$(TEST_SOURCES:$(TEST_SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o)
test: all
$(BIN_DIR)/$(APP): $(OBJECTS) | $(BIN_DIR)
$(LD) $(LFLGAS) -o $# $^
$(OBJ_DIR)/%.o: | $(OBJ_DIR)
$(CC) $(CFLAGS) $(INCFLAGS) -o $# $<
$(DEPENDS): $(SOURCES) | $(OBJ_DIR)
$(CC) $(INCFLAGS) -MM $(SOURCES) | sed -e 's!^!$(OBJ_DIR)/!' >$#
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPENDS)
endif
$(BIN_DIR):
mkdir -p $#
$(OBJ_DIR):
mkdir -p $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR) $(OBJ_DIR)
You're trying to write a sophisticated makefile without understanding the basics, which is almost impossible. Let's try a very simple approach.
First, suppose the source files are
src/main.cpp
src/func.cpp
test/unit.cpp
test/global.cpp
Now we need a list of the object files that test will need.
SOURCES:=$(wildcard $(SRC_DIR)/*.cpp) # this will be src/main.cpp src/func.cpp
NON_MAIN_SOURCES:=$(filter-out $(SRC_DIR)/$(MAIN_CPP_NAME), $(SOURCES)) # this will be src/func.cpp
TEST_DIR_SOURCES:=$(wildcard $(TEST_SRC_DIR)/*.cpp) # this will be test/unit.cpp test/global.cpp
TEST_SOURCES:=$(notdir $(NON_MAIN_SOURCES) $(TEST_DIR_SOURCES)) # this will be func.cpp unit.cpp global.cpp
TEST_OBJECTS:=$(patsubst %.cpp,$(OBJ_DIR)/%.o,$(TEST_SOURCES)) # this will be obj/func.o obj/unit.o obj/global.o
(Note that you must avoid name collisions between src/ and test/, e.g. having a src/func.cpp and also a test/func.cpp. This is a consequence of your directory structure; there's no way for the makefile to work around it.)
Now we must tell Make how to build those object files. We can start with a rule for the sources in src:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CC) $(CFLAGS) $(INCFLAGS) -o $# $<
(I have omitted the $(OBJ_DIR) prerequisite for simplicity. For now, you will be responsible for making sure that obj/ exists.)
Now for the sources in test. A crude but effective approach is to add a rule for them:
$(OBJ_DIR)/%.o: $(TEST_DIR)/%.cpp
$(CC) $(CFLAGS) $(INCFLAGS) -o $# $<
There are more sophisticated ways, but you must master the basics first.
Finally, the rule to build bin/mytestname:
$(BIN_DIR)/mytestname: $(TEST_OBJECTS)
$(LD) $(LFLAGS) -o $# $^
That's enough for now.

Changes in header not resulting in recompile using makefile

Edit
After writing this I noticed some things and went back over the file. I changed the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following:
$(CXX) -MM $(CXXFLAGS) $^ > $#
Since it seemed kind of redundant to first take the generated dependency files, name them into .o files and then turn them back into .d files.
Now the target actually makes, but it will still not remake when the header files are changed.
Original
I have this makefile I created as part of a course, and everything works fine when running make, building for both the host and target. The problem arises when a change occurs in a header file(example: part1.h), this implementation was made specifically to take this into account, and it seemed to work.
A few weeks on now, and I finally realised it doesn't work as intended, as it will not recompile after a change to any of the header files. (part1.h or part2.h).
I took a look into the dependency files generated by the target:
$(BUILD_DIR)/%.d: %.cpp
An example of part1.d has the following contents:
build/host/build/host/part1.o: part1.cpp part1.h
To me, the double directory listing is an error, but so I tried changing the line:
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
To the following, removing the BUILD_DIR variable:
$(CXX) -MT $(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
Doing this solves the double directory listing problem, but gives me a linker error:
build/host/main.o: file not recognized: File format not recognized
I'm trying to find some solution to this, which will make sure that the program is recompiled when changes are made to the header files.
I'm trying to figure out what I'm missing, I've looked at the related literature and everything seems to match up.
SOURCES=main.cpp part1.cpp part2.cpp
OBJECTS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.o))
DEPS=$(addprefix $(BUILD_DIR)/,$(SOURCES:.cpp=.d))
EXE=prog
CXXFLAGS=-I.
#Make sure that default choice for make is the host
ifndef (${ARCH})
ARCH=host
endif
#Making for host
ifeq (${ARCH},host)
CXX=g++
BUILD_DIR=build/host
BIN_DIR=bin/host
endif
# Making for target
ifeq (${ARCH},target)
CXX=arm-devkit-g++
BUILD_DIR=build/target
BIN_DIR=bin/target
endif
$(BIN_DIR)/$(EXE): $(DEPS) $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $(OBJECTS)
#Generate dependency files. Place them in build/host or build/target depending on choice
$(BUILD_DIR)/%.d: %.cpp
$(CXX) -MT $(BUILD_DIR)/$(#:.d=.o) -MM $(CXXFLAGS) $^ > $#
#Generate object files. Place them in build/host or build/target, depending on choice.
$(BUILD_DIR)/%.o: %.cpp
$(CXX) -o $# -c $^
#Create the build dir,
${BUILD_DIR}:
mkdir -p ${BUILD_DIR}
#Create the bin dir
${BIN_DIR}:
mkdir -p ${BIN_DIR}
.PHONY:clean
clean:
rm -f $(BUILD_DIR)/*.o $(BIN_DIR)/$(EXE) $(BUILD_DIR)/*.d
ifneq ($(MAKECMDGOALS),clean)
-include $(DEPS)
endif
If you generate the dependencies as part of the compilation not only do you avoid having to take the extra step, you also rely on the compiler to generate the correct paths. This entails a few other changes to your makefile but I found it simpler to just rewrite it, make has a number of features to simplify some of the other operations.
arch ?= host
build_dir := build/$(arch)
bin_dir := bin/$(arch)
ifeq ($(arch),target)
prefix := arm-devkit-
endif
sources := main.cpp part1.cpp part2.cpp
objects := $(sources:%.cpp=$(build_dir)/%.o)
deps := $(objects:.o=.d)
target := $(bin_dir)/prog
CXX := $(prefix)$(CXX)
CPPFLAGS := -MMD -MP
$(target): CC := $(CXX)
$(target): $(objects) | $(bin_dir)
$(LINK.o) $^ $(LDLIBS) -o $#
$(build_dir)/%.o: %.cpp | $(build_dir)
$(COMPILE.cpp) $(OUTPUT_OPTION) $<
$(build_dir) $(bin_dir): ; mkdir -p $#
.PHONY: clean
clean: ; $(RM) $(target) $(objects) $(deps)
-include $(deps)

Makefile for building C++ Google Protocol Buffers Project

I Just started fooling around using Google Protocol Buffers and I am trying to incorporate the C++ output files from the protocol buffer compiler into my project. I have Been using a simple makefile for my projects so far and it does the trick for building source files all sharing the same extension. I use ".cpp" for my source files but Google Protocol Buffers outputs its source as ".pb.cc" files. I need to be able to compile and link both types of source files into one executable.
I have been searching and fiddling around with my makefile for a few hours now and have had no success.
My Current Makefile:
PROGRAM_NAME=aserv
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g --std=c++14 -O3 -I/usr/local/include/
LDFLAGS=-g -L/usr/local/lib -L/usr/local/lib/boost
LDLIBS= -lrtaudio -pthread -lboost_system -lprotobuf
INSTALL_DIR = /usr/local/bin/
SRCS=$(wildcard *.cpp)
OBJS=$(subst .cpp,.o,$(SRCS))
all: $(PROGRAM_NAME)
$(PROGRAM_NAME): $(OBJS)
$(CXX) $(LDFLAGS) -o $(PROGRAM_NAME) $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
rm -f ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS) $(PROGRAM_NAME) .depend
install:
cp $(PROGRAM_NAME) $(INSTALL_DIR)$(PROGRAM_NAME)
uninstall:
$(RM) $(INSTALL_DIR)$(PROGRAM_NAME)
dist-clean: clean
$(RM) *~ .depend
include .depend
I am not too well versed in writing makefiles yet, so I just don't quite know what to do to make this work.
If it helps i have GNU make 4.1 and gcc 5.3.1 on Ubuntu 16.04 beta
I couldnt get your original Makefile to work so I changed a few things but I think the tricky part with this is the implicit rules that make generates to build your .o files. I think for the .pb.cc files you need to generate .pb.o objects so that the implicit rules can match them.
Try this:
PROGRAM_NAME = aserv
CC = gcc
CXX = g++
RM = rm -f
CXXFLAGS = --std=c++14 -pthread -g -O3 -MMD -MP
CPPFLAGS = -I/usr/local/include/
LDFLAGS = -L/usr/local/lib -L/usr/local/lib/boost
LDLIBS = -lrtaudio -lboost_system -lprotobuf
INSTALL_DIR = /usr/local/bin
SRCS = $(wildcard *.cpp) $(wildcard *.pb.cc)
OBJS = $(subst .pb.cc,.pb.o,$(subst .cpp,.o,$(SRCS)))
DEPS = $(subst .pb.cc,.pb.d,$(subst .cpp,.d,$(SRCS)))
all: $(PROGRAM_NAME)
$(PROGRAM_NAME): $(OBJS)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $# $^ $(LDFLAGS) $(LDLIBS)
-include $(DEPS)
clean:
$(RM) $(OBJS) $(PROGRAM_NAME)
install:
cp $(PROGRAM_NAME) $(INSTALL_DIR)
uninstall:
$(RM) $(INSTALL_DIR)/$(PROGRAM_NAME)
dist-clean: clean
$(RM) *~ $(DEPS)
If you wanto to only strictly rely on Make, and not the surrounding shell you can add another set of SRC and OBJ variables, which will serve as a second set of dependencies.
Add these right below the first set:
SRC1=$(wildcard *.pb.cc)
OBJ1=$(subst .pb.cc,.o,$(SRC1))
And change the .depend and $(PROGRAM_NAME) rule:
.depend: $(SRCS) $(SRC1)
$(PROGRAM_NAME): $(OBJS) $(OBJ1)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
%.o: %.c
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) -c -o $# $<

makefile that makes executable for each file in a folder

Below is a makefile. Please refer to the section where %.c is the target, and one of the dependencies is a .psvn file. I would like this make file to go through every psvn file and generate a .c file for it. How would I change the makefile to do this?
CC = gcc
CXX = g++
OPT = -g -Wall -O3 -Wno-unused-function -Wno-unused-variable -std=c++11
PSVNOPT = --no_state_map --no_abstraction --backwards_moves --history_len=0
psvn2c_core.c:
cp ../psvn2c_core.c ./psvn2c_core.c
psvn2c_state_map.c:
cp ../psvn2c_state_map.c ./psvn2c_state_map.c
psvn2c_abstraction.c:
cp ../psvn2c_abstraction.c ./psvn2c_abstraction.c
%.c: %.psvn psvn2c_core.c psvn2c_state_map.c psvn2c_abstraction.c
../psvn2c $(PSVNOPT) --name=$(*F) < $< > $#
rm -f ./psvn2c_core.c ./psvn2c_state_map.c ./psvn2c_abstraction.c
.PRECIOUS: %.c
%.succ: %.c succ.c
$(CC) $(OPT) succ.c -include $< -o $#
%.run: %.c run.cpp Node.cpp distribution.cpp
$(CXX) $(OPT) run.cpp Node.cpp distribution.cpp -include $< -o $#
.PHONY : clean
clean:
rm -f *.run *.o psvn2c_core.c psvn2c_state_map.c psvn2c_abstraction.c
Add something like this BEFORE the first target (psvn2c_core.c:):
PSVN_FILES := $(wildcard *.psvn)
C_FILES := $(patsubst %.psvn,%.c,$(PSVN_FILES))
all: $(C_FILES)
Done. When make all (or make since all will be the default target since it appears first in the makefile) is invoked, it will try to build all the .c files.