Configure makefile for debug and release targets - makefile

Considering a Makefile similar to the following:
CC = gcc
CXX = g++
CXXFLAGS += -std=c++11
SRCDIR = .
OBJECTS = \
file1.o \
file2.o \
file3.o
THREADS = 1
all: release
release: CXXFLAGS += -DNUM_THREADS=$(THREADS)
release: main
debug: CXXFLAGS += -g -DDEBUG -DVERBOSENESS=3 -DNUM_THREADS=$(THREADS)
debug: main
# Build main executable...
main: $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $# $^
# Compile all object files...
file1.o: $(SRCDIR)/file1.cpp
$(CXX) $(CXXFLAGS) -c $^
file2.o: $(SRCDIR)/file2.cpp
$(CXX) $(CXXFLAGS) -c $^
file3.o: $(SRCDIR)/file3.cpp
$(CXX) $(CXXFLAGS) -c $^
This works properly only for the first make: using other words, object files are not recompiled when I launch make with a different target respect to the previous one.
That said, how could I make the object files recompile if I change between debug or release target?

If you want to force recompilation strictly based on one label, say "Debug" vs. "Release", then you can do it by writing and depending on appropriate timestamp files, like so:
TYPE = Debug
#
# ... conditional settings based on $(TYPE) ...
#
OBJS = prog.o
all: test
prog: $(OBJS)
$(CC) -o $# $(OBJS)
$(OBJS): $(TYPE)-mode-stamp
$(TYPE)-mode-stamp: last-mode-stamp
touch $#
touch -r $# last-mode-stamp
last-mode-stamp:
touch $#
clean:
#rm *-mode-stamp $(OBJS) prog
That supposes you select the build type by setting variable $(TYPE), possibly via the command line. All the object files have $(TYPE)-mode-stamp as a prerequisite, so if that file is out of date then all of them will be rebuilt, along with anything that has any of them as a prerequisite. $(TYPE)-mode-stamp itself has last-mode-stamp as a prerequisite, so the former is updated if it is older than the latter, or if the latter itself is out of date. The recipe for $(TYPE)-mode-stamp sets both files timestamps to the current time, so that
$(TYPE)-mode-stamp is no longer out of date with respect to last-mode-stamp, and
last-mode-stamp is newer than any OtherType-mode-stamp that may be present.
A rule without any prerequisites (but with a recipe) creates last-mode-stamp if it does not initially exist.
Note well that this is altogether different from and orthogonal to monitoring whether any build tools or flags change.

Related

Multiple make targets in the same CMake project

In my project I have a makefile that looks like this:
CXX = clang++
CFLAGS = -std=c++11
COMMON_SOURCES = file1.cpp file2.cpp
TARGET_SOURCES = main.cpp
TEST_SOURCES = run_tests.cpp test_file1.cpp test_file2.cpp
COMMON_OBJECTS = $(COMMON_SOURCES:.c=.o)
TARGET_OBJECTS = $(TARGET_SOURCES:.c=.o)
TEST_OBJECTS = $(TEST_SOURCES:.c=.o)
EXECUTABLE = build/application
TEST_EXECUTABLE = build/tests
.PHONY: all target tests
all: target tests
target: $(EXECUTABLE)
tests: $(TEST_EXECUTABLE)
clean:
rm build/tests & rm build/application &
$(EXECUTABLE): $(COMMON_OBJECTS) $(TARGET_OBJECTS)
$(CXX) $(CFLAGS) $(LDFLAGS) $^ -o $#
$(TEST_EXECUTABLE): $(COMMON_OBJECTS) $(TEST_OBJECTS)
$(CXX) $(CFLAGS) $(LDFLAGS) $^ -o $#
.c.o:
$(CXX) $(CFLAGS) $< -o $#
This lets me run make tests or make target and it will build the appropriate executable.
How do I set up a CMakeLists file to get the same convenient build system?
Except for using clang++, I think if you put the following in a CMakeLists.txt file and then run your cmake configure step in a build directory (i.e., mkdir build; cd build; cmake ..), you should have what you are asking for.
project(myproject)
# I am not sure how you get cmake to use clang++ over g++
# CXX = clang++
add_definitions(-std=c++11)
set(COMMON_SOURCES file1.cpp file2.cpp)
set(TARGET_SOURCES main.cpp)
set(TEST_SOURCES run_tests.cpp test_file1.cpp test_file2.cpp)
add_executable(application ${COMMON_SOURCES} ${TARGET_SOURCES})
add_executable(tests ${COMMON_SOURCES} ${TEST_SOURCES})
Every add_custom_target() (and some other commands, like add_executable) actually adds target in the make sence.
add_custom_target(tests) # Note: without 'ALL'
add_executable(test_executable ...) # Note: without 'ALL'
add_dependencies(tests test_executable)
So, test_executable will be build on make tests, but not in case of simple make.

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.

How to use the include directive in a makefile for a specific target

I want to use the include directive only for a specific target. I do not want to run the other makefiles when the target is not needed because it means the makefiles are generated needlessly.
So is there a way to conditionally use the include directive, which is conditional on a target? Or somehow to make the include directive a prerequisite of a target.
Here's what I have so far:
# Flags
INCDIR = $(CURDIR)/include
CFLAGS = -Wall -Wno-overflow -Wno-uninitialized -pedantic -std=c99 -I$(INCDIR) -O3
LFLAGS = -flat_namespace -dynamiclib -undefined dynamic_lookup
# Directory names
# Set vpath search paths
vpath %.h include
vpath %.c src
vpath %.o build
vpath %.d build
# Get files for the core library
CORE_FILES = $(wildcard src/*.c)
CORE_OBJS = $(patsubst src/%.c, build/%.o, $(CORE_FILES))
CORE_DEPS = $(CORE_OBJS:.o=.d)
# Core library target linking
core : $(CORE_OBJS) | bin
$(CC) $(LFLAGS) -o bin/libcbitcoin.2.0.dylib $(CORE_OBJS)
# Include header prerequisites (How to do only for "core" target?)
include $(CORE_DEPS)
# Makefiles for header dependencies.
$(CORE_DEPS): build/%.d: src/%.c | build
rm -f $#; \
$(CC) -I$(INCDIR) -MM $< -MT '$(#:.d=.o) $#' > $#
# Objects depend on directory
$(CORE_OBS) : | build
# Create build directory
build:
mkdir build
# Create bin directory
bin:
mkdir bin
# Core Compilation
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $#
# Depencies require include/CBDependencies.h as a prerequisite
build/CBOpenSSLCrypto.o: include/CBDependencies.h
# Crypto library target linking
crypto : build/CBOpenSSLCrypto.o -lcrypto -lssl | bin
$(CC) $(LFLAGS) -o bin/libcbitcoin-crypto.2.0.dylib build/CBOpenSSLCrypto.o -lcrypto -lssl
# Crypto library compile
build/CBOpenSSLCrypto.o: dependencies/crypto/CBOpenSSLCrypto.c
$(CC) -c $(CFLAGS) $< -o $#
#Clean
clean:
rm -f $(CORE_OBJS) $(CORE_DEPS) build/CBOpenSSLCrypto.o
As you should be able to tell I do not need to include the ".d" files for "crypto" but I do for "core" (default goal).
Thank you for any help.
Make is not a procedural language, so treating it as one goes against the grain; your makefiles will be difficult to scale, and it can lead to subtle bugs.
There's a better way by Tom Tromey that's clean, efficient and scalable. The trick is to realize that you can build the dependency file in the same step as the object file. The dependencies simply tell Make when the object is due to be rebuilt; you don't need them when you first build the object, because Make knows that the object must be built. And if the dependencies change, that can only be because something in the source or the old dependencies has changed, so again Make knows that the object must be rebuilt. (This is not obvious, so it may take a little cogitation.)
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $#
$(CC) -MM -MF build/$*.d $<
-include build/*.d
There's one more hitch: if you alter the code so as to remove a dependency -- and also remove that file -- you won't be able to rebuild, because the old dependency list will still demand a file which can no longer be found. The sophisticated solution is to process the dependency file so as to make each prerequisite (e.g. header) a target in its own right, with no commands, so that it can be assumed to be rebuilt when needed:
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $#
$(CC) -MM -MF build/$*.d $<
#cp build/$*.d build/$*.P
#sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < build/$*.P >> build/$*.d;
#rm build/$*.P
A cruder method, but almost as foolproof, is to put in catch-all rules for headers and sources:
$(CORE_OBJS): build/%.o: src/%.c
$(CC) -c $(CFLAGS) $< -o $#
$(CC) -MM -MF build/$*.d $<
%.cc %.h:
EDIT:
To break down the new commands:
The -MM option tells gcc to produce a make rule for the object file, instead of preprocessing or compiling. The default is to send the rule to wherever it would send preprocessed output, which will usually be stdout.
The -MF option, used with -MM, specifies the output file. So -MM -MF build/$*.d will put the rule where we want it.
So the following two commands are (almost always) equivalent:
$(CC) -MM -MF build/$*.d $<
$(CC) -MM $< > build/$*.d
(I've left out the -I$(...) and the possibility of using the -MMD option, because both get a little complicated and are not really the point of the question.)
You can use MAKECMDGOALS.
ifeq (core,$(MAKECMDGOALS))
include $(CORE_DEPS)
endif
You could of course, use ifneq (,$(findstring core,$(MAKECMDGOALS))) if there was a possibility of more than one target.
Note: this is a 'quick and dirty' solution -- I agree with Beta that you shouldn't make this a common practice (this could get messy if you did it in a lot of makefiles...).
John
I can't help breaking the guidelines for what is a good answer.
My answer to the original question is in my opinion, no you cannot include rules that are dependant on the target -all rules are processed before targets are considered. This is a limitation of make (I guess). Then again, good point, there is MAKECMDGOALS, but is this not just a hack in the make utility itself?
The answer from Beta is reasonable and orthodox enough, but you can't call it clean even if it is the best that can be done. It won't work if make has not processed the particular target before and the appropriate build/*.d dependency file is not sitting there.

makefile target specific variables as prerequisites

Related: Target-specific Variables as Prerequisites in a Makefile
I'm trying to craft a Makefile which uses a target-specific-variable to specify the output directory for the object files and the final executable. The idea is to maintain two separate binary versions, a 'release' version and a 'debug' version with extra debugging information.
My problem is that 'make' does a clean build every time, even if I haven't changed a thing. I'm pretty sure it's because 'make' is evaluating the prerequisites of the target 'corewars' before the variable declaration in the prerequisites for the 'debug' or 'release' target.
The Makefile is presented below.
CXX=g++
LD=g++
LDFLAGS=
CXXFLAGS=-Iinclude -Wall -Wextra
OBJECTS=main.o Machine.o Core.o ProcessQueue.o Instruction.o
OUTPUT_DIR:=Test/
.PHONY: default
.PHONY: all
.PHONY: release
default: release
all: release
release: OUTPUT_DIR:=Release/
release: corewars
.PHONY: debug
debug: CXXFLAGS+=-DDEBUG -g
debug: OUTPUT_DIR:=Debug/
debug: corewars
corewars: $(OUTPUT_DIR) $(addprefix $(OUTPUT_DIR),$(OBJECTS))
$(LD) -o $(addprefix $(OUTPUT_DIR),corewars) $(addprefix $(OUTPUT_DIR),$(OBJECTS))
Release:
mkdir -p $#
Debug:
mkdir -p $#
%.o: %.cpp include/%.h
$(CXX) -c $(CXXFLAGS) $< -o $(OUTPUT_DIR)$#
.PHONY: clean
clean:
$(RM) -r Release
$(RM) -r Debug
First of all, a non-phony recipe must create a target, $#, not $(OUTPUT_DIR)$#. Also consider converting directory dependencies into order-only prerequisites.
In order to get a proper value of $(OUTPUT_DIR) inside the list of prerequisites, you would have to use secondary expansion, because otherwise, during the primary expansion, the global definition OUTPUT_DIR:=Test/ is used instead of the target-specific one.
Unfortunately, I can't think of a sane way to make it work using target specific variables, without resorting to secondary expansion and vpath magic. Personally I would rather setup the environment first (find out the value of OUTPUT_DIR, etc.) and then re-execute Make with the proper values.
ifndef OUTPUT_DIR
.PHONY: default all release debug
default all: release
release: export OUTPUT_DIR := Release/
debug: export OUTPUT_DIR := Debug/
debug: export EXTRA_CXXFLAGS := -DDEBUG -g
release debug:
#$(MAKE)
else
# ...
CXXFLAGS := -Iinclude -Wall -Wextra $(EXTRA_CXXFLAGS)
PROGRAM := $(OUTPUT_DIR)corewars
OBJECTS := $(addprefix $(OUTPUT_DIR), \
main.o Machine.o Core.o ProcessQueue.o Instruction.o)
# Default target.
$(PROGRAM): $(OBJECTS) | $(OUTPUT_DIR)
$(LD) -o $# $<
$(OUTPUT_DIR)%.o: %.cpp | $(OUTPUT_DIR)
$(CXX) -c $(CXXFLAGS) $< -o $#
$(OUTPUT_DIR):
mkdir -p $#
endif # OUTPUT_DIR
The two parts could them be split into separate makefiles, the root (starter) one, and the one that does the real work, to make the whole thing more manageable.
Target-specific variables are only available within the context of the recipes of the target and its recursive prerequisites. That is, target-specific variables cannot be used as targets nor prerequisites.
One workaround is the makefile there.

Make searches dependencies in the wrong place

I'm relatively new to (GNU) Make, and find it incedibly difficult. I consider switching to SCons, but still, I'd like to understand.
I have a makefile in a folder, that contains subdirectories ./src, ./obj/[release|debug] and ./bin[release|debug]. The makefile should be able to grab the C++ sources in ./src, compile them into object files in the appropriate ./obj directory, and link these object files and put the result in the appropriate ./bin directory. Here is my makefile (edited for simplicity):
CONFIG = release
#CONFIG = debug
OBJS = Container.o
OBJDIR = obj/$(CONFIG)
BINDIR = bin/$(CONFIG)
VPATH = src $(BINDIR)
vpath %.o $(OBJDIR)
.PHONY: release
release: $(OBJS)
$(CXX) $(LXXFLAGS) -o $(BINDIR)/$# $^
Container.o: Container.cpp Container.hpp
$(CXX) -c $(CXXFLAGS) -o $(OBJDIR)/$# $<
The first time I run make, the "release" target will search for "Container.o" in the current folder, as well as in $(OBJDIR). Failing to find it, the secong target will be correctly executed, generating the object file in the correct folder. The "release" target will then execute, but the linker will complain that "Container.o" is not found...
The second time I run make, the "release" target will search for "Container.o" and find it in $(OBJDIR). The linker will then execute correctly (the path where "Container.o" has been found is prepended to the filename).
Is there a way to make it work in a single pass? It drives me crazy!
Make does have a long learning curve, and you're attempting something tricky (and which runs right into one of Make's big weaknesses, poor wildcard handling). I'm not sure that my answer will help more than confuse, but at least it will solve your specific problem.
If you want to use the CONFIG approach, this will do it:
CONFIG = release
#CONFIG = debug
OBJS = Container.o
TRUE_OBJS = $(addprefix obj/$(CONFIG)/, $(OBJS))
vpath %.cpp src
.PHONY: $(CONFIG)
$(CONFIG): bin/$(CONFIG)/$(CONFIG)
bin/$(CONFIG)/$(CONFIG): $(TRUE_OBJS)
$(CXX) $(LXXFLAGS) -o $# $^
$(TRUE_OBJS): obj/$(CONFIG)/%.o : %.cpp
$(CXX) -c $(CXXFLAGS) -o $# $<
But you can do without it (and without the chore of editing the makefile whenever you want to change configurations):
OBJS = Container.o
vpath %.cpp src
.PHONY: release debug
release: bin/release/release
debug: bin/debug/debug
bin/release/release: $(addprefix obj/release/, $(OBJS))
bin/debug/debug: $(addprefix obj/debug/, $(OBJS))
bin/release/release bin/debug/debug:
$(CXX) $(LXXFLAGS) -o $# $^
obj/release/%.o obj/debug/%.o: %.cpp
$(CXX) -c $(CXXFLAGS) -o $# $<

Resources