Conditional variable assignement in makefile target - makefile

I'm trying to get conditional assignment in a makefile target, only if it was not set by the requiring target:
REPO_PROD = prod
REPO_DEV = dev
.PHONY: ko-build-container
ko-build-container: KO_DOCKER_REPO ?= $(REPO_PROD)
ko-build-container:
#echo $(KO_DOCKER_REPO)
.PHONY: ko-build-container-dev
ko-build-container-dev: KO_DOCKER_REPO = $(REPO_DEV)
ko-build-container-dev: ko-build-container
Unfortunately make ko-build-container-dev prints prod.
What am I missing here ?

Another alternative is to use a third target, like:
ko-build-container-base:
echo $(KO_DOCKER_REPO)
ko-build-container: KO_DOCKER_REPO = $(REPO_PROD)
ko-build-container: ko-build-container-base
ko-build-container-dev: KO_DOCKER_REPO = $(REPO_DEV)
ko-build-container-dev: ko-build-container-base

Apparently, with GNU make, the outcome of the conditional assignment (assign or not assign) is decided in a phase where only global variables are available, but the selection of the final value comes from a later phase where inherited target-specific variables are also available. So, even more bizarre than what you observed, after skipping a conditional assignment because a global variable was set, the final value is not necessarily that of the global variable, it can be inherited from a parent target! Demo:
$ cat Makefile
.PHONY: sub all
all: VAR = all
all: sub
# no global VAR set => assign instead of using inherited VAR = all
sub: VAR ?= sub
sub:
#echo $(VAR)
$ make
sub
$ cat Makefile
.PHONY: all
VAR = global
# global VAR set => do not assign, use global VAR = global
all: VAR ?= all
all:
#echo $(VAR)
$ make
global
$ cat Makefile
.PHONY: sub all
VAR = global
all: VAR = all
all: sub
# global VAR set => do not assign... but use inherited VAR = all
sub: VAR ?= sub
sub:
#echo $(VAR)
$ make
all
This strange behavior is reported here: https://savannah.gnu.org/bugs/?18305 and there is also a discussion about whether it should/could be fixed.
Separating the outcome from the selection of the value in conditional assignments is clearly a bug, I think. Nobody would imagine such a weird behavior. Anyway, instead of a target-specific conditional assignment you could use the workaround suggested in the discussion:
$ cat Makefile
REPO_PROD = prod
REPO_DEV = dev
.PHONY: ko-build-container
ko-build-container:
#echo $(or $(KO_DOCKER_REPO),$(REPO_PROD))
.PHONY: ko-build-container-dev
ko-build-container-dev: KO_DOCKER_REPO = $(REPO_DEV)
ko-build-container-dev: ko-build-container
$ make ko-build-container-dev
dev

Related

run a target always along with default target

I have a default target "all" but I want to initialize a few variables ever time I run the makefile . whatever is the target for make flow.
cat Makefile
all: last_step
initialize:
ifeq (,$(filter $(ps),0 1))
#$(eval override ps=0)
endif
step1:
<>
step2: step1
<>
....
last_step: second_last_step
<>
I want to initialize the variable every time a make file is run .
initialize target should be run in both the following flow styles.
make .
make nth-step
Nothing easier:
ifeq (,$(filter $(ps),0 1))
override ps=0
endif
all: last_step
...
step1:
...
...

Makefile tree for debug/test/release builds with multiple targets

Structure:
makefile
system/
-> makefile
-> kernel/
-> -> makefile
-> -> src/
-> FutureModules
-> -> makefile
-> -> src/
userland/
-> makefile
-> FutureModules
-> -> makefile
-> -> src/
Currently I'm building it with make system.
I'd like to split it up into Debug/Test/Release builds so that i can do something like make debug system or make -d system with multiple targets (e.g. make debug system userland or something like that).
I'd like to change the targets so i can directly build a target instead of building system and manually have to add the desired targets in system/makefile.
Now in order to achieve this:
Do constants get shared between makefiles? So when i do make system and i define CFLAGS += -g -Og in the root makefile, does the system/makefile get the constants from the root makefile?
Do constants stay the same in a make session? So when i do make debug system userland and have something like debug: CFLAGS += -g -Og, do system and userland get the -g -Og flags?
EDIT: I managed to achieve 2. by using $(shell find -maxdepth 1 -type d) and some other commands.
Solved it with:
#Build mode. m=d => Debug | m=t => Test | m=r => release | default => release
ifeq ($(m), d)
NASBUILD = $(NASDEBUG)
GASBUILD = $(GASDEBUG)
CPPBUILD = $(CPPDEBUG)
CBUILD = $(CDEBUG)
else ifeq ($(m), t)
NASBUILD = $(NASTEST)
GASBUILD = $(GASTEST)
CPPBUILD = $(CPPTEST)
CBUILD = $(CTEST)
else ifeq ($(m), r)
NASBUILD = $(NASRELEASE)
GASBUILD = $(GASRELEASE)
CPPBUILD = $(CPPRELEASE)
CBUILD = $(CRELEASE)
else
NASBUILD = $(NASRELEASE)
GASBUILD = $(GASRELEASE)
CPPBUILD = $(CPPRELEASE)
CBUILD = $(CRELEASE)
endif
export NASBUILD
export GASBUILD
export CPPBUILD
export CBUILD
Where xxxBUILD and so on gets added to the corresponding xxxFLAGS.

Makefile: embedded statements

I have in the /bin folder a file program.cc.
The following Makefile statements
BINS = $(wildcard bin/*.cc)
EXECS = $(notdir $(BINS))
EXECSR = $(EXECS:.cc=)
mean that EXECSR is program
I try to avoid the intermediary variable EXECS in the above statements
BINS = $(wildcard bin/*.cc)
EXECSR = $($(notdir $(BINS)):.cc=)
but this approach fails - EXECSR is empty. How should I modify the Makefile to avoid the intermediary variable EXECS?
EXECSR = $(notdir $(BINS:.cc=))

GNU Make: How to perform second expansion with suffix-changing substitution

What I'm going for (what's failing)
I have a list of dependencies for each file:
point_deps =
bounds_deps = point
triangle_deps = point bounds
Image_deps = types bounds triangle
main_deps = Image triangle bounds point types
I'd like to write a rule to include the relevant dependencies. Here's my best attempt:
out/%.o: src/%.cpp src/%.h $$($$*_deps:%=src/%.h)
g++ -o $# -c $<
I expect $* to evaluate to, for instance, "main". Then the suffix-changing substitution should change each entry in the dependency list to begin with "src/" and end with ".h".
When I try to run the code above, I get an error (on the out/%.o line):
makefile:26: *** multiple target patterns. Stop.
What's working (non-optimal)
For now I have to create a separate variable for each file's header dependencies:
point_deps_h = $(point_deps:%=src/%.h)
bounds_deps_h = $(bounds_deps:%=src/%.h)
triangle_deps_h = $(triangle_deps:%=src/%.h)
Image_deps_h = $(Image_deps:%=src/%.h)
main_deps_h = $(main_deps:%=src/%.h)
Then I can use secondary-expansion to include the correct header files:
out/%.o: src/%.cpp src/%.h $$($$*_deps_h)
g++ -o $# -c $<

Split a variable definition in different lines

Ok, I suppose this one is silly (and have done it in the past) but I honestly cannot remember how it's done.
I have a variable like :
GCC = gcc
So, far so good...
Now, what if my variable definition is too long and want to split it into different lines, so that it looks nice and manageable?
D_FILES = main console globals components/program components/statement components/statements components/assignment components/loop components/block components/library components/argument components/expression components/expressions components/functionDecl components/ruleDecl components/functionCall components/functionCallSt components/returnSt components/outSt components/inSt
I think you can do something like this
CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \
-DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \
-DDEFBLOCKING=$(DEFBLOCKING)
put backslash at and and new line starting with TAB.
I don't know why you're having trouble using backslashs, but you can do it this way:
D_FILES = main console globals components/program components/statement
D_FILES += components/statements components/assignment components/loop
D_FILES += components/block components/library components/argument
# and so on

Resources