Makefile function expansion - makefile

build_debug:=dltvr
define debug
$$(findstring $(2),$$(if $$(DEBUG_SCOPE_DIR),$$(if $$(filter $$(DEBUG_SCOPE_DIR)%,$(1)),$(build_debug)),$(build_debug)))
endef
define warn
$$(if $(call debug,$(1),$(2)),$$(warning $(3)))
endef
$(call warn,jianxi,d,D jianxi)
In my optinion, $(call warn,...) will be expand to
$(if $(findstring d,$(if $(DEBUG_SCOPE_DIR),$(if $(filter $(DEBUG_SCOPE_DIR)%,jianxi),dltvr),dltvr)),$(warning D jianxi))
And will output Makefile:13: D jianxi

You are correct; $(call warn,...) will be expanded to $(if $(findstring ...)...). But it will not be expanded any further.
You have escaped the '$' symbols too far. Try this:
define warn
$(if $(call debug,$(1),$(2)),$(warning $(3)))
endef

Related

Makefile: conditionals inside define

I am trying to check that variable value is yes or no, but the following always fails:
FLAG1 ?= no
FLAG2 ?= yes
define check_
ifneq ($(filter $(2),$($(1))),$($(1)))
$(error Bad $(1) argument)
endif
endef
$(call check_,FLAG1,yes no)
$(call check_,FLAG2,yes no)
What am I doing wrong?
FLAG1 ?= no
FLAG2 ?= yes
define check_
$(if $(filter $($(1)),$(2)),,$(error BAD $(1) argument))
endef
$(call check_,FLAG1,yes no)
$(call check_,FLAG2,yes no)
Notice that you added a space before FLAG1, which means $$(1) resolves to $( FLAG1), which in turn resolves to blank. The next part is that I'm not sure about is the use if ifneq inside of a define. You can use $(if ) instead
---- EDIT ------
Actually, it's a combination of the missing space and #MadScientists answer... The following also works:
define check_
ifneq ($(filter $($(1)),$(2)),$($(1)))
$$(error Bad $(1) argument [$($(1))] / [$(filter $($(1)),$(2))])
endif
endef
$(eval $(call check_,FLAG1,yes no))
Thus ifneq can be used inside of a macro... (and as #MadScientist pointed out, you have to escape the $ in front of $(error) to prevent it from being expanded by call...)
You can't use plain call with a multi-line macro. You have to use $(eval $(call ...)) if the result of the call function consists of more than one line of makefile content.
You can use this:
define check_
ifneq ($$(filter $(2),$$($(1))),$$($(1)))
$$(error Bad $(1) argument)
endif
endef
Basically, anything you want to be interpreted by the eval needs to be escaped so that call doesn't see it.

Missing separate error from makefile

With this Makefile, I'm not sure why I'm thrown a missing separator error.
define foo
$(eval a := $(1))
$(eval b := $(1))
endef
$(call foo,hello)
$(info $(a))
$(info $(b))
all: ;
If I however replaces the first eval with this,
$(eval a := $(1)) \
then the error goes away. eval expands to nothing, and it's happy with only one eval inside the define. But I'm not sure why it's complaining in this case, nor why the trailing back slash solves it.
define foo
$(eval a := $(1))
$(eval b := $(1))
endef
bar:=$(call foo,hello)
$(info $(a))
$(info $(b))
$(info bar=[$(bar)])
all: ;
Running this makefile outputs:
$ make -f Makefile.sample
hello
hello
bar=[
]
make: 'all' is up to date.
So $(foo) function outputs new line character. It should either output nothing or value should be captured in variable or trapped with $(eval) or $(strip).
$(eval a := $(1)) \ results in no new line output from $(foo) that is why it fixes the problem.
Alternatives to adding backslashes to your $(foo) are:
#1:
define fooBody
$(eval a := $(1))
$(eval b := $(1))
endef
foo = $(strip $(call fooBody,$1,$2))
#2
define fooBody
$(eval a := $(1))
$(eval b := $(1))
endef
foo = $(eval $(call fooBody,$1,$2))
#3
$(strip $(call foo,hello))
#4
$(eval $(call foo,hello))
#5
.:=$(call foo,hello)
My personal choice is #1.
The call expansion results in a single newline (because, as you say, both the eval's expand to the empty string. When make tries to parse that, it doesn't understand it and throws this error.
The important thing to understand is that make will break the input into logical lines before it tries to run expansion. So after the expansion is complete, make expects to see a single line of output and it doesn't understand newlines existing in that single line.
Probably this could be handled better, if you wanted to file a bug at https://savannah.gnu.org/bugs/?func=additem&group=make
ETA Actually I checked and this has already been fixed in GNU make 4.2:
$ make-4.1
Makefile:5: *** missing separator. Stop.
$ make-4.2
make: *** No targets. Stop.

Custom Make function doesn't get parameter

I want to add Modules to my build system.
To keep my makefile clean when adding new modules, they all follow the same pattern, so I tried to generalize it with a function:
uc = $(shell echo $1 | tr '[a-z]' '[A-Z]')
define driver-mod
$(eval CFLAGS += -DUSE_$(call uc, $1));
$(eval include $(DRIVERS_SRC)/$1/Makefile.include);
endef
ifneq (,$(filter led,$(USEMODULE)))
$(call driver-mod, led)
endif
ifneq (,$(filter uart,$(USEMODULE)))
$(call driver-mod, uart)
endif
ifneq (,$(filter button,$(USEMODULE)))
$(call driver-mod, button)
endif
(the ifneq is going to be replaced with a $(foreach x, $(USEMODULE), $(call driver-mod, $(x))
However, it seems like $1 in driver-mod is not evaluated, I get
make: *** $(DRIVERS_SRC): Is a directory. Stop.
(doesn't actually output $(DRIVERS_SRC) but it's value, edited for clarity)
When I replace the $1 with e.g. led, it works as expected.
What am I missing?
Turns out I have to escape the $ for eval:
define driver-mod
$(eval CFLAGS += -DUSE_$(call uc, $1));
$(eval include $(DRIVERS_SRC)/\$1/Makefile.include);
endef
works!
Can be simplified as follows:
uc = $(shell echo $1 | tr '[a-z]' '[A-Z]')
define __driver-mod
CFLAGS += -DUSE_$(uc)
include $(DRIVERS_SRC)/$1/Makefile.include
endef
driver-mod = $(eval $(call __driver-mod,$(strip $1)))
$(foreach 1,$(USEMODULE),$(driver-mod))

Makefile macro to generate rules

The following makefile is an example. I'm trying to generate the rules for building targets using a defined macro.
What I get is
make: *** No rule to make target `../x86_64/lib-reloc-debug/libstats.tar', needed by `all'. Stop.
sources=$(wildcard $1/*.cpp)
MODE_SUFFIX=-debug
M=../x86_64/lib$(MODE_SUFFIX)
L=../x86_64/lib-reloc$(MODE_SUFFIX)
dir_c_objects=$(patsubst %.c,%.o,$(wildcard $1/*.c))
dir_cpp_objects=$(patsubst %.cpp,%.o,$(wildcard $1/*.cpp))
dir_objects=$(filter-out $1/test%, $(call dir_c_objects, $1) $(call dir_cpp_objects, $1))
dir_objects_with_tests=$(call dir_c_objects, $1) $(call dir_cpp_objects, $1)
libobjdir=$(subst lib,obj,$(dir $1))
l_prefix=$(foreach file,$(1),$(addprefix $L/, $(file))))
TRACE=$(if $(VERBOSE),,#)
define my_make_archive
$(eval name:=$(strip $1))
$(eval reqs:=$2)
$(eval L_sources:=$(call sources, $(name)))
$(eval objects:=$(call dir_objects, $(name)))
$(eval L_objects:=$(foreach file,$(objects),$(addprefix $L/, $(file))))
$(eval M_objects:=$(foreach file,$(objects),$(addprefix $M/, $(file))))
$(eval L_reqs:=$(foreach file,$(reqs),$(addprefix $L/, $(file))))
$(eval M_reqs:=$(foreach file,$(reqs),$(addprefix $M/, $(file))))
$L/lib$(name).tar: $$(L_sources) $(L_reqs)
tar xvf $L/lib$(name).tar: $(L_sources) $(L_reqs)
endef
$(call my_make_archive, stats,)
all: $L/libstats.tar
echo foo
I was not able to find any good examples of using defines to generate rules.
You're making this much too complicated, and your coding is way out ahead of your testing. Try this:
define my_make_archive
name:=$(strip $1)
reqs:=$(2)
L_sources:=$(name).cpp
L_reqs=$$(addprefix $$L/,$$(reqs))
$(L)/lib$(name).tar: $$(L_sources) $$(L_reqs)
tar xvf $$# $$^
endef
all: $L/libstats.tar
echo foo
$(eval $(call my_make_archive, stats))

View end result of Makefile "expansion"

I am trying to understand what the end product of this Makefile which uses eval. Is there a way to view the effective end product of what the Makefile looks like as if eval weren't used?
VALID_TOOLCHAINS := newlib glibc pnacl
NACL_SDK_ROOT ?= $(abspath $(CURDIR)/../../..)
include $(NACL_SDK_ROOT)/tools/common.mk
TARGET = nacl_io
DEPS = nacl_io
LIBS = $(DEPS) ppapi pthread
CFLAGS = -Wall
SOURCES = handlers.c \
nacl_io_demo.c \
queue.c
$(foreach dep,$(DEPS),$(eval $(call DEPEND_RULE,$(dep))))
$(foreach src,$(SOURCES),$(eval $(call COMPILE_RULE,$(src),$(CFLAGS))))
ifeq ($(CONFIG),Release)
$(eval $(call LINK_RULE,$(TARGET)_unstripped,$(SOURCES),$(LIBS),$(DEPS)))
$(eval $(call STRIP_RULE,$(TARGET),$(TARGET)_unstripped))
else
$(eval $(call LINK_RULE,$(TARGET),$(SOURCES),$(LIBS),$(DEPS)))
endif
$(eval $(call NMF_RULE,$(TARGET),))
Yes, I know of two ways:
replace eval with info
run make -p and find your rules explicitly written in the output of that

Resources