I have C++ project that I build using a Makefile with two targets as so
debug: FLAGS += -g3 -DDEBUG -DSOCKET_LOG_COMMUNICATION
#printf ""
test: some_other_target
$(COMPILER) ...
I wanted to call make as so
make debug test
to define a macro and also build the test target. Is this possible?
Target-specific variables apply only to the named target and its dependencies (unless the variable is declared private), so the only way you would be able to have test inherit debug's variables would be debug: test which probably isn't what you're looking for.
One way to do this is use conditional statements:
ifdef debug
FLAGS += -g3 -DDEBUG -DSOCKET_LOG_COMMUNICATION
$(info whatever)
endif
test: some_other_target
$(COMPILER) ...
and invoke make test debug=1.
Related
What I'm interested in doing is checking the value of a variable that's been overridden on the command-line has one of several valid values. Specifically, I have part of my makefile that looks like so:
ifndef BUILD
BUILD ::= release
endif
# Set flags for $(CC), based on the value of $(BUILD)
CFLAGS ::= -Wall -pthread -std=c17 -I./src/include
CFLAGS.debug ::= -g
CFLAGS.release ::= -O3
CFLAGS ::= $(CFLAGS.$(BUILD)) $(CFLAGS)
My goal is to be able to run something like make BUILD=debug without having to write a seperate debug target and adding a bunch of mess to my recipies.
What I want is a way to do something like $(warn Invalid BUILD option) if something like make BUILD=production is specified. Is there a better/more idiomatic way of doing this than just nesting a bunch of ifneq?
Well, something like this will work:
BUILD ?= release
OK_BUILDS := debug release
$(if $(filter $(BUILD),$(OK_BUILDS)),,$(warn Invalid BUILD option: $(BUILD))
I have a makefile with the following lines:
debug: CFLAGS += $(DEBUGFLAGS)
debug: clean all
What I want to do is run 'clean' and 'all' with the Target Specific Variable values. This works fine and as expected.
But if I ran this with parallel execution 'clean' might destroy the files being create by 'all'.
So if I do something like the following:
debug: CFLAGS += $(DEBUGFLAGS)
debug:
$(MAKE) clean
$(MAKE) all
This will ensure that the order of the rules is respected. But the Target Specific Variables will not be taken into the new invocations of make.
So I was wondering how I can use both Target Specific Variables and parallel execution.
Why not just pass through the values as well?
debug: CFLAGS += $(DEBUGFLAGS)
debug:
$(MAKE) clean CFLAGS='$(CFLAGS)'
$(MAKE) all CFLAGS='$(CFLAGS)'
Not sure which version of make introduced it (3.8? 4.0?), but if you add 'clean' to the pseudo-target .NOTPARALLEL, then clean is not run in parallel, and other targets are. I use make -j clean all and this seems to work as expected.
e.g.
...<variables defined here>...
all: $(TARGETS)
clean:; rm -rf $(TARGETS) ...
...<rules defined here>...
.PHONY: all clean
.NOTPARALLEL: clean
I have some ancillary targets in a makefile that I want to restrict for internal or "private" use (only) inside the makefile. That is, I want to be able to specify these targets as dependencies from within the makefile, but I want to prevent the target from being specified as a build goal from the command line. Somewhat analogous to a private function from OOP: the target is harmful (or simply doesn't make sense) to build separately.
I wish there were a special-target .HIDDEN or .PRIVATE or something that did this, akin to what .PHONY does for non-file targets, but I don't think this exists. The private keyword is only for variables.
What is a good/general/elegant way to protect a target for internal/private use only?
The best workaround that I could come up with is to check $(MAKECMDGOALS) for "unacceptable" targets, then error-out if specified; this seems inelegant. I'm sure the makefile could be rewritten to avoid this situation -- perhaps a superior solution -- but that's not practical here.
Below the cut-line... here's a contrived example for illustration.
Though I'm looking for a general solution, one example of targets that are harmful as individual/primary goal is with inheriting of target-specific variable values:
override CFLAGS += -Wall
all : debug
%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
debug : CFLAGS += -g3 -O0
release : CFLAGS += -O3
debug : CPPFLAGS += -DDEBUG
release : CPPFLAGS += -DRELEASE
debug release : foo.o bar.o main.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
clean:
-rm -f *.o debug release
.PHONY: all clean
Implicit rule duplicated (unnecessary) for illustration. With the goal of debug or release, foo.o and others will inherit respective CFLAGS and CPPFLAGS -- If one does make clean debug all objects will be consistent. But for example if someone builds foo.o separately, it will fail to inherit the appropriate flags; e.g., make clean foo.o debug you'll get foo.o built with default CFLAGS; then it doesn't need to be updated when building debug, so it will be linked with other objects with different optimizations or different macro settings. It will probably work in this case, but it's not what was intended. Marking foo.o, etc. as illegal goals would prevent this.
EDIT:
It's very clear that my example (above) was not a good choice for my more-general question: hiding targets was not the best way to fix an issue with my example. Here's a modified example that illustrates the modified question "How to enforce target-specific values?" -- it builds on commentary from #Michael, #Beta, #Ross below, and allows posing and answering this more limited scenario.
As described in previous responses below, it's a much better idea in this case to create objects that have different build flags in separate locations. e.g.,
bin_debug/%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
bin_release/%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
OBJS = foo.o bar.o main.o # or $(SRCS:.o=.c)
DEBUG_OBJS = $(addprefix bin_debug/,$OBJS)
RELEASE_OBJS = $(addprefix bin_release/,$OBJS)
debug : $(DEBUG_OBJS)
release : $(RELEASE_OBJS)
debug release :
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
Pattern rule duplicated because I think it has to be (multiple "pattern targets" (%) convince make all targets are built at once with one recipe; see SO questions this and this).
So now, add in target-specific flags:
debug : CPPFLAGS += -DDEBUG
release : CPPFLAGS += -DRELEASE
But this still suffers:
make bin_debug/foo.o
will not get the CPPFLAGS from debug. I've accepted #Michael's answer below as it got me thinking about the problem in a more helpful way, but also answered some of my own rhetorical questions below.
You kind of can define private targets by starting their name with two hyphens.
--private-target:
#echo private
public-target: --private-target
#echo public
You can call make public-target but make --private-target will complain about an unknown option:
$ make public-target
private
public
$ make --private-target
/Library/Developer/CommandLineTools/usr/bin/make: unrecognized option `--private-target'
This is not a feature of make, but takes advantage of the fact that command line options are passed with two hyphens and as a result make will complain about an unknown option. This also can be easily bypassed by signaling the end of options:
$ make -- --private-target
private
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
This program built for i386-apple-darwin11.3.0
The problem you are trying to solve is legitimate but you are heading on the worse possible path to solve it.
Declaring private targets does not make any sense
When we write a Makefile, we are describing a compilation job in terms of targets, sources and recipes. The advancement of this job is described by the set of targets which are already built. Now you are accurately observing that the sequence
make clean
make foo.o
make debug
will produce objects whose format is inconsistent with foo.o thus leaving your build directory in an inconsistent state. But it is very wrong to deduce that the user should not be able to construct foo.o explicitly. Consider the following sequence:
make clean
# Wait for foo.o being compiles and
# interrupt the build job with a signal
make debug
Since make sees that foo.o it will resume its task where it was at and left foo.o untouched while compiling subsequent units with different flags, leaving the build directory the same inconsistent state as in the first scenario.
Hence, if we could implement private targets in Makefiles, this would be ineffective and could convey a false sense of security, which is even worse than insecurity by itself. Also the solution you imagined annihilates one of the most important advantages of using Makefiles over shell scripts: Make makes it easy to continue an interrupted task where it was at.
I documented some other aspects of using Makefiles in relation to the set of targets already built in my answer to the question “What is the purpose of linking object files separately in a Makefile?”.
Another solution to your problem
To address the issue of compilation flags inconsistency, we can arrange to store built targets into a special directory, depending on the compilation flags used. Implementing this would fix the issue without forcing us to resign upon the ease of resuming an interrupted compilation job.
Here is an implementation roadmap:
Identify build profiles, here you have release and build.
Choose which compilation to use for each build profile.
Choose in which directory to store built targets for each build profile.
Write your Makefile so that built targets are stored in the directories you choosed. Please refer Gnu make - how to get object files in separate subdirectory.
Note. In my opinion, the BSD variant of make has a much nicer support for writing targets in a special directory, see my answer to the question “How to write a Makefile using different directories for targets and sources”. Generally I prefer the BSD variant of make because its documentation is short and to the point and it enjoys a lot of useful advanced examples, since operating system build and ports build in the BSD world are orchestrated by this program.
One solution to the problem is to migrate the CPPFLAGS to the pattern rules (e.g., bin_debug/%.o: CPPFLAGS...) instead of the regular rule (debug: CPPFLAGS...), final result:
bin_debug/%.o : CPPFLAGS += -DDEBUG
bin_debug/%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
bin_release/%.o : CPPFLAGS += -DRELEASE
bin_release/%.o : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
OBJS = foo.o bar.o main.o # or $(SRCS:.o=.c)
DEBUG_OBJS = $(addprefix bin_debug/,$OBJS)
RELEASE_OBJS = $(addprefix bin_release/,$OBJS)
debug : $(DEBUG_OBJS)
release : $(RELEASE_OBJS)
debug release :
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
so make bin_debug/foo.o will get CPPFLAGS including -DDEBUG.
Now, lets say you have >>2 rules: debug, release, config01, config02, config03, ... each with their own CPPFLAGS.
One way might be to continue reduplicating all of the pattern rules, but that gets annoying if anything has to change. Furthermore it's not really possible to use in a foreach. This seems handy:
debug : CPPFLAGS+=-DDEBUG
release : CPPFLAGS+=-DRELEASE
config01 : CPPFLAGS+=-DSOMETHING
config02 : CPPFLAGS+=-DSOMETHINGELSE
TARGETS = debug release config01 config02
OBJS = foo.o bar.o main.o # or $(SRCS:.o=.c)
define TARGET_template
bin_$(1)/%.o : %.c
$$(CC) $$(CFLAGS) $$(CPPFLAGS) -c -o $# $<
$(1): $(addprefix bin_$(1)/,$(OBJS))
# other TARGET-specific stuff here
endef
$(foreach tgt,$(TARGETS),$(eval $(call TARGET_template,$(tgt))))
But still doesn't fix the situation of make bin_debug/foo.o -- still doesn't get CPPFLAGS.
So, instead of making target-specific variable-value like debug: CPPFLAGS+=... you could have a variable that is specific to the target, like CPPFLAGS_debug, then add to each rule:
CPPFLAGS_debug = -DDEBUG
CPPFLAGS_release = -DRELEASE
CPPFLAGS_config01 = -DSOMETHING
CPPFLAGS_config02 = -DSOMETHINGELSE
TARGETS = debug release config01 config02
OBJS = foo.o bar.o main.o # or $(SRCS:.o=.c)
define TARGET_template
bin_$(1)/%.o : CPPFLAGS+=$$(CPPFLAGS_$(1))
bin_$(1)/%.o : %.c
$$(CC) $$(CFLAGS) $$(CPPFLAGS) -c -o $$# $$<
$(1): $(addprefix bin_$(1)/,$(OBJS))
# other TARGET-specific stuff here
endef
$(foreach tgt,$(TARGETS),$(eval $(call TARGET_template,$(tgt))))
Beware; above may need more $$(...)s, untested.
Problems? Better way?
Thinking about this and tried the following:
TEST := $(shell echo $$RANDOM)
test : $(TEST)
$(TEST):
<tab>#echo tada $(TEST)
then doing a make test on command line seems to work and I think it would be difficult to get the result without using the test target. Maybe this path can help?
I don't think there's any "elegant" way to have targets somehow made private. I think the only solution that could be called elegant would be to rewrite your makefile so that it doesn't matter what target users invoke, as Beta suggests. It would also have the advantage of making your makefile more maintainable and easier to understand.
A not so elegant but fairly simple way to make targets "private" would be to rename the makefile to something other than one of the default names. Then put a new makefile in it's place that invokes the "private" makefile to do it's work. Something like:
.SUFFIXES:
PUBLIC_TARGETS = all debug release clean
REAL_MAKEFILE = private.mak
define invoke_make
$(1): $(REAL_MAKEFILE)
$(MAKE) -f $(REAL_MAKEFILE) $(1)
endef
$(foreach target, $(PUBLIC_TARGETS), $(eval $(call invoke_make,$(target))))
.PHONY: $(PUBLIC_TARGETS)
Obviously this doesn't prevent a determined user from invoking "private" targets, but hopefully it makes it clear that they shouldn't be doing this. That's all making things private in object-oriented languages does anyways. It's always possible for a sufficiently determined user to bypass it.
Even if previous speakers called this a bad idea, I was very interested in the concept of having a custom special target like .PRIVATE to more or less protect some targets from beeing called straigt.
And for everyone interested in it... this is what I came up with:
ifeq ($(strip $(filter .PRIVATE,$(MAKECMDGOALS))),)
__PRIVATEGOALS = $(shell make -f $(firstword $(MAKEFILE_LIST)) -n .PRIVATE | tail -n 1)
$(foreach __privgoal,$(__PRIVATEGOALS),$(eval __PRIVATECMDGOALS += $(filter $(__privgoal),$(MAKECMDGOALS))))
endif
ifneq ($(strip $(__PRIVATECMDGOALS)),)
$(error tried to call *private* goal(s) $(strip $(__PRIVATECMDGOALS)))
endif
.PHONY: .PRIVATE
.SILENT: .PRIVATE
.PRIVATE:
##
$^
Put it at the top of your makefile, or at least in front of the first target declared as private. You could as well put it into a separate file, like private.mk and include it in your main makefile.
You should be able to use the .PRIVATE target in the same way as you use the .SILENT or the .PHONY targets. An error is triggered in case a "private" target is called and make stops.
I was wondering if there was any sample code for Makefiles (make) and CMakeLists.txt (cmake) that both do the same thing (the only difference being that one is written in make and the other in cmake).
I tried looking for 'cmake vs make', but I never found any code comparisons. It would be really helpful to understand the differences, even if just for a simple case.
The following Makefile builds an executable named prog from the sources
prog1.c, prog2.c, prog3.c and main.c. prog is linked against libmystatlib.a
and libmydynlib.so which are both also built from source. Additionally, prog uses
the library libstuff.a in stuff/lib and its header in stuff/include. The
Makefile by default builds a release target, but offers also a debug target:
#Makefile
CC = gcc
CPP = g++
RANLIB = ar rcs
RELEASE = -c -O3
DEBUG = -c -g -D_DEBUG
INCDIR = -I./stuff/include
LIBDIR = -L./stuff/lib -L.
LIBS = -lstuff -lmystatlib -lmydynlib
CFLAGS = $(RELEASE)
PROGOBJS = prog1.o prog2.o prog3.o
prog: main.o $(PROGOBJS) mystatlib mydynlib
$(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog
debug: CFLAGS=$(DEBUG)
debug: prog
mystatlib: mystatlib.o
$(RANLIB) libmystatlib.a mystatlib.o
mydynlib: mydynlib.o
$(CPP) -shared mydynlib.o -o libmydynlib.so
%.o: %.c
$(CC) $(CFLAGS) $(INCDIR) $< -o $#
%.o: %.cpp
$(CPP) $(CFLAGS) $(INCDIR) -fPIC $< -o $#
Here is a CMakeLists.txtthat does (almost) exactly the same, with some comments to underline the
similarities to the Makefile:
#CMakeLists.txt
cmake_minimum_required(VERSION 2.8) # stuff not directly
project(example) # related to building
include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for compiler
link_directories(${CMAKE_SOURCE_DIR}/stuff/lib) # -L flags for linker
set(PROGSRC prog1.c prog2.c prog3.c) # define variable
add_executable(prog main.c ${PROGSRC}) # define executable target prog, specify sources
target_link_libraries(prog mystatlib mydynlib stuff) # -l flags for linking prog target
add_library(mystatlib STATIC mystatlib.c) # define static library target mystatlib, specify sources
add_library(mydynlib SHARED mydynlib.cpp) # define shared library target mydynlib, specify sources
#extra flags for linking mydynlib
set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
#alternatively:
#set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")
In this simple example, the most important differences are:
CMake recognizes which compilers to use for which kind of source. Also, it
invokes the right sequence of commands for each type of target. Therefore, there
is no explicit specification of commands like $(CC) ..., $(RANLIB) ... and so on.
All usual compiler/linker flags dealing with inclusion of header files, libraries, etc.
are replaced by platform independent / build system independent commands.
Debugging flags are included by either setting the variable CMAKE_BUILD_TYPE to "Debug",
or by passing it to CMake when invoking the program: cmake -DCMAKE_BUILD_TYPE:STRING=Debug.
CMake offers also the platform independent inclusion of the '-fPIC' flag (via
the POSITION_INDEPENDENT_CODE property) and many others. Still, more obscure settings can be implemented by hand in CMake just as well as in a Makefile (by using COMPILE_FLAGS
and similar properties). Of course CMake really starts to shine when third party
libraries (like OpenGL) are included in a portable manner.
The build process has one step if you use a Makefile, namely typing make at the command line. For CMake, there are two steps: First, you need to setup your build environment (either by typing cmake <source_dir> in your build directory or by running some GUI client). This creates a Makefile or something equivalent, depending on the build system of your choice (e.g. make on Unixes or VC++ or MinGW + Msys on Windows). The build system can be passed to CMake as a parameter; however, CMake makes reasonable default choices depending on your system configuration. Second, you perform the actual build in the selected build system.
Sources and build instructions are available at https://github.com/rhoelzel/make_cmake.
Grab some software that uses CMake as its buildsystem (there's plenty of opensource projects to choose from as an example). Get the source code and configure it using CMake. Read resulting makefiles and enjoy.
One thing to keep in mind that those tools don't map one-to-one. The most obvious difference is that CMake scans for dependencies between different files (e.g. C header and source files), whereas make leaves that to the makefile authors.
If this question is about a sample Makefile output of the CMakeList.txt file then please check the cmake-backend sources and generate one such Makefile. If it is not then adding to the reply of #Roberto I am trying to make it simple by hiding the details.
CMake function
While Make is flexible tool for rules and recipe, CMake is a layer of abstraction that also adds the configuration feature.
My plain CMakeLists.txt will look like the following,
cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})
Note, that CMake hides how the build can be done. We only specified what is the input and output.
The CMakeLists.txt contains list of function-calls that are defined by cmake.
(CMake function) Vs Make rules
In Makefile the rules and recipes are used instead of functions . In addition to function-like feature, rules and recipes provide chaining. My minimalistic Makefile will look like the following,
-include "executable.mk"
TARGETS=testapp.bin
all:${TARGETS}
While the executable.mk will look like the following,
SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)
%.bin:$(OBJECTS)
$(CC) $(CFLAGS) -o $# $^ $(LFLAGS) $(LIBS)
.PHONY: all clean
clean:
$(RM) $(OBJECTS) $(DEPS) $(TARGETS)
-include $(DEPS)
Starting from the scratch I shall start with a Makefile like the following,
all: testapp.bin
testapp.bin:sourcea.o sourcb.o
$(CC) $(CFLAGS) -o $# $^ $(LFLAGS) $(LIBS)
.PHONY: all clean
clean:
$(RM) $(OBJECTS) testapp.bin
I got this snippet from here and modified it. Note that some implicit-rules are added to this file which can be found in the makefile-documentation. Some implicit variables are also relevant here.
Note, that Makefile provides the detail recipe showing how the build can be done. It is possible to write executable.mk to keep the details defined in one file. In that way the makefile can be reduced as I showed earlier.
Internal Variables in CMake and Make
Now getting little advanced, in CMake we can set a compiler flag like the following,
set(CMAKE_C_FLAGS "-Wall")
Please find out more about CMake default variables in CMakeCache.txt file.
The CMake code above will be equivalent to Make code below,
CFLAGS = -Wall
Note that CFLAGS is an internal variable in Make, the same way, CMAKE_C_FLAGS is internal variable in CMake .
adding include and library path in CMake
We can do it in cmake using functions.
target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})
Vs adding include and library path in Make
We can add include and libraries by adding lines like the following,
INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest
Note this lines above can be generated from auto-gen tools or pkg-config. (though Makefile is not dependent of auto-config tools)
CMake configure/tweek
Normally it is possible to generate some config.h file just like auto-config tools by using configure_file function. It is possible to do more trick writing custom functions. And finally we can select a config like the following,
cmake --build . --config "Release"
It is possible to add some configurable option using the option function.
Makefile configure/tweak
If somehow we need to compile it with some debug flag, we can invoke the make like,
make CXXFLAGS=NDEBUG
I think internal variables, Makefile-rules and CMake-functions are good start for the comparison, good luck with more digging.
This is either trivial or runs counter to the philosophy of how make should be used, but I'd like to have a command line that reads as "make debug" rather than "make DEBUG=1". I tried creating a phony target called debug that did nothing except set the DEBUG variable, but then there was a difference between "make debug build" and "make build debug"--namely that in one case, the variable got set after the build happened.
Is there a way to give certain targets precedence?
Thanks for your help.
See 'Target-specific variable values' in this page.
You can also do it by looking at the MAKECMDGOALS variable
ifneq "$(findstring debug, $(MAKECMDGOALS))" ""
DEBUG = 1
endif
build:
#echo build and DEBUG is [$(DEBUG)]
debug:
This is what happens when you call it:
$ make build
build and DEBUG is []
$ make build debug
build and DEBUG is [1]
make: Nothing to be done for `debug'.
$ make debug build
make: Nothing to be done for `debug'.
build and DEBUG is [1]
you can write the following:
.PHONY: debug
debug:
$(MAKE) -$(MAKEFLAGS) build DEBUG=1
build:
echo makeflags='$(MAKEFLAGS)' debug=${DEBUG}
This will at least work with GNU Make, BSD Make and Interix Make. I didn't try all the other implementations.
One thing you can do with GnuMake is use macros that expand to rules with the foreach builtin. Something like:
TARGETS := build all foo bar baz
define DEBUG_TARGET_RULE
$(1).debug:
$$(MAKE) DEBUG=1 $(1)
debug.$(1):
$$(MAKE) DEBUG=1 $(1)
endef
$(foreach target,$(TARGETS),$(eval $(call DEBUG_TARGET_RULE,$(target))))
This will allow you to type make debug.foo or make foo.debug and it will automatically turn into make DEBUG=1 foo, and it works for any target you put in $(TARGETS)
If your debug will only be used with the build target, you might as well make debug call build so you can just type make debug or make build, where make build would be non-debug.
But as for your actual question, I'm not familiar enough with makefiles to answer it.
One approach is to set up the dependencies and build rules in both the build and debug targets, but add the your debugging options to the debug target. A simple example:
Makefile
program: program.c
gcc -o program program.c
debug: program.c
gcc -D DEBUG -o program program.c
Program.c
#include <stdio.h>
int main(void) {
#ifdef DEBUG
printf("DEBUG on!\n");
#endif
printf("in the program\n");
return 0;
}