Makefile dependencies depend on parameters - makefile

We have a project that builds one application but uses different sources depending of some parameter. Simplified example looks like this:
app1.c
int main() {
printf("1\n");
}
app2.c
int main() {
printf("2\n");
}
Makefile
ifeq ($(PARAM),true)
OBJ=app1.o
else
OBJ=app2.o
endif
all: app
app: $(OBJ)
$(CC) $< -o $#
The problem:
$ make app
cc -c -o app2.o app2.c
cc app2.o -o app
$ ./app
2
$ PARAM=true make app
cc -c -o app1.o app1.c
cc app1.o -o app
$ ./app
1
$ make app # I want 2 again
make: `app' is up to date.
$ ./app
1
Is there a sane way to properly rebuild everything without deleting the output?

The problem is that app depends on different inputs depending on the value of that variable. Make does not remember the values of variables between invocations. You effectively get different makefiles with different value of that variable.
One solution is to unconditionally build two apps:
all: app1 app2
app1: app1.o
$(CC) -o $# $<
app2: app2.o
$(CC) -o $# $<
And then if you only need to build one you do:
$ make app1
To build another:
$ make app2
To build all:
$ make
You may also like to add a dependency on Makefile, so that your applications get rebuilt when you change Makefile, e.g.:
app1: app1.o Makefile
$(CC) -o $# $(filter-out Makefile,$^)
And generate dependencies automatically:
%.o: %.c Makefile
$(CC) -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
-include $(wildcard *.d)

Related

What are the default rules used by make?

Even when I do not specify a Makefile, make has built in commands, such as:
$ ls
a.c
$ make a.o
cc -c -o a.o a.c
$
Is there a way to know the exact list of built in commands? For example, I am expecting something like:
%.o: %.c
$(CC) $(CFLAGS) $(AAA) $(BBB) -c -o $# $<
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(AAA) $(BBB) -c -o $# $<
...
It looks like the first flag variable is CFLAGS for C and CXXFLAGS for C++, but I have no idea what the other flag variables are (AAA and BBB above).
Does make store the default rules in some configuration file? Or is it in make's source code?
I am using GNU Make 4.3 on a Fedora Linux machine.

Creating 2 versions of same lib using GNU make

I need to create 2 different versions of same lib (.a & .so files), using different compilation flags.
for instance,
the following debug flag should be enabled in only one of the builds:
#ifdef ENABLE_NEW_FEATURE
//some code
#endif
the lib Makefile is being called from outside project with many executables, some of them need to have the new feature and some of them not.
i wonder how can i use Makefile to create 2 different versions of same lib without suffering race condition in case of running make -j.
The usual way is to use several directories for the objects. Then you may use something like:
SOURCES=f1.cpp f2.cpp
all: libmylib-d.a libmylib-o.so
libmylib-d.a: CFLAGS=-Dd
libmylib-d.a: $(SOURCES:%.cpp=obj-d/%.o)
ar -cru $# $^
libmylib-o.so: CFLAGS=-Do -fPIC
libmylib-o.so: $(SOURCES:%.cpp=obj-o/%.o)
g++ -shared -o $# $^
obj-d/%.o: %.cpp | obj-d
$(CXX) $(CFLAGS) -c -o $# $<
obj-o/%.o: %.cpp | obj-o
$(CXX) $(CFLAGS) -c -o $# $<
obj-o obj-d:
mkdir $#

Makefile with different source types doesn't notice make.depend

I want my Makefile to accept different source file types. It does, but it does not recompile when I alter an include file. Here's the Makefile:
C_SOURCES := $(wildcard *.c)
CPP_SOURCES := $(wildcard *.cpp)
CC_SOURCES := $(wildcard *.cc)
ALL_SOURCES := $(notdir $(C_SOURCES) $(CPP_SOURCES) $(CC_SOURCES))
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
ALL_OBJECTS := $(notdir $(C_OBJECTS) $(CPP_OBJECTS) $(CC_OBJECTS))
#############################################################
all: a.out
a.out: $(ALL_OBJECTS)
g++ -o $# -g $^
%.o: %.cpp
g++ -c $# -g $^
%.o: %.cc
g++ -c $# -g $^
%.o: %.c
g++ -c $# -g $^
clean:
rm -f a.out
rm -f *.o
make.depend: $(ALL_SOURCES)
g++ -MM $^ > $#
-include make.depend
The lines starting with *.o: are a recent addition -- I wondered if it might help. No effect.
make.depend is doing its job: I checked it out, and its dependencies are correct. (For my MCVE I have one source file main.cpp which includes date.h.)
main.o: main.cpp date.h
The output of $(info $(ALL_OBJECTS)) is main.o.
So: how can I get it to recognize changes to includes?
It would be helpful, when asking questions, to show an example of running the commands and what is printed. Given the makefile you provide I'd be surprised of make actually ran any commands at all, other than generating the depend file.
That's because this:
C_OBJECTS := ${C_SOURCES: .c =.o}
is invalid syntax. Or more precisely, it doesn't do what you want to do. It replaces the literal string _____.c__ (where the _ are whitespace... SO won't let me just use spaces) at the end of each word in C_SOURCES with .o. Of course you don't have any of those, so basically your ALL_OBJECTS variable contains just your source files (since no changes are made by the substitution).
You can use:
$(info $(ALL_OBJECTS))
to see what happens here.
This needs to be written:
C_OBJECTS := ${C_SOURCES:.c=.o}
CPP_OBJECTS := ${CPP_SOURCES:.cpp=.o}
CC_OBJECTS := ${CC_SOURCES:.cc=.o}
Whitespace in makefiles is very tricky. You definitely have to be careful where you put it and you can't add it anywhere you like.
Also I have no idea why you're using notdir since all your files are in the current directory.
And technically it's incorrect to compile .c files with the g++ compiler front-end.
ETA also your pattern rules are incorrect: you're missing the -o option to the compiler; they should all be the equivalent of:
%.o: %.c
g++ -c -o $# -g $^
Better is to use the standard make variables, then you can customize the behavior without rewriting all the rules:
CFLAGS = -g
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
Update Just use the comprehensively enginerred automatic dependency file generation #MadScientist describes at http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/. This works with both GCC and clang (due to clang's explicit goal to be commandline compatible to GCC).
For completeness' sake, my original answer:
The generated dependency rules must depend on the sources determined by the dependeny rule generating rule. This requires the -MT parameter to gcc.
I have included this as an example in a slightly cleaned up version of your GNUmakefile:
#############################################################
ALL_CFLAGS = -g
ALL_CXXFLAGS = -g
#############################################################
.PHONY: all
all: all-local
#############################################################
bin_PROGRAMS += test-cxx
test_cxx_OBJECTS += main.o
test_cxx_OBJECTS += main-c.o
test-cxx: $(test_cxx_OBJECTS)
$(LINK.cc) $(ALL_CXXFLAGS) -o $# $^
ALL_OBJECTS += $(test_cxx_OBJECTS)
#############################################################
%.o: %.cpp
$(COMPILE.cpp) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.cc
$(COMPILE.cc) $(ALL_CXXFLAGS) -o $# -c $<
%.o: %.c
$(COMPILE.c) $(ALL_CFLAGS) -o $# -c $<
#############################################################
%.dep: %.cpp
$(COMPILE.cpp) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.cc
$(COMPILE.cc) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
%.dep: %.c
$(COMPILE.c) -MM -MT "$*.o $# " $< > $#.tmp
mv -f $#.tmp $#
ALL_DEPS = $(ALL_OBJECTS:.o=.dep)
-include $(ALL_DEPS)
#############################################################
.PHONY: all-local
all-local: $(bin_PROGRAMS)
.PHONY: clean
clean:
rm -f $(bin_PROGRAMS)
rm -f *.dep
rm -f *.o
#############################################################
The *.dep generating rules will recursively examine all included source files, and list them all in the generated *.dep file.
Using a separate *.dep file for each object file means that if you change only one source file, only the *.dep files needing regeneration will actually be regenerated.
The *.dep generating rule creates a *.dep.tmp file first, and only moves that to *.dep if generating the *.dep.tmp file has been successful. So if for some reason generating the *.dep.tmp file fails (e.g. you might be including a non-existing header file), you will not have a newly generated (and thus considered up to date) empty *.dep file being included by make.

makefile automatic variable for corresponding c file

i hava a makefile something like this:
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(notdir $(allsrc:.c=.o))
...
test: $(allobjs)
$(allobjs): $(allsrc)
gcc -c -o $# $<
make test performs:
gcc -c -o release/a.o aaa/a.c
gcc -c -o release/b.o aaa/a.c
gcc -c -o release/c.o aaa/a.c
(automatic variable $< always takes first prerequisite)
but i want "corresponding one":
gcc -c -o release/a.o aaa/a.c
gcc -c -o release/b.o bbb/b.c
gcc -c -o release/c.o ccc/c.c
what should i change to accomplish desirable result?
i know that this will work for sure:
$(outdir)/a.o: aaa/a.c
gcc -c -o $# $<
$(outdir)/b.o: bbb/b.c
gcc -c -o $# $<
$(outdir)/c.o: ccc/c.c
gcc -c -o $# $<
and wondering how to accomplish the same in one receipe. (because in my real makefile i have ~20 different source files not just 3 like i made here for example)
You don't write your recipe like that. That's not how make works.
That recipe says that every item in $(allobjs) has every item in $(allsrc) as its prerequisite but that's not what you mean.
You mean that every .o file has the matching .c file as its prerequisite which is exactly what the built in %.o: %.c rule already does. You don't even need a makefile to do that.
Edit: Actually, you don't mean that. I had missed that the source files were in different directories. That changes and complicates things.
Chris Dodd wrote up two good solutions for this.
The usual way to do what you are asking would be something like:
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(notdir $(allsrc:.c=.o)))
VPATH = $(sort $(dir $(allsrc)))
...
test: $(allobjs)
$(outdir)/%.o: %.c
gcc -c -o $# $<
Of course, this will run into problems if you have a b.c in both aaa and bbb, but since you're trying to put all the object files in the same directory, you have that regardless. It might make more sense to get rid of the $(notdir and keep the same directory structure under $(outdir), in which case you don't need the VPATH
outdir = release
allsrc = aaa/a.c bbb/b.c ccc/c.c
allobjs = $(addprefix $(outdir), $(allsrc:.c=.o))
...
test: $(allobjs)
$(outdir)/%.o: %.c
mkdir -p `dirname $#`
gcc -c -o $# $<

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