Is there a way to configure makefile to link extra objects on debug mode? - makefile

I'm trying to write a makefile which supports release mode and debug mode, while in debug mode, I want to link an extra object debug.o to override functions for debugging.
For example:
CFLAGS = -Wall -I$(INCPATH)
INCPATH = include
TARGET = foo
OBJ = foo.o bar.o
# release mode
all: build run clear
# debug mode
debug: CFLAGS += -g -DDEBUG
debug: OBJ += debug.o
debug: build gdb-run clear
# link objects
build: $(OBJ)
gcc $(CFLAGS) -o $(TARGET) $(OBJ)
# compile source code
%.o: %.c $(INCPATH)/*.h
gcc $(CFLAGS) -c $# $<
# default run mode
run:
./$(TARGET)
# debug run mode
gdb-run:
gdb --args $(TARGET)
clear:
rm -f $(OBJ) $(TARGET)
I expected it expand $(OBJ) to foo.o bar.o debug.o when I call make debug, but instead it only expands to foo.o bar.o, because targets are expanded immediately when parsed.
I've tried using .SECONDEXPANSION:, but couldn't work it out.
And I've also tried $(eval OBJ += debug.o), but that resulted in expanding $(OBJ) to foo.o bar.o debug.o even while running make all.
Is this possible, or should I just work around?
edit: fixed a typo, thanks to #matt

I use the GNU make "conditional" mechanism with a make variable named MODE for this. In your case, what about
MODE = RELEASE
OBJ = foo.o bar.o
ifeq ($(MODE),DEBUG)
OBJ += debug.o
endif
[...]
Then build with either
make # a MODE=RELEASE build by default
or
make MODE=DEBUG

I expected it expand $(OBJ) to foo.o bar.o debug.o
It does this inside the recipe, but not in the prerequisite list.
6.11 Target-specific Variable Values
As with automatic variables, these values are only available within the context of a target’s recipe (and in other target-specific assignments).
So you have to stick with conditionals to achieve your goal.
BTW. CFLAGS = -Wall -I(INCPATH) is a typo. %.o: %.c $(INCPATH)/*.h is plainly wrong - use $(wildcard ...) when really needed. Also change all occurences of build to $(TARGET), as it's really foo what you're building. Then revise your makefile - it's probably not a good idea to clean everything after every run.

Related

Makefile with rules compiling with different flags

I'm currently trying to write a Makefile that allows for compilation using debug symbols and without depending on the rule used, while only using a single variable. The "regular" compilation should not have debug symbols, but the "debug" one should. This is what I have currently, but this makes it always use debug symbols (I think the eval statement is evaluated when reading the makefile maybe?)
I also have to keep this number of variables, and prevent make from running itself (for example simply running make inside of debug using an override).
Is there a way to edit a variable inside of a rule that only applies to that specific rule?
# variable declaration
CFLAGS = -Wall -Wextra -Werror
CC ?= gcc
SRC = file1.c file2.c main.c file3.c
OBJ = $(SRC:.c=.o)
EXEC = programm
# Main compiler rule, compiles all obj into final executable.
$(EXEC): $(OBJ)
$(CC) -o $# $(OBJ)
# Runs the regular compiling method with additional debug information (flag "-g")
debug : $(eval CFLAGS += -g) $(EXEC);
# Compiles different files into their .o counterparts
%.o: %.c
$(CC) $(CFLAGS) -o $# -c $<
# removes building .o files
clean:
find . -name '*.o' -delete
# runs clean and remove programm
fclean: clean
rm -rf $(EXEC)
# runs fclean and rebuilds programm
re : fclean $(EXEC)
# runs fclean and rebuilds programm with debug information
redebug : fclean debug

How can I configure my makefile for debug and release builds to more complex projects with multiple executables?

In the post How can I configure my makefile for debug and release builds?, I find the answer https://stackoverflow.com/a/20830354/5922947 perfect!
But it seems work with only one final target.
I've tried unsuccessfully to extend this makefile to my projects where there are several executables as targets.
What changes should I make to this example so that I can have multiple final targets and with
make
or
make all
I can produce all targets (in debug or release modes), or
make test
for a specific target?
EDIT:
One of the attempts I made but which did not produce any results, but serves to better illustrate what is intended:
(...)
OBJS = $(SRCS:.c=.o)
EXE=$($(TARGET)_EXE)
sample1_EXE=sample1
sample2_EXE=sample2
sample1: TARGET=sample1
sample1: debug
sample2: TARGET=sample2
sample2: debug
all: prep debug sample1 sample2
The problem has two parts: specifying the mode, and coordinating the build.
(This will be tricky, so we will take it in stages.)
First the mode. Setting the value of mode in the command, and using debug as the default, is easy. We put this in the makefile:
mode = debug
And a command like make sailfish mode=release will override it.
Now to use the mode:
mode = debug
ifeq ($(mode),debug)
BUILDDIR := debug
CFLAGS += -g -O0 -DDEBUG
else
ifeq ($(mode),release)
BUILDDIR := release
CFLAGS += -O3 -DNDEBUG
else
$(error unknown mode: $(mode))
endif
endif
Note that I added the error statement to catch mistakes like make mode=test and make mode=releas. Such errors are much easier to catch and correct if they cause Make to abort on the spot. (Also note that the leading whitespace is not necessary, it has no effect on execution, but it makes the makefile easier to read.)
Now for the build. Suppose we execute make sailfish, so that the mode is debug. First notice that although we give sailfish as the target, we are not actually building sailfish, we are building debug/sailfish. This is important, so we make sailfish a PHONY target that requires the file we actually want:
.PHONY: sailfish
sailfish: $(BUILDDIR)/sailfish
The relevant objects are sailfish.o and seaThing.o. (You must compose this list yourself, it is almost impossible for Make to deduce it.) We could put the objects in the makefile as a distinct variable:
sailfish_OBJS := sailfish.o seaThing.o
but it will make things simpler later if we make this a target-specific variable:
$(BUILDDIR)/sailfish: $(addprefix $(BUILDDIR)/,sailfish.o seaThing.o)
$(CC) $(CFLAGS) -o $# $^
We still need a rule to build the object files, and we notice that the two pattern rules in the linked answer collapse into one:
$(BUILDDIR)/%.o: %.c
$(CC) -c $(CFLAGS) -o $# $<
This is enough to build debug/sailfish and release/sailfish. To add the executable catamaran, we add:
.PHONY: catamaran
catamaran: $(BUILDDIR)/catamaran
$(BUILDDIR)/catamaran: $(addprefix $(BUILDDIR)/,catamaran.o boatThing.o seaThing.o)
$(CC) $(CFLAGS) -o $# $^
But we notice some redundancy here, so we combine the PHONY declarations:
.PHONY: sailfish catamaran
Then we notice that if we put the names of the executables in a variable:
EXECUTABLES := sailfish catamaran
we can use it in the PHONY declaration:
.PHONY: $(EXECUTABLES)
and we can also combine the two PHONY rules into a static pattern rule:
$(EXECUTABLES): %: $(BUILDDIR)/%
and we can separate the prerequisite lines from the recipes and use one recipe for both:
$(BUILDDIR)/sailfish: $(addprefix $(BUILDDIR)/,sailfish.o seaThing.o)
$(BUILDDIR)/catamaran: $(addprefix $(BUILDDIR)/,catamaran.o boatThing.o seaThing.o)
$(addprefix $(BUILDDIR)/,$(EXECUTABLES)):
$(CC) $(CFLAGS) -o $# $^
Now, to add another executable like seagull, we must only add seagull to the EXECUTABLES := ... line, and write another line:
$(BUILDDIR)/seagull: $(addprefix $(BUILDDIR)/,seagull.o birdThing.o seaThing.o)
A few more refinements are possible, but this should be enough for now.

Compile object files into release and debug folders using Makefile

I want to compile my source code and place object files into release and debug folders using make. Is it possible to do it without duplicating rules?
Here is what I tried:
SRCS = a.c b.c c.c
OBJS = $(patsubst %.c,$(BUILD_TYPE)/%.o,$(SRCS))
TARGET = $(BUILD_TYPE)/main
.PHONY: all
all: release
.PHONY: debug
debug: BUILD_TYPE = debug
debug: CFLAGS = -g
debug: $(TARGET)
.PHONY: release
release: BUILD_TYPE = release
release: CFLAGS = -O3
release: $(TARGET)
$(TARGET): $(OBJS)
$(CC) -o $# $(OBJS)
$(BUILD_TYPE)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
Edit:
I actually did not want to create the different "main" in the same folder. I wanted them in separate folders. My bad. I changed the example above.
Looks like that there is not a clean way to do this. I need to write multiple rules.
You seem to want this makefile to be able to build two different versions of main, and put them in the same place. The trouble is that ordinarily if Make sees a main, it concludes that main need not be rebuilt, but you might want it rebuilt if you want the other version. Unless you want a mechanism to allow Make to remember which version the extant main is, you must suffer the inefficiency of rebuilding it every time.
First we change the object rule:
release/%.o debug/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
Then we make lists of the objects:
debug_OBJS=$(patsubst %.c,debug/%.o,$(SRCS))
release_OBJS=$(patsubst %.c,release/%.o,$(SRCS))
Then the main targets:
.PHONY: debug release
debug: CFLAGS = -g
debug: $(debug_OBJS)
release: CFLAGS = -O3
release: $(release_OBJS)
debug release:
$(CC) -o main $^
Yes, there is still a little bit of redundancy. Yes, it is possible to squeeze it out with some clever coding. But with only two variants, the simple approach is much easier to read and maintain.

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)

Makefile not executing to the end

I have the following makefile but it just executes the 1st command where it builds me the .o files and not the .so files. What am I doing wrong?
Thanks,
SHELL = /bin/sh
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -shared
TARGET = Stepper.so
SOURCES = $(shell echo ./*.c)
HEADERS = $(shell echo ./*.h)
OBJECTS = $(SOURCES:.c=.o)
LIBS = liblua523.a
PREFIX = $(DESTDIR)/usr/local
BINDIR = $(PREFIX)/bin
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
clean:
rm $(OBJECTS)
Unless you specify a different target on the command line, make always builds the first real target found in the makefile. In this case, the first real target is the first object file, so that's all that's built.
This is why you typically see makefiles with a first target of all or similar, which just depends on the various other targets you want built during a standard invocation of "make" with no arguments.
However, your makefile is really not right, in a number of ways. The fact that it's running it all means you actually only have one source file. As soon as you have >1 it will fail.
This:
SOURCES = $(shell echo ./*.c)
is not very efficient; you should use wildcard here:
SOURCES = $(wildcard ./*.c)
This rule:
$(OBJECTS): $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -c $(SOURCES) -o $(OBJECTS)
Tells make, "for every object file, if any source file or any header file has changed, recompile it". Basically, it means that if you change ANYTHING in the directory, EVERYTHING will rebuild. If you want that you might as well write a shell script and not bother with make at all.
Further, the compiler will fail when you have >1 source file, as it will try to run:
gcc -g -Wall -c foo.c bar.c -o foo.o bar.o
which is not right.
You don't need to define this rule at all; make has a built-in rule which knows how to build an object file from a source file. Just replace it with this:
$(OBJECTS): $(HEADERS)
(no recipe) so make knows that the objects depend on the headers as well as the source. Note this is not ideal since all objects rebuild if any header changes but it's fine for a simple program.

Resources