makefile ifeq analog - makefile

I have really big sources with alot of different makefiles.
And now i need add one little condition there, where i can check if line contain what i want then i should use some symbols.
I know that ifeq must be placed at 0 column.
But I cant chage whole sources only for this condition.
How i can check what conatains in variable without ifeq?
I have something like this in define function:
$(gen_cpp_objects): $(intermediates)/%.o: \
$(intermediates)/%$(LOCAL_CPP_EXTENSION) $(yacc_cpps) \
$(proto_generated_headers) $(my_compiler_dependencies) \
$(LOCAL_ADDITIONAL_DEPENDENCIES)
$(transform-$(PRIVATE_HOST)cpp-to-o)
And i need insert condition into $(transform-$(PRIVATE_HOST)cpp-to-o)
i want something like this:
file:=somefile.someextension
define transform-cpp-to-o
#mkdir -p $(dir $#)
#echo "target $(PRIVATE_ARM_MODE) C++: $(PRIVATE_MODULE) <= $<"
ifeq ($(strip $<),$(file))
#Do something here
endif
$(hide) $(PRIVATE_CXX) \
$(addprefix -I , $(PRIVATE_C_INCLUDES)) \

You can use the if function as an inline condition:
$(if $(filter $(strip $<),$(file)), then-block, else-block)

Related

How can I split a string by a delimiter in Makefile?

Here's the code snippet from my Makefile:
%/foo: %/bar.yaml
$(BINARY) generate -g go \
--package-name {COOL_VALUE}
# COOL_VALUE should be the parent folder of a `foo`, e.g., `foo1/foo2/foo -> foo2`
the question is how can I split $# string by / to get the second last element:
E.g.,
make foo1/foo2/foo
> ./binary generate -g go \
--package-name foo2
make foo3/foo
> ./binary generate -g go \
--package-name foo3
My attempts:
I came up with
$(eval package_name := $(word 1,$(subst /, ,$#)))
% pick second last element somehow
If you are really talking about / as a delimiter, then your best bet is to use the filename functions like this:
PARENT = $(notdir $(patsubst %/,%,$(dir $#)))
$(eval package_folders := $(filter-out foo,$(subst /, ,$#)))
$(eval package_name := $(word $(words $(package_folders)), $(package_folders)))
#echo "$(package_name)"

Makefile wildcard for makefile variables, to define generic rules

Background, I suspect XY problem
I have simpler C modules in a directory. I want to write unit tests for these in a sub-directory test/. These unit tests are no more than C programs linking to the module under test, one directory above. I want a Makefile that defines several build targets and lets me build and run the test executables in one step, or separately.
My attempted solution
I've attempted the following:
CC = gcc
CFLAGS = -ggdb -Wall -Wextra -Werror -O3 -std=c99
PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
../parameter_list.c \
parameter_list_test.c
PARAM_LIST_OBJECT_FILES := $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES)))
TARGETS = $(PARAM_LIST_TARGET)
all: $(TARGETS)
$(%_TARGET): $(%_OBJECT_FILES)
$(CC) $(CFLAGS) $^ -o $#
.c.o:
$(CC) -c $< -o $# $(CFLAGS)
clean:
$(RM) *.o $(TARGETS)
test: all
#for t in $(TARGETS) ; do ./$$t ; done
This doesn't work, and it's because of the $(%_TARGET): row. Not surprising, I didn't expect it to work, but I hope this illustrates what I'm trying to achieve.
I want to create more chunks of the form _TARGET, _SOURCE_FILES, and _OBJECT_FILES, to test other modules besides PARAM_LIST, for example:
PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
../parameter_list.c \
parameter_list_test.c
PARAM_LIST_OBJECT_FILES := $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES)))
OTHER_MODULE_TARGET = other_module_test
OTHER_MODULE_SOURCE_FILES = \
../other_module.c \
other_module_test.c
OTHER_MODULE_OBJECT_FILES := $(addsuffix .o,$(basename $(OTHER_MODULE_SOURCE_FILES)))
I understand that % works on filenames, so attempting to use it on variables fails:
$(%_TARGET): $(%_OBJECT_FILES)
$(CC) $(CFLAGS) $^ -o $#
How can I write a rule that matches the Makefile variables _TARGET to their associated _OBJECT_FILES, without creating one per test target?
Or more importantly, how should I do it totally differently?
Edit: I've seen this, however it seems it's only working with a single source file per executable.
You can always access make variables by constructing their names:
MY_VAR := "my var"
HIS_VAR := "his var"
HER_VAR := "her var"
CATS_VAR := "cats var"
DOGS_VAR := "dogs var"
ALL_PERSONS := MY HIS HER CATS DOGS
ALL_VARS := $(foreach p,$(ALL_PERSONS),$($(p)_VAR))
$(info $(ALL_VARS))
Output:
$ make
"my var" "his var" "her var" "cats var" "dogs var"
Defining the dependencies separately seems to work, thanks to this answer:
TARGETS = $(PARAM_LIST_TARGET) $(OTHER_MODULE_TARGET)
all: $(TARGETS)
$(PARAM_LIST_TARGET): $(PARAM_LIST_OBJECT_FILES)
$(OTHER_MODULE_TARGET): $(OTHER_MODULE_OBJECT_FILES)
$(TARGETS):
$(CC) $(CFLAGS) $^ -o $#
This eliminates the need for a duplicate rule (one per target). Still, the definition of dependencies for each target looks like duplicates, a pattern match for these would be nice.
More than that, the OBJECT_FILES variable becomes unnecessary. This works:
PARAM_LIST_TARGET = parameter_list_test
PARAM_LIST_SOURCE_FILES = \
../parameter_list.c \
parameter_list_test.c
$(PARAM_LIST_TARGET): $(addsuffix .o,$(basename $(PARAM_LIST_SOURCE_FILES))) # The dependencies directly
It would still feel nice to have this last row as one rule for all targets. Something like "for all variables ending with TARGET, build a dependency to the content of the variable with the same name, but ending with SOURCE_FILES instead".

Using GNU-make functions to check if variables are defined

I'm writing a makefile that requires some enviroment variables to be defined. I am trying to use something like this to acheive this:
define check-var-defined
ifndef $(1)
$(error $(1) is not defined)
endif
endef
$(call check-var-defined,VAR1)
$(call check-var-defined,VAR2)
$(call check-var-defined,VAR3)
rule1:
#stuff
When I run make with no args I get this:
$ make
Makefile:7: *** VAR1 is not defined. Stop.
But when I run it with VAR1 specified I get the same error.
$ make VAR1=hello
Makefile:7: *** VAR1 is not defined. Stop.
Any ideas why this doesn't work? What can I do to make this work? Thanks in advance.
(Note that I need to check that the variables are actually defined when the makefile is run, as I need to include another makefle further down and the variables need to be set correctly by the time I do this).
The $(call ...) function does not evaluate the results of the function as if it were makefile code, so you can't things like ifdef there.
What happens is that the contents of check-var-defined are expanded and since it doesn't recognize the ifdef operation, it just proceeds to expand the $(error ...) function every time.
If you want to use ifdef you have to use $(eval ...) with $(call ...) which will evaluate the result as if it were a makefile.
Simpler is to use the $(if ...) function, like this:
check-var-defined = $(if $(1),,$(error $(1) is not defined))
Note that this will fail if the variable is empty, which is not quite the same thing as being undefined; it could have been defined to be empty (as VAR1=). But that's the way ifdef works, too, confusingly.
the macro in 1st answer is great but doesn't actually report the name of the 'empty' variable. here is a slight improvement with example/test:
# -*- mode: makefile -*-
check-var-defined = $(if $(strip $($1)),,$(error "$1" is not defined))
my_def1:=hello
my_def3:=bye
$(call check-var-defined,my_def1)
$(call check-var-defined,my_def2)
$(call check-var-defined,my_def3)
and the result:
Makefile:10: * "my_def2" is not defined. Stop.
defined = $(strip $(filter-out undefined,$(flavor $1)))
ensure-defined = \
$(eval .ensure-defined :=) \
$(foreach V,$(sort $1), \
$(if $(call defined,$V),,$(eval .ensure-defined += $V)) \
) \
$(if $(strip ${.ensure-defined}), \
$(foreach V,${.ensure-defined}, \
$(info NOT DEFINED: $$$V) \
) \
$(error Required variables not defined) \
)
ifFOO = $(if $(call defined,FOO), \
$(info FOO is defined: '${FOO}'), \
$(info FOO not defined) \
)
$(ifFOO)
FOO := foo
$(ifFOO)
$(call ensure-defined,FOO BAR)
all: ; #:
OUTPUT:
$ make -f foo.mk
FOO not defined
FOO is defined: 'foo'
NOT DEFINED: $BAR
foo.mk:25: *** Required variables not defined. Stop.

Debug message in Android Makefile

Because I've got problems with files that are not copied to their target anymore I want to debug the Android makefile.
# -----------------------------------------------------------------
# Define rules to copy PRODUCT_COPY_FILES defined by the product.
# PRODUCT_COPY_FILES contains words like <source file>:<dest file>.
# <dest file> is relative to $(PRODUCT_OUT), so it should look like,
# e.g., "system/etc/file.xml".
# The filter part means "only eval the copy-one-file rule if this
# src:dest pair is the first one to match %:dest"
$(foreach cf,$(PRODUCT_COPY_FILES), \
$(eval _src := $(call word-colon,1,$(cf))) \
$(eval _dest := $(call word-colon,2,$(cf))) \
$(eval _fulldest := $(call append-path,$(PRODUCT_OUT),$(_dest))) \
$(if $(filter $(_src):$(_dest),$(firstword $(filter %:$(_dest),$(PRODUCT_COPY_FILES)))), \
$(eval $(call copy-one-file,$(_src),$(_fulldest))),) \
$(eval ALL_DEFAULT_INSTALLED_MODULES += $(_fulldest)) \
)
My aim is to view PRODUCT_COPY_FILES before the loop starts, but what is the right syntax? However every try results in error messages. The whole Makefile can be found here:
https://android.googlesource.com/platform/build/+/master/core/Makefile
This will probably do it:
$(info $(PRODUCT_COPY_FILES))

Problem creating gnu makefile "function"

I have a big chunk of my makefile (~50 lines) that needs to be copy-pasted 5 times for different case (the different libraries used). Is it possible to create a function in a makefile and just call that function instead of copy-pasting?
This is an example of what I've tried. Basically this tries to find the right path for an installed library.
define Flags_template
$(1)_include_home := $(HOME)/usr/include
$(1)_include_home_name := $(HOME)/usr/include/$(1)
ifneq ($$(wildcard $($(1)_include_home)/$(2)),)
$(1)_Include := $$($(1)_include_home)
else
ifneq ($$(wildcard $($(1)_include_home_name)/$(2)),)
$(1)_Include := $$($(1)_include_home_name)
endif
endif
CFLAGS += -I$$($(1)_Include)
endef
$(eval $(call Flags_template,stdcout,StdCout.hpp))
.PHONY: test
test:
# stdcout_include_home_name = $(stdcout_include_home_name)
# stdcout_Include = $(stdcout_Include)
# CFLAGS: $(CFLAGS)
Typing "make", I get this output:
# stdcout_include_home_name = /home/nicolas/usr/include/stdcout
# stdcout_Include =
# CFLAGS: -I
It's so close. But note the last "-I", I always get dupplicates, one fully expended, one empty...
I don't understant what needs to be eval'ed, escaped with two $, etc.
How can I achieve this?
Thank you very much.
Does §8.8 of the GNU Make (3.82) manual help?
[...] Although it might seem overly complex to use eval in this example,
rather than just writing out the rules, consider two things: first, the template definition (in
PROGRAM_template) could need to be much more complex than it is here; and second, you
might put the complex, “generic” part of this example into another makefile, then include
it in all the individual makefiles. Now your individual makefiles are quite straightforward.
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
# Everything after this is generic
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $#
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)
This Works (For Me)
This is the output from the GNU makefile just below:
stdcout_include_home = /work4/jleffler/usr/include
stdcout_include_home_name = /work4/jleffler/usr/include/stdcout
stdcout_Include = /work4/jleffler/usr/include
CFLAGS: -I/work4/jleffler/include -I/work4/jleffler/usr/include
GNU Makefile
CFLAGS = -I${HOME}/include
define Flags_template
$(1)_include_home := $(HOME)/usr/include
$(1)_include_home_name := $(HOME)/usr/include/$(1)
ifneq ($$(wildcard $$($(1)_include_home)/$(2)),)
$(1)_Include := $$($(1)_include_home)
else
ifneq ($$(wildcard $$($(1)_include_home_name)/$(2)),)
$(1)_Include := $$($(1)_include_home_name)
else
$(1)_Include := Neither $$($(1)_include_home) nor $$($(1)_include_home_name) contains $2
endif
endif
CFLAGS += -I$$($(1)_Include)
endef
$(eval $(call Flags_template,stdcout,StdCout.hpp))
.PHONY: test
test:
#echo stdcout_include_home = $(stdcout_include_home)
#echo stdcout_include_home_name = $(stdcout_include_home_name)
#echo stdcout_Include = $(stdcout_Include)
#echo CFLAGS: $(CFLAGS)
The difference is in the wildcard invocations:
ifneq ($$(wildcard $($(1)_include_home)/$(2)),) # Fails
ifneq ($$(wildcard $$($(1)_include_home)/$(2)),) # Works
I have half an intuition about when double-dollars and when single-dollars are needed; I am not sure I can articulate the decision, though.

Resources