How can I run a pattern rule within another rule in a makefile? - 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)

Related

Makefile with multiple programs with debug and release modes?

I've written simple calculator in C++, and decided to separate lexer+parser and actual "frontends" which can be GUI or command-line. Project structure looks like that:
src/
parser.hpp
parser.cpp
scanner.hpp
scanner.cpp
exceptions.hpp
term-calc.cpp
gui-calc.cpp
Makefile
Obviously parser and scanner should be compiled into object files separately, and term-calc and gui-calc separately. Furthermore I want to have debug builds and release builds,
so I imagine final project structure like that:
src/
...
obj/
debug/
parser.o
scanner.o
...
release/
parser.o
scanner.o
...
out/
debug/
term-calc
gui-calc
release/
term-calc
gui-calc
Makefile
I'm pretty new to Makefiles but this is what I came up with so far (I've ommited automatic dependency generation for now):
CXX := g++
CXXFLAGS := -std=c++17 -pedantic -Wall -Wextra -fno-rtti
SRCDIR := $(CURDIR)/src # sources
OBJDIR := $(CURDIR)/obj # objects
INCDIR := $(CURDIR)/inc # generated dependencies
OUTDIR := $(CURDIR)/out # executables
# target programs
TERM_CALC := term-calc
GUI_CALC := gui-calc
all: debug
# debug flags
debug: CXXFLAGS += -O0 -g -fsanitize=address
# debug objects and executables go into /debug subdirectory
debug: OBJDIR += /debug
debug: OUTDIR += /debug
# release flags
release: CXXFLAGS += -Os -ffunction-sections -fdata-sections -flto -fno-ident
release: LDFLAGS += -Wl,-gc-sections -s -flto
# release objects and executables go into /release subdirectory
release: OBJDIR += /release
release: OUTDIR += /release
# common objects
OBJECTS := $(OBJDIR)/scanner.o $(OBJDIR)/parser.o
# target-specific objects
$(TERM_CALC): OBJECTS += $(OBJDIR)/term-calc.o
$(GUI_CALC): OBJECTS += $(OBJDIR)/gui-calc.o
# TARGET_NAME is name of program to build
# ensure it is valid, if defined
ifdef TARGET_NAME
ifneq ($(TARGET_NAME),$(TERM_CALC))
ifneq ($(TARGET_NAME),$(GUI_CALC))
$(error Invalid target name '$(TARGET_NANE)')
endif
endif
endif
ifdef TARGET_NAME
# how to build target program
$(TARGET_NAME): $(OUTDIR)/$(TARGET_NAME)
$(OUTDIR)/$(TARGET_NAME): $(OBJECTS)
#mkdir -p $(OUTDIR)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) $^ -o $#
endif
# how to build objects
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
#mkdir -p $(OBJDIR)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $#
# if TARGET_NAME is not specified, just compile objects
TARGET_NAME ?= $(OBJECTS)
debug : $(TARGET_NAME)
release : $(TARGET_NAME)
# clean everything
clean:
$(RM) -r $(OBJDIR) $(OUTDIR) $(INCDIR)
.PHONY = all debug release clean
Unfortunately it absolutely does not work, while writing this makefile, I was getting many errors but even after fixing all of them as I thought, I still get:
Makefile:52: *** mixed implicit and normal rules: deprecated syntax
make: *** No rule to make target '/%.cpp', needed by '/root/cpp/calc/obj'. Stop.

Using GNU Make to compile non-existent object files

I've been learning C++ for a few months now by just using an editor and my terminal to compile and run my programs. But I saw a need to be a bit more formal with my projects, so I'm trying to learn how to build a proper project file structure and also how to use Make.
Currently, I am using GNU Make 4.1. But I am having trouble to creating object files with Make, receiving the error:
make: *** No rule to make target 'build/%.o', needed by 'main'. Stop.
I've been looking all over for a solution, but none have worked so far.
Here is my makefile:
# Specify compiler
CC=gcc
# Specify linker
LINK=gcc
# Specify flags
CPPFLAGS = -Wall -g
# Specify directories
SRCDIR = ./src
OBJDIR = ./build
# Compile object files
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -c -o $# $< $(CPPFLAGS)
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Consider the final rule...
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Unfortunately $(OBJDIR)/%.o isn't expanded in the way in which you require. Assuming all of your source files are in $(SRCDIR) you can create a variable containing their names...
SRCFILES := $(wildcard $(SRCDIR)/*.cpp)
Now create a variable containing the corresponding object file paths...
OBJFILES := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCFILES))
Now $(OBJFILES) should contain the list of object file paths on which main is dependent. So the final rule becomes...
main: $(OBJFILES)
$(CC) -o $# $^

Generate debug versions of targets in a DRY method

I am using GNUmake and I have a makefile with some targets defined and their respective dependencies. I would like to create a debug version of these targets, so I have this:
TARGET := a b c
all: $(TARGET)
a: a.o e.o
$(CC) $(CFLAGS) $(INCDIRS) -c $(^) -o $(#)
b: b.o g.o
$(CC) $(CFLAGS) $(INCDIRS) -c $(^) -o $(#) -pthread
c: f.o c.o
$(CC) $(CFLAGS) $(INCDIRS) -lm -c $(^) -o $(#)
%.o: %.c
$(CC) $(CFLAGS) $(INCDIRS) -c $(^) -o $(#)
So this is all good, but now I would like to create debug versions of these rules, but I don't want to have to rewrite the rules. I just want to add additional flags like -g -DDEBUG to the CFLAGS variable and change the names of the targets.
I tried this static rule stuff
$(TARGET:%=debug_%): %: * #<--- not sure how to specify the dependencies
# CFLAGS += -g -DDEBUG <-- uncommenting this line is an error
This didn't work. I wanted the above rule to match the targets I already specified, but add additional parameters to CFLAGS which will then generate files like debug_a, debug_b, debug_c etc. I am not sure if this is possible with make but that was just the way I was reasoning about this.
Any help will be appreciated, thanks
So I finally found a suitable solution:
DEBUG_TARGET := $(TARGET:%=debug_%)
debug: $(DEBUG_TARGET)
$(DEBUG_TARGET):
debug_%: CFLAGS += -g -DDEBUG
debug_%: %
#mv $* debug_$*
This will generate a debug version of each target without having to create separate rules.
The last line was the sweet spot for me and this accomplishes what I wanted without having to repeat myself too much

No targets . Stop

This is my direcctoriy
Image
What i dont know is why I get the message
no targets.stop
CFLAGS := -g -std=c++11# -Wall
LIB := -L lib -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt
# ALL SERVER %.o
/build/server/%.o: /src/server.cpp /lib/server/%.cpp
g++ $(CFLAGS) /src/server.cpp /lib/server/%.cpp -o -c $# $^
You should define the "all" target with object files as dependencies, in order to run the command "make" or "make all".
There are also some mistakes in makefile syntax and on paths. Here are suggestion of solution:
SRCS := ./src/server.cpp ./lib/server/server.cpp # input source files
OBJS := ./build/server/user.o ./build/server/server.o # output object files
# ALL TARGET
all: $(OBJS)
$(OBJS): $(SRCS)
g++ ... # to complete to generate object files from source files

Makefile that rebuilds all if compiled with dif flags

So I am having a little bit of a tough time trying to figure out how to make my Makefile so that when I do make and it compiles a release version then later on do a make debug it compiles a debug version with the new -DDEBUG and -g set on gcc if the files have not been updated.
For example:
main.cpp is edited
run make
compiles main.cpp
run make debug
main.cpp is not recompiled because there were no changes even though the flags for compilation differ
Note I don't want to have to do a clean each time either because I dont want to have to recompile files if I do 2 makes in a row so setting clean as a dependency is not going to be a valid answer here
You may like to compile object files into a different directory depending on the build mode, e.g.:
# default mode, override with `make BUILD=release`
BUILD := debug
obj_dir := ${BUILD}
CFLAGS.debug := -g -O0
CFLAGS.release := -g -O3 -march=native -DNDEBUG
all : ${obj_dir}/test
# Example executable
${obj_dir}/test : ${obj_dir}/test.o
test.c :
echo "int main() { return 0; }" > $#
# Generic rules
${obj_dir} :
mkdir $#
${obj_dir}/%.o : %.c Makefile | ${obj_dir} # Also recompile when Makefile changes.
${CC} -c -o $# ${CPPFLAGS} ${CFLAGS} ${CFLAGS.${BUILD}} -MD -MP $<
${obj_dir}/% : Makefile | ${obj_dir} # Also re-link when Makefile changes.
${CC} -o $# ${LDFLAGS} $(filter-out Makefile,$^) ${LDLIBS}
clean :
rm -rf ${obj_dir}
-include $(wildcard ${obj_dir}/*.d)
${obj_dir}/*.d : ;
.PHONY: all clean
(Bonus feature: automatic dependency generation).
Usage:
[max#localhost:~/tmp] $ make
mkdir debug
echo "int main() { return 0; }" > test.c
cc -c -o debug/test.o -g -O0 -MD -MP test.c
cc -o debug/test debug/test.o
[max#localhost:~/tmp] $ make
make: Nothing to be done for 'all'.
[max#localhost:~/tmp] $ make BUILD=release
mkdir release
cc -c -o release/test.o -g -O3 -march=native -DNDEBUG -MD -MP test.c
cc -o release/test release/test.o
[max#localhost:~/tmp] $ make BUILD=release
make: Nothing to be done for 'all'.
First of all, you should not run make debug - that would mean, you want to build a different target (debug). But you don't, you want to build the same target, just with different options. That's what you do, you run a different option, a variable value
>make DEBUG=Y
When you run
>make
you also pass that variable really, just with the empty string as value.
Now, in order for this to work as you want in the Makefile, you would want to make it as if DEBUG was a prerequisite file, with recipes like this:
foobar.o: foobar.c DEBUG
gcc $(if $(DEBUG), -DDEBUG -g) -c $< -o $#
Of course, normally this won't work, because DEBUG is a variable, not a file. So you need a hack, that I call "dependable variables". It is basically a way to declare a variable to behave like a file. I describe this technique in one of my other answers:
How do I add a debug option to Makefile
I once did something like this, it looked like that (boiled down to the minimum):
EXE := a.out
SRC := $(wildcard *.c)
ifneq ($(MAKECMDGOALS),debug)
OBJ := $(SRC:.c=.o)
else
OBJ := $(SRC:.c=-d.o)
endif
.PHONY: all debug
all: $(EXE)
debug: CFLAGS += -g -DDEBUG
debug: $(EXE)
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
%.o %-d.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
The trick is to use two separate list of object files, and select one depending of the target.

Resources