In a Makefile, how do I define wildcard patterns? - makefile

My directory has many files with similar names: test1.cpp, test2.cpp, test3.cpp, etc. I want to compile all test files into executables test1, test2, test3, etc. They don't have to be linked to each other.
CC = clang++
CXX = clang++
INCLUDES =
CFLAGS = -g -Wall $(INCLUDES)
CXXFLAGS = -g -Wall $(INCLUDES)
LDFLAGS = -g
LDLIBS =
.PHONY: default
default: test1 test2
test1:
test2:
Instead of specifying test1, test2, I want to use wildcards or pattern matching or something along those lines. How do I do this?

David Rodgriquez has the right idea: make has built-in rules that will handle this for you. However I would recommend using a makefile rather than setting variables in your environment, so you can easily perform the build as another user etc. where the environment is not set up properly. Also you can use a makefile to create the default target.
This is good enough:
CC = clang++
CXX = clang++
INCLUDES =
CFLAGS = -g -Wall $(INCLUDES)
CXXFLAGS = -g -Wall $(INCLUDES)
LDFLAGS = -g
LDLIBS =
.PHONY: default
default: $(basename $(wildcard test*.cpp))
That's all you need!

Related

CXXFLAGS not being appended in makefile

I have a makefile that I want to be able to produce both a release build and a debug build. When I just run:
make
I want the CXXFLAGS to be:
-std=c++11 -Isrc/includes -c -Os
and when I run
make debug
I want the CXXFLAGS to be
-std=c++11 -Isrc/includes -c -g
I am trying to do this through he use of phony targets and appending the extra flags to the CXXFLAGS variable, however these extra flags are never being appended. why is it that make debug still produces:
g++ -std=c++11 -Isrc/includes -c src/file.cpp -o build/obj/file.o
and not the expected
g++ -std=c++11 -Isrc/includes -c -g src/file.cpp -o build/obj/file.o
when it is run?
contents of makefile:
vpath %.cpp src/macro
vpath %.cpp src/data_types
vpath %.hpp src/includes
vpath %.cpp src
CXX := g++
CXXFLAGS := -std=c++11 -Isrc/includes -c
LXX = g++
LXXFLAGS :=
BUILDDIR := build
OBJDIR := $(BUILDDIR)/obj
SRCS := $(notdir $(shell find -name '*.cpp'))
OBJS := $(patsubst %.cpp, $(OBJDIR)/%.o, $(SRCS))
all: release aval
aval: builddir $(OBJS) $(SRCS)
$(LXX) $(LXXFLAGS) $(OBJS) -o $(BUILDDIR)/aval
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) $^ -o $#
.PHONY: release
release: CXXFLAGS += -Os
release: LXXFLAGS += -s -Os
.PHONY: debug
debug: clean db aval
.PHONY: db
db: CXXFLAGS += -g
.PHONY: builddir
builddir:
#mkdir -p $(OBJDIR)
.PHONY: clean
clean:
#rm -f -r build/obj/*.o
#rm -f build/avalanche
the issue with what you are doing is that you are editing the CXXFLAGS in the dependency list of a rule which won't work because of the way the make file is parsed.
Another way - and really easy, and saves you recursively calling make - which I don't see as particularly evil - but some do. Its certainly less complicated this way I find.
CXXFLAGS = defaults
ifneq (,$(findstring release,$(MAKECMDGOALS)))
CXXFLAGS += release
else ifneq (,$(findstring debug,$(MAKECMDGOALS)))
CXXFLAGS += debug
endif
all:
#echo CXXFLAGS = $(CXXFLAGS)
# Rules for release / debug. The `; #:` part means the body of the rule is empty (do nothing). It just "calls" the dependency rule `all`.
release: all ; #:
debug: all ; #:
So here we are looking at the command goals and "parsing them" to look for your options and add to the flags.
We also need rules for debug and release to call the build rule (which I am calling all for the moment).
Here is the output:
admin#osboxes:~/sandbox/flags$ make
CXXFLAGS = defaults
admin#osboxes:~/sandbox/flags$ make release
CXXFLAGS = defaults release
admin#osboxes:~/sandbox/flags$ make debug
CXXFLAGS = defaults debug
The approach you have chosen does not work, because
db: CXXFLAGS += -g
means that the variable CXXFLAGS is updated to include -g for the goal db, but no other goal. I.e. this change is not global like you intended it to be.
The following would be one way of implementing what you intended:
.PHONY: all release
# NOTE: must be first goal in Makefile to be default goal
all release:
$(MAKE) -f $(lastword $(MAKEFILE_LIST)) BUILD_CXXFLAGS="-Os" BUILD_LXXFLAGS="-s -Os" build
.PHONY: debug
debug:
$(MAKE) -f $(lastword $(MAKEFILE_LIST)) BUILD_CXXFLAGS="-g" BUILD_LXXFLAGS="-g" build
.PHONY: build
build: clean aval
CXX := g++
CXXFLAGS := $(BUILD_CXXFLAGS) -std=c++11 -Isrc/includes -c
LXX = g++
LXXFLAGS := $(BUILD_LXXFLAGS)
# ... and the rest of your original Makefile ...
With build implemented as a dummy echo, I get the following output from the above:
$ make -s
CXX '-Os -std=c++11 -Isrc/includes -c' LXX '-s -Os'
$ make -s all
CXX '-Os -std=c++11 -Isrc/includes -c' LXX '-s -Os'
$ make -s release
CXX '-Os -std=c++11 -Isrc/includes -c' LXX '-s -Os'
$ make -s debug
CXX '-g -std=c++11 -Isrc/includes -c' LXX '-g'
BTW: you also need to add -g to LXXFLAGS, otherwise you won't get a debug binary.

Generate all targets in makefile

I have Makefile:
INC=-I/usr/lib/boost_1_61_0
PYTHON_VERSION = 2.7
PYTHON_INCLUDE = /usr/include/python$(PYTHON_VERSION)
# location of the Boost Python include files and library
MINIREADER_INC = ./../../hdr
BOOST_INC = /usr/lib/boost_1_61_0
BOOST_LIB = /usr/lib/boost_1_61_0/stage/lib
TARGET = LoggerTestModule
$(TARGET).o: $(TARGET).cpp
g++ -I$(PYTHON_INCLUDE) -I$(BOOST_INC) -I$(MINIREADER_INC) -fPIC -c $(TARGET).cpp --std=c++14 -g3
$(TARGET).so: $(TARGET).o
g++ -shared -Wl,--export-dynamic $(TARGET).o ../../Release/src/Logger.o -L$(BOOST_LIB) -lboost_python -L/usr/lib/python$(PYTHON_VERSION)/config -lpython$(PYTHON_VERSION) -o $(TARGET).so --std=c++11 -g3
When running make -f Makefile only object file gets generated, how I can change makefile to generate both "object and library file"?
Thanks
Add a phony target and put it before the others such that it is the default goal:
...
TARGET = LoggerTestModule
.PHONY: all
all: $(TARGET).o $(TARGET).so
$(TARGET).o: $(TARGET).cpp
g++ -I$(PYTHON_INCLUDE) -I$(BOOST_INC) -I$(MINIREADER_INC) -fPIC -c $(TARGET).cpp --std=c++14 -g3
...
Explanations: all is the default goal (first non-special target in Makefile) and depends on $(TARGET).o $(TARGET).so. So, we invoking make without specifying a goal, it is all that will be built and all its pre-requisites will be rebuilt if needed. Declaring it as a pre-requisite of the .PHONY special target tells make to rebuild it, even if, by accident, a file named all exists.
Get rid of the rule for the object file, make already knows how to build it. You should probably also restructure your vars to align them with the built-in rule for linking, which you can then recycle
TARGET := LoggerTestModule
PYTHON_VERSION := 2.7
PYTHON_INCLUDE := /usr/include/python$(PYTHON_VERSION)
MINIREADER_INC := ./../../hdr
BOOST_INC := /usr/lib/boost_1_61_0
BOOST_LIB := /usr/lib/boost_1_61_0/stage/lib
CPPFLAGS := -I$(PYTHON_INCLUDE) -I$(MINIREADER_INC) -I$(BOOST_INC)
CXXFLAGS := -fPIC -std=c++14 -g3
LDFLAGS := -L$(BOOST_LIB) -L/usr/lib/python$(PYTHON_VERSION)/config
LDLIBS := -lboost_python -lpython$(PYTHON_VERSION)
$(TARGET).so: CC := $(CXX)
$(TARGET).so: LDFLAGS += -shared -Wl,--export-dynamic
$(TARGET).so: $(TARGET).o ../../Release/src/Logger.o
$(LINK.o) $^ $(LDLIBS) -o $#

How can I run a pattern rule within another rule in a makefile?

I am looking to write a makefile to automate the compiling of a project that I am working on where the files may, or may not, change in number. I also need to be able to quickly tell make to compile the files as a debug build or a release build (differentiated by a command line define). After some research, I came upon pattern rules and made one. Here is the code I have so far:
# Our folders
# ODIR - The .o file directory
# CDIR - The .cpp file directory
# HDIR - The .hpp file directory
ODIR = obj
CDIR = src
HDIR = inc
# Get our compiler and compiler commands out of the way
# CC - Our compiler
# CFNO - Our compiler flags for when we don't have an output file
# CF - Our compiler flags. This should be appended to any compile and should
# have the name of the output file at the end of it.
# OF - Object flags. This should be appended to any line that is generating
# a .o file.
CC = g++
CFNO = -std=c++11 -wall -Wno-write-strings -Wno-sign-compare -lpaho-mqtt3c -pthread -O2 -I$(HDIR)
CF = $(CFNO) -o
OF = -c
# Our project/output name
NAME = tls_test
# Set out Debug and Release settings, as well as any defines we will use to identify which mode we are in
# NOTE: '-D[NAME OF DEFINE]' is how you create a define through the compile commands
DEBUG = -DDEBUG -g
RELEASE = -DRELEASE
# Our two compile modes
# eval allows us to create variables mid-rule
debug:
$(eval DR = $(DEBUG))
release:
$(eval DR = $(RELEASE))
# Our compiling commands
all:
$(CC) $(CF) $(NAME) $(ODIR)/*.o
# NOTE: $# is the end product being created and $< is the first of the prerequisite
$(ODIR)/%.o: $(CDIR)/%.c
echo "$(CC) $(DR) $(OF) $(CF) $# $<"
The issue that I am having is with the order that I need things to run in. The command line call should tell make to use either debug or release, which sets a make variable, then call all. all should then run the pattern rule at the bottom before running the line currently in the all rule. So, how do I make a pattern rule a dependency and how do I call a rule from another rule?
Use target-specific variables
While not strictly necessary, separating your flags goes a long way in managing build options, you can then use target-specific variable appends to toggle the flags. While you're at it you might as well use the built-in variable names.
I've also added dependency generation (-MMD -MP) because it's always useful.
ODIR := obj
CDIR := src
HDIR := inc
SRCS := $(wildcard $(CDIR)/*.cpp)
OBJS := $(SRCS:$(CDIR)/%.cpp=$(ODIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
CPPFLAGS := -I$(HDIR) -MMD -MP
CXXFLAGS := -std=c++11 -Wall -Wno-write-strings -Wno-sign-compare -pthread -O2
LDFLAGS := -pthread
LDLIBS := -lpaho-mqtt3c
NAME := tls_test
.PHONY: debug release clean
debug: CPPFLAGS+=-DDEBUG
debug: CXXFLAGS+=-g
release: CPPFLAGS+=-DRELEASE
debug release: $(NAME)
$(NAME): $(OBJS)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $#
$(OBJS): $(ODIR)/%.o: $(CDIR)/%.cpp
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) $<
clean: ; $(RM) $(NAME) $(OBJS) $(DEPS)
-include $(DEPS)

CXXFLAGS changes not being honored?

I have the following in my GNU makefile:
# CXXFLAGS ?= -DNDEBUG -g2 -O3
CXXFLAGS ?=
# Add -DNDEBUG if nothing specified
ifeq ($(filter -DDEBUG -DNDEBUG,$(CXXFLAGS)),)
$(info Adding -DNDEBUG to CXXFLAGS)
CXXFLAGS += -DNDEBUG
endif
# Add a symolize if nothing specified
ifeq ($(filter -g -g1 -g2 -g3 -Oz,$(CXXFLAGS)),)
$(info Adding -g2 to CXXFLAGS)
CXXFLAGS += -g2
endif
# Add an optimize if nothing specified
$(info Adding -O3 to CXXFLAGS)
ifeq ($(filter -O -O0 -O1 -O2 -O3 -Og -Os -Oz -Ofast,$(CXXFLAGS)),)
CXXFLAGS += -O3
endif
When I run it:
$ make CXXFLAGS="-g3"
Adding -DNDEBUG to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -g3 -c foo.cpp
...
In fact, if I uncomment the CXXFLAGS ?= -DNDEBUG ..., then I can append again. But that's not very helpful since I'm trying to make arguments optional (but with sane defaults).
And if I type just make, then it works (-fPIC -march=native -Wall -Wextra -pipe is added later by the same makefile, and it has always worked):
$ make
Adding -DNDEBUG to CXXFLAGS
Adding -g2 to CXXFLAGS
Adding -O3 to CXXFLAGS
g++ -DNDEBUG -g2 -O3 -fPIC -march=native -Wall -Wextra -pipe -c serpent.cpp
...
According to the manual and 6.6 Appending More Text to Variables:
Often it is useful to add more text to the value of a variable already defined. You do this with a line containing ‘+=’, like this:
objects += another.o
Why is make not adding the values to the variable? How can I achieve the behavior I want?
By passing a variable via command-line, you're telling make that you are overriding any definitions in the file, which allows a user to compile as they intend rather than as you intend. Ignoring the restriction of user freedom, you can use the override directive:
To append more text to a variable defined on the command line, use:
override variable += more text
Variable assignments marked with the override flag have a higher priority
than all other assignments, except another override. Subsequent
assignments or appends to this variable which are not marked override
will be ignored.
I would discourage you from using override when possible because it's annoying to realize that -O0 was needed to disable the optimizations that you enabled when I don't want them enabled (after all, I specify my own flags for a reason). Of course, if no flags were specified at all, then defaults are perfectly reasonable. In fact, Automake projects seem to default to -g -O2 when no compilation flags are specified.
There are exceptions to this advice of course, such as adding a directory to search for includes/libs or preprocessor definitions for compiling a conditional section of code on a certain platform.

using an ifdef conditional to set a Make flag

I have a simple gnu makefile:
ifdef $(DEBUGGING)
CFLAGS = -g -O0 -Wall
else
CFLAGS = -O3 -Wall
endif
test:
#echo DEBUGGING is $(DEBUGGING)
#echo $(CFLAGS)
When I invoke it like this, I see that DEBUGGING is set to true, but ifdef $DEBUGGING appears to be false:
$ DEBUGGING=true make test
DEBUGGING is true
-O3 -Wall
I would expect that CFLAGS would be set to "-g -O0 -Wall". What am I missing?
You use the NAME of the variable in the ifdef:
ifdef DEBUGGING
The value given to ifdef is expanded first, and the result is considered a variable name.

Resources