How to match double stem in target like %/% or other way? - makefile

I need to build targets with names like,
v1/thread4/foo v1/thread8/foo v1/thread16/foo
v2/thread4/foo v2/thread8/foo v2/thread16/foo
I want to match the thread% and v%, because for my code, the threadNum=? and the Version=? are the Macros need to define in the compile time.
so in the result, I hope to get a layout like, and the foo is the executable name
v1-|thead4/foo
|thead8/foo
|thead16/foo
v2-|thead4/foo
|thead8/foo
|thead16/foo
I've tried ways like, it doesn't work
%/%/foo: foo.cc $(HEADERS)
$(CXX) $(CXXFLAGS) -DTHREAD=$* -o $# $< $(LDLIBS)

It's pretty easy when you realise that $# is v1/thread4/foo (say),
to then pull out the bits you need.
In this case, something like:
v = $(firstword $(subst /, ,$#))
thread = $(notdir ${#D})
YMMV of course. leading to
targets := \
v1/thread4/foo v1/thread8/foo v1/thread16/foo \
v2/thread4/foo v2/thread8/foo v2/thread16/foo
all: ${targets}
v = $(firstword $(subst /, ,$#))
thread = $(notdir ${#D})
${targets}:
: '$#: v [$v] thread [${thread}]'
giving
$ make
: 'v1/thread4/foo: v [v1] thread [thread4]'
: 'v1/thread8/foo: v [v1] thread [thread8]'
: 'v1/thread16/foo: v [v1] thread [thread16]'
: 'v2/thread4/foo: v [v2] thread [thread4]'
: 'v2/thread8/foo: v [v2] thread [thread8]'
: 'v2/thread16/foo: v [v2] thread [thread16]'

There is no way to have multiple patterns in GNU make.
If your example above is actually reflective of what you want to do, it's simple enough, though:
VLIST := 1 2
TLIST := 4 8 16
TARGETS := $(foreach V,$(VLIST),$(foreach T,$(TLIST),v$V/thread$T/foo))
$(TARGETS): foo.cc $(HEADERS)
$(CXX) $(CXXFLAGS) -DTHREAD=$* -o $# $< $(LDLIBS)

Related

How to optimize this makefile?

I'm trying to optimize this makefile for adding PGM.
I created makefile needs to be optimized:
SOURCES = main.cpp logic.cpp
OBJECTS = $(SOURCES:.cpp=.o)
CC = CC
MODEL001 = FLAGA FLAGB
MODEL002 = FLAGC
CFLAGS001 = -c $(MODEL001:%=-D%)
CFLAGS002 = -c $(MODEL002:%=-D%)
PGMNUM = 001 002
all: PGM001 PGM002
PGM001:$(SOURCES)
$(CC) $(CFLAGS001) $(SOURCES)
$(CC) -o $PGM001 $(OBJECTS)
PGM002:$(SOURCES)
$(CC) $(CFLAGS002) $(SOURCES)
$(CC) -o $PGM002 $(OBJECTS)
Currently, I change the following variables when adding a PGM003.
ADD : MODEL003, CFLAGS003, PGM003:$(SOURCES)...
MODIFY : PGMNUM, all
Just by adding MODEL003 and PGMNUM, this makefile seems to work. How can I do it?
(pseudo code like this but does not work):
SOURCES = main.cpp logic.cpp
OBJECTS = $(SOURCES:.cpp=.o)
CC = CC
MODEL001 = FLAGA FLAGB
MODEL002 = FLAGC
MODEL003 = FLAGD FLAGE
PGMNUM = 001 002 003
CFLAGS$(PGMNUM) = -c $(MODEL$(PGMNUM):%=-D%)
all: $(PGMNUM:%=PGM%)
PGM$(PGMNUM):$(SOURCES)
$(CC) $(CFLAGS$(PGMNUM)) $(SOURCES)
$(CC) -o $PGM$(PGMNUM) $(OBJECTS)
By 'optimize', I take it you want to make it use less lines of code, rather than make it run faster. If so, you can use a function and eval as so:
SOURCES := main.cpp logic.cpp
PGMNUMS := 001 002 003
CC := CC
MODEL001 := FLAGA FLAGB
MODEL002 := FLAGC
MODEL003 := FLAGD
define func
CFLAGS$1 := -c $(MODEL$(p):%=-D%)
OBJECTS$1 := $$(SOURCES:.cpp=.$1.o)
$$(OBJECTS$1) : %.$1.o : %.cpp
$(CC) $$(CFLAGS$1) -o $$# $$^
PGM$1 : $$(OBJECTS$1)
$(CC) -o $$# $$^
endef
$(info --vv-- show generated code --vv--)
$(foreach p,$(PGMNUMS),$(info $(call func,$p)))
$(info --^^-- end of generated code --^^--)
#actually generate the calls:
$(foreach p,$(PGMNUMS),$(eval $(call func,$p)))
all: $(PGMNUM:%=PGM%)
Basically, you define a function func, and then run it for all values of $(PGMNUMS). Notice the use of $$ in the function definition -- in the function, $1 will expand to the first parameter. Items with $$var in front of them will expand to $var, rather than expanding at the time. I added a $(info..) which is useful to debug what you generate.

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".

GNU Make correct behaviour when including other makefiles

I have the following makefile in the root of the project:
Makefile
# Board version
# Available: 3
PI ?= 3
# Kernel binaries
ifeq ($(PI), 3)
KERNEL_IMG := kernel8.img
else ifeq ($(PI), 2)
KERNEL_IMG := kernel7.img
else ifeq ($(PI), 1)
KERNEL_IMG := kernel.img
else
$(error Unsupported Raspberry Pi version)
endif
KERNEL_ELF := $(patsubst %.img,%.elf,$(KERNEL_IMG))
# Directories/paths
BUILD_DIR := build
# Toolchain
TOOLCHAIN ?= aarch64-elf
OBJCOPY := $(TOOLCHAIN)-objcopy
LD := $(TOOLCHAIN)-ld
CC := $(TOOLCHAIN)-gcc
# Misc
LINKER_SCRIPT := linker.ld
# Flags
LDFLAGS := -T $(LINKER_SCRIPT)
ASFLAGS :=
CFLAGS :=
# Source files
C_SRC := $(wildcard *.c)
ASM_SRC := $(wildcard *.S)
# Include
include pi/$(PI)/mod.mk
# Object files
OBJECTS := $(patsubst %,$(BUILD_DIR)/%.o,$(C_SRC))
OBJECTS += $(patsubst %,$(BUILD_DIR)/%.o,$(ASM_SRC))
# Targets
.PHONY: all builddirs clean
all: $(BUILD_DIR)/$(KERNEL_IMG)
$(BUILD_DIR)/$(KERNEL_IMG): $(BUILD_DIR)/$(KERNEL_ELF)
$(OBJCOPY) $< -O binary $#
$(BUILD_DIR)/$(KERNEL_ELF): $(LINKER_SCRIPT) $(OBJECTS)
$(LD) $(OBJECTS) $(LDFLAGS) -o $#
$(OBJECTS): | builddirs
builddirs: $(BUILD_DIR)/pi/$(PI)
$(BUILD_DIR)/pi/$(PI):
mkdir -p $#
$(BUILD_DIR)/%.S.o: %.S
$(CC) -c $< $(ASFLAGS) -o $#
$(BUILD_DIR)/%.c.o: %.c
$(CC) -c $< $(CFLAGS) -o $#
clean:
$(RM) -r $(BUILD_DIR)
It includes pi/3/mod.mk
C_SRC +=
ASM_SRC += pi/3/start.S
$(BUILD_DIR)/pi/3/start.S.o: pi/3/start.S pi/3/include/cpu/sysregs.h
$(CC) -c $< $(ASFLAGS) -o $#
Now here's the problem: whenever I run 'make' in the root of a project, '$(BUILD_DIR)/pi/3/start.S.o' rule invokes, instead of 'all'. If I move 'include pi/$(PI)/mod.mk' to the very bottom of the root makefile, and replace 'C_SRC' and 'ASM_SRC' variables in 'pi/3/mod.mk' with 'OBJECTS += $(BUILD_DIR)/pi/3/start.S.o' and invoke 'make', this rule isn't even invoked, so I get an error that make doesn't know how to build start.S.o.
What am I doing wrong and what is the best way to handle this?
Make's default goal is the first target in your Makefile. In your case the first target is the one defined in the included Makefile: $(BUILD_DIR)/pi/3/start.S.o. Either invoke make all or move the all rule in your Makefile such that it becomes the first one, or tell make that the default goal is all:
.DEFAULT_GOAL := all
(see GNU make manual).

makefile read reused variable inside recipe

In trying to implement nonrecursive make, I have a Rules.mk which looks like:
############
# Enter Stack
############
sp := $(sp).x
dirstack_$(sp) := $(d)
d := $(dir)
.. setup things like OBJECTS_$(d), DEPS_$(d), TARGET_$(d), etc ...
############
# Exit Stack
############
-include $(DEPS_$(d))
d := $(dirstack_$(sp))
sp := $(basename $(sp))
One of the variables I wanted to set was:
INCLUDE_PATH_$(d) := -Isomething -Isomething/else ...
To be used in the compilation rule:
$(OBJDIR_$(d))/%.o : $(d)/%.cpp $(OBJDIR_$(d))/%.d
$(CC) $(CFLAGS) $(INCLUDE_PATH_$(d)) -o $# -c $<
But this doesn't work - $(INCLUDE_PATH_$(d)) doesn't get expanded until later - when $(d) is no longer has the value I need it to have in order for this to work. What's the way for me to do this properly?
You could use a target-specific variable
$(OBJDIR_$d)/%.o : INCLUDES := $(INCLUDE_PATH_$d)
$(OBJDIR_$d)/%.o : $d/%.cpp $(OBJDIR_$d)/%.d
$(CC) $(CFLAGS) $(INCLUDES) -o $# -c $<
The following is perhaps more standard / flexible (assuming CPPFLAGS isn't set to recursively expand) although it depends on your needs
$(OBJDIR_$d)/%.o : CPPFLAGS += $(INCLUDE_PATH_$d)
$(OBJDIR_$d)/%.o : $d/%.cpp $(OBJDIR_$d)/%.d
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<

Make: prerequisites in variable - secondexpansion

I would like to define a generic makefile that can be included by different makefiles like this (where a source t.c is compiled into t.o and archived in libl.a):
Makefile:
LIBS := libl
OBJS_libl := t
include c.mk
c.mk:
ALIBS := $(LIBS:%=%.a)
.SECONDEXPANSION:
all : $(ALIBS)
%.a : $$(patsubst %,%.o,$$(OBJS_$$(patsubst %.a,%,$$(#F))))
ar crs $# $(patsubst %,%.o,$(OBJS_$(#F:%.a=%)))
%.o : %.c
gcc -c $(#F:%.o=%.c) -o $#
The goal is that the prerequisites of the rule %.a expand as t.o for libl.a
This seems to work for explicit rules (if I replace %.a by libl.a) but not for implicit rules.
=> make: *** No rule to make target `libl.a', needed by `all'. Stop.
Can I achieve this and how please?
[Edit] The goal indeed is to have in the same directory several libraries like libl.a, each made with some of the objects:
LIBS := libl1 libl2
OBJS_libl1 := t1 u1
OBJS_libl2 := t2 u2
Makefile:
LIBS := libl.a
$(LIBS): t.o
include c.mk
c.mk:
%.a:
ar crs $# $^
%.o : %.c
gcc -c $< -o $#
EDIT:
LIBS := libl1.a libl2.a
$(LIBS):
libl1.a : t1.o u1.o
libl2.a : t2.o u2.o
Anything else?

Resources