Custom Make function doesn't get parameter - makefile

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))

Related

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.

Having trouble understanding $$$$(dir $$$$#) in Makefile using eval

The Makefile template is as follows:
# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$#) $$#"> $$#
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$#)
#echo + cc $$<
$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$#
ALLOBJS += $$(call toobj,$(1),$(4))
endef
# compile file: (#files, cc[, flags, dir])
define do_cc_compile
$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4))))
endef
I know eval will expand twice, so we should use another $. But why should we use $$$$(dir $$$$#) here? I have tried to understand this, but I failed.
When make parses the file, it expands. If it sees $$ it expands it to $. So $$$$ will expand to $$ (two dollars). The eval, once applied will want to expand that once more to $. Thus you need four dollars (note $$$ would expand to $ followed by the expansion of $(, or whatever the next character happens to be, which would likley result in an error)

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))

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.

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