Makefile -- do not rebuild order-only dependency if it already exists - makefile

I'm wondering if it's possible to create a does-not-exist-only target, such that a dependency's sub-dependencies are not considered if the dependency already exists.
That is, if I had the following:
A : | B
#echo building $#
#touch $#
B : C
#echo build $#
#touch $#
.PHONY: C
C:
#echo build $#
And then I do make A; make A. In the first make it rebuilds C, B, then A. In the second invocation, it still rebuilds C and B even though it doesn't need to in order to build A. I'd like to short-circuit this such that it doesn't consider the dependencies of B if B already exists...

There's more than one way to do it.
One way is to use Recursive Make (DUHN-DUHN-DUHNNNN!)
B :
#$(MAKE) C
#echo build $#
#touch $#
Or you could turn C from a rule to a recipe:
define c-steps
#echo build C
#echo with all the steps that C entails
endef
B :
$(call c-steps)
#echo build $#
#touch $#

A : | B
#echo building $#
#touch $#
B : $(if $(filter B,$(MAKECMDGOALS)),C) | C
#echo build $#
#touch $#
C:
#echo build $#
#touch $#
Your dependency B : C only applies when you wish to make B explicitly. The caveat of this is that it works only if you remove the phoniness of C.

Related

GNU make: generic rule for compiling from different paths

I have a makefile like this:
default: exe
%.obj: %.src
# dummy compiler
#echo link $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo link $^ to $#
cat $^ > $#
main.obj: main.src
foo.obj: /some/dir/1/foo.src
bar.obj: /some/dir/2/bar.src
Make can't compile foo.obj and bar.obj (and 20+ other objects), because it does not use the "%.obj: %.src" rule. The directories of foo.obj and foo.src resp. bar.obj and bar.src do not match, so the rule does not match.
Is there a way to specify a rule that ignores the directory part of the filenames?
Update:
To make that Makefile work, I copied the compiler lines from the pattern rule to the foo.obj and bar.obj rules (and the 20+ other object rules). That's anything but clean and maintainable. Essentially, I need a pattern rule that ignores the source and object directories when comparing.
I know of no such features (excepted macros, you could arrange for them to generate the makefile fragments you are writing manually). But GNU Make has a vpath feature which allows to specify a path where to look for files of a given extension and which interact with the automatic variables to make something close to what you want.
Your Makefile can be then written as:
default: exe
vpath %.src some/dir/1:some/dir/2
%.obj: %.src
# dummy compiler
#echo compiling $< to $#
cat $< > $#
exe: main.obj foo.obj bar.obj
# dummy linker
#echo linking $^ to $#
cat $^ > $#
Note that this is not exactly what you want: if there is a bar.src in both some/dir/1 and some/dir/2, the one from some/dir/1 will be used.
You can make a variable of all .src files in all subdirectories with $(shell find . -name '*.src'). Here's an example:
OBJS := $(shell find . -name '*.src')
default: exe
%.obj: %.src
#echo link $< to $#
cat $< > $#
exe: $(OBJS)
#echo link $^ to $#
cat $^ > $#
The macro way of doing this would be as follows:
define mymacro
$1: $2
#echo compiling $$< to $$#
cat $$< > $$#
endef
$(eval $(call mymacro,foo.obj,/some/dir/1/foo.src))
$(eval $(call mymacro,bar.obj,/some/dir/2/bar.src))
But be aware that macros make the makefile less maintainable (as it's harder to read, and introduces some sharp sticks inexperienced users might trip on). It also works on GNU make, but may fail on some other make systems.
I have written a build system which uses gmtt and which relies on explicit source elicitation. At the core is a beefed up version of wildcard named wildcard-rec which supports recursive descent akin to ** in other extended wildcard matchers (like git) - maybe it fits your taste and use case:
include gmtt.mk
default: exe
SOURCE_LOCATOR := $(call wildcard-rec,main.src some/dir/**/3/*.src some/**/1/foo.src some/dir/2/bar.src)
$(info Compiling these sources: $(SOURCE_LOCATOR))
OBJECTS := $(addsuffix .obj,$(basename $(notdir $(SOURCE_LOCATOR))))
$(info Building these objects: $(OBJECTS))
# Generate the source prerequisite for each object
TGT-PREREQ := $(join $(addsuffix :,$(OBJECTS)),$(SOURCE_LOCATOR))
# Introduce them as targets via eval:
$(foreach tp,$(TGT-PREREQ),$(info $(tp))$(eval $(tp)))
$(OBJECTS):
#echo compile $< to $#
exe: $(OBJECTS)
#echo link $^ to $#
Test:
Compiling these sources: main.src some/dir/foo/3/a.src some/dir/foo/3/b.src some/dir/bar/1/foo.src some/dir/2/bar.src
Building these objects: main.obj a.obj b.obj foo.obj bar.obj
main.obj:main.src
a.obj:some/dir/foo/3/a.src
b.obj:some/dir/foo/3/b.src
foo.obj:some/dir/bar/1/foo.src
bar.obj:some/dir/2/bar.src
compile main.src to main.obj
compile some/dir/foo/3/a.src to a.obj
compile some/dir/foo/3/b.src to b.obj
compile some/dir/bar/1/foo.src to foo.obj
compile some/dir/2/bar.src to bar.obj
link main.obj a.obj b.obj foo.obj bar.obj to exe

Impose an order for the prerequisites of a target

I have a makefile snippet:
all: $(objects)
fresh: clean all
clean: ;rm $(objects)
Here, I want to ensure that when I do make fresh - clean should precede all.
But how can I make sure this, given that when I do make all, clean should not be made?
I can imagine that one way could be like this
fresh: clean
make all
Is it the right (or the only) way to solve this issue?
If you use GNU make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh:: clean
fresh:: all
.PHONY: clean fresh all
Please note the double colon after targets fresh! See the documentation:
The double-colon rules for a target are executed in the order they
appear in the makefile.
If you run make -j2 fresh it shows it works as expect:
clean
end clean
all
end all
But with fresh:: clean all doesn't work properly parallel (maybe unexpected).
With BSD make:
all:
#echo $#
#sleep 1
#echo end $#
clean:
#echo $#
#sleep 1
#echo end $#
fresh: clean all
#echo $#
.ORDER: clean all
.PHONY: clean all fresh
Note the line begin with .ORDER. It works well in parallelization too (see man make). Without parallelization the order of dependencies in line fresh: counts.
As you already suggest in your question, calling make recursively on the same makefile for the target all in a recipe whose prerequisite is clean:
# At the very beginning of the makefile
CURRENT_MAKEFILE := $(lastword $(MAKEFILE_LIST))
# ...
.PHONY: fresh
fresh: clean
$(MAKE) -f $(CURRENT_MAKEFILE) all
This imposes an order, since the target fresh depends on the prerequisite clean, clean's recipe will be executed before fresh's recipe, which in turn will execute all's recipe.
Note that I'm using here $(MAKE) instead of make for the recursion.

master-makefile

Hello I'd like to create a master file for 3 separated makefiles in 3 different directories. Makefiles work on their own, but not from a mastermakefile (below). After entering A directory, I get an error that: make: Circular A <- A dependency dropped.
make: `A' is up to date.
PROG = A B C
TRGTS = A B C
$(PROG): $(TRGTS)
all: $(TRGTS)
A:
cd ./A ; make a
B:
cd ./B ; make b
C:
cd ./C ; make c
clean:
/ rm -f *.o *~
cd ./A ; make clean
cd ./B ; make clean
cd ./C ; make clean
The following code is almost the same as William answered, but without using 'for' loop statement.
subdirs := A B C
.PHONY: all $(subdirs)
all: $(subdirs)
$(subdirs):
$(MAKE) -C $#
I'm rusty on makefiles and know for sure the following is not the best answer. But it might help for now...
TARGETS = A B C
.phoney: all
all:
#for subdir in $(TARGETS); do \
$(MAKE) -C $$subdir all || exit 1; \
done
Note that the indents must use a TAB, not spaces

Referring to the target name from the list of the prerequisites

In a Makefile, I would like to refer to the target name from the list of prerequisites and to build something with it. Something of the form:
%.foo: $(addsuffix .bar, $(DATA_%))
#echo $<
So that, supposing you have:
DATA_test = 1 2 3
When you call it as:
make test
That will expand to:
1.bar 2.bar 3.bar
Is this somehow possible? What would be a better approach to the problem?
If your version of Make has secondary expansion, this will probably work (I can't test it because today all I have handy is an old version).
.SECONDEXPANSION:
%.foo: $$(addsuffix .bar, $$(DATA_$$*))
#echo $^
Without that, I don't see any better way to do it than this:
define FOO_RULE
$(1).foo: $(addsuffix .bar,$(DATA_$(1)))
endef
FOO_TYPES = test real whatever
$(foreach t,$(FOO_TYPES),$(eval $(call FOO_RULE,$(t))))
%.foo:
#echo building $# from $^

Make 3 passes for a target

I'll explain myself, here is my scenario:
Compile my target
Do a first optimization based on the first compilation
Do a second optimization based on the first optimization
Do a third optimization based on the second optimization
So far I tried the following:
.SUFFIXES:
.SECONDARY:
OBJECTS := $(addsuffix .obj,$(SOURCES))
override OBJECTS := $(OBJECTS:$(SRC)/%.obj=$(OBJ)/%.obj)
OC1 := $(patsubst %.obj, %.oc1, $(filter %c.obj,$(OBJECTS)))
O1 := $(L166_CMD:%.lnp=%.o1)
all: $(TARGET) $(O1)
$(TARGET): $(OBJECTS)
#echo Linking $(TARGET)...
$(OBJ)/%.c.obj: $(SRC)/%.c
#echo Compiling $(<F) ...
# c.oc1 is a intermediate file
%.c.oc1: %.c.obj
#echo 1 - Optimize $<...
#touch $#
$(O1): $(OC1)
#touch $#
echo Linking O1
Result is, I modify a C file, the target will regenerate only the modified C file but the O1 pass will optimize all C files again like it was not done before (but it was).
How can I modify this behavior?
The reason is your last target, $(O1): $(OC1). That is each O1 depends on every OC1.
What is the actual value of $(O1)? Is it supposed to be a list or a single target?
I would try to replace this rule by a pattern (if it possible).

Resources