I would like a Makefile variable to hold a list of tests but run each test with a different flag and have the ability to run all tests or selectively one from the command line. Here's what I have so far and I am not sure how to add more tests but prevent creating individual variables for each test. In the example below I can say make all or make run_tests TESTS=block_test_A to either run all tests or a specific test. This works but if I were to add another 10 tests I would like to modify only TESTS string and add them there instead of adding TEST4, TEST5 and so on. Is there a clever way to make a loop that can parse the list of tests in TESTS and create the variables. I tried a couple of variations but couldnt get it to work. sim_design is target not shown that will execute the compile/sim using the values in the Makefile variables SIM_FLAGS and SIM_LOG. Thanks.
TESTS := block_test_A block_test_B block_test_C
TEST1 := $(word 1, $(TESTS))
$(TEST1) : SIM_FLAGS:= "$(SIM_FLAGS) -top $(TEST1)"
$(TEST1) : SIM_LOG:= "logs/$(TEST1).log"
TEST2 := $(word 2, $(TESTS))
$(TEST2) : SIM_FLAGS:= "$(SIM_FLAGS) -top $(TEST2)"
$(TEST2) : SIM_LOG:= "logs/$(TEST2).log"
TEST3 := $(word 3, $(TESTS))
$(TEST3) : SIM_FLAGS:= "$(SIM_FLAGS) -top $(TEST3)"
$(TEST3) : SIM_LOG:= "logs/$(TEST3).log"
$(TESTS):
$(shell mkdir -p logs)
#(echo Running TEST $# with SIM_FLAGS=$(SIM_FLAGS) SIM_LOG=$(SIM_LOG))
$(MAKE) sim_design SIM_FLAGS=$(SIM_FLAGS) SIM_LOG=$(SIM_LOG)
run_tests: $(TESTS)
all:
#(echo Running Regression on $(DESIGN_TOP) with following list of tests $(TESTS))
#(echo To run a single test generating a dump use: make run_tests TESTS=\"valid_test_name\" REGRESS=0)
$(MAKE) run_tests REGRESS=1
This seems like exactly what automatic variables were created for...?
What's wrong with this:
TESTS := block_test_A block_test_B block_test_C
SIM_FLAGS += -top $#
SIM_LOG = logs/$#.log
$(TESTS):
#mkdir -p logs
#echo Running TEST $# with SIM_FLAGS=$(SIM_FLAGS) SIM_LOG=$(SIM_LOG)
$(MAKE) sim_design SIM_FLAGS="$(SIM_FLAGS)" SIM_LOG="$(SIM_LOG)"
Other things:
You never want to use the make shell function inside a recipe.
I don't really see the point in putting echo into a subshell with (...)
Related
Is there any way to create multiline functions out of Makefile commands?
I know we can do something like this to encapsulate a recipe (of shell commands) as a function:
define function
#echo 'First argument: $1'
#echo 'Second argument: $2'
endef
.PHONY test-function
test-function:
$(call function, a, b)
With this, running make test-function will give the output:
First argument: a
Second argument: b
I also know we can use the call directive with one-line macros consisting of make syntax/directives (example taken from here):
pathsearch = $(firstword $(wildcard $(addsuffix /$(1),$(subst :, ,$(PATH)))))
LS := $(call pathsearch,ls)
But let's say I wanted to call a macro made up of multiple make commands, including conditionals. How would I achieve that?
When I run make build-type=API build with the following Makefile:
define check-arguments
ifeq ($1, api)
#echo 'Building API'
else ifeq ($1, service)
#echo 'Building Service'
else
$$(error 'Build type must be API or Service')
endif
endef
.PHONY: build
build:
$(call check-arguments, $(build-type))
#echo 'Starting build'
...
...
I keep getting the error Makefile:13: *** missing separator. Stop..
You can use eval. The GNU Make Manual states:
...it [eval] allows you to define new makefile constructs that are not constant; which are the result of evaluating other variables and functions.
eval will parse ifeq and $(error) as part of the makefile instead of as commands for the recipe.
One thing to keep in mind is that eval parses its input by itself, without regard for the surrounding syntax of the makefile. This means that you cannot use it to define only part of a rule, like in your example:
build:
$(call check-arguments, $(build-type))
If we use $(eval $(call check-arguments, $(build-type))), then eval will parse the expansion of check-arguments by itself and complain because the recipe has no target. (See this answer.) The solution here is to include build: in check-arguments somehow.
While having $(eval) is fine, I would like to recommend a different approach, based on target resolution instead of conditionals, like so:
$ cat Makefile
supported_build_types := api service
.PHONY: build
build: build-$(build-type)
.PHONY: $(addprefix build-,$(supported_build_types))
$(addprefix build-,$(supported_build_types)): build-%:
#echo 'Building $*'
#echo 'Starting build'
.PHONY: build-
build-:
$(error Must provide build-type of: $(supported_build_types))
.PHONY: build-%
build-%:
$(error Unsupported build type: $*. Must be one of: $(supported_build_types))
This can allow easier extensibility and maintenance while keeping away nuisances of $(eval)s, $(call)s and appropriate escaping.
Running supported build types:
$ make build build-type=api
Building api
Starting build
$ make build build-type=service
Building service
Starting build
Invalid build type:
$ make build build-type=foo
Makefile:17: *** Unsupported build type: foo. Must be one of: api service. Stop.
Missing build type:
$ make build
Makefile:13: *** Must provide build-type of: api service. Stop.
I'd like to ignore dependency check in makefile.
For example, please look this code.
test:: test1 test2
#echo "test"
test1:: back3
#echo "test1"
test2:: back3
#echo "test2"
back3::
#echo "back3"
Results of "make test"
back3
test1
test2
test
But I want to get below result.
back3
test1
back3 <---- I want to run back3 again.
test2
test
How can I do this?
You could use Make recursively:
test: test1 test2
#echo "test"
test1:
$(MAKE) back3
#echo "test1"
test2:
$(MAKE) back3
#echo "test2"
back3:
#echo "back3"
or use a "canned recipe":
define run_back3
#echo "back3"
endef
test: test1 test2
#echo "test"
test1:
$(run_back3)
#echo "test1"
test2:
$(run_back3)
#echo "test2"
You write
I'd like to ignore dependency check in makefile.
, by which you seem to mean that you want all the prerequisites of each target to be rebuilt prior to building that target, specifically for that target, such that prerequisites may be built more than once.
make simply does not work like that. On each run, make builds each target at most once. Prerequisite lists help it determine which targets need to be built, in which order, but designating a prerequisite should not be viewed as calling a subroutine.
If indeed you want something that works like calling a subroutine, then it needs to be expressed in the rule's recipe, not its prerequisite list. Your other answer presents two alternatives for that. Of those, the recursive make example is more general; the one based on defining a custom function is specific to GNU make.
I have the following Makefile entry:
TEST_DIRS = abcd pqr xyz
test_lib :
for dir in $(TEST_DIRS); do \
$(MAKE) -C $$dir; \
done
run :
./abcd/test/abcd_test.o --log_level=message
./pqr/test/pqr_test.o --log_level=message
./xyz/test/xyz_parser_test.o --log_level=message
test : test_lib run
I don't want to write 3 separate commands for run target instead make it generic. So that everytime a new test file gets added, I dont want add a new command under run target. Can somebody help me?
TESTS := $(addprefix TEST_, $(TEST_DIRS))
run: $(TESTS)
TEST_%:
./$*/test/$*_test.o --log_level=message
Assuming the naming scheme is consistent (and those are just oddly named binaries and not actually object files) then something like this should work:
Using a shell loop:
run :
for name in $(TEST_DIRS); do \
./$$name/test/$${name}_test.o --log_level=message; \
done
Using make foreach:
run :
$(foreach name,$(TEST_DIRS),./$(name)/test/$(name)_test.o --log_level=message;)
The question is about parallel making w/ GNU makefile.
Given a folder structure as below, the goal is to deliver a makefile that it supports make release/debug/clean in parallel.
project folder structure:
foo
+-foo1
+-foo2
+-foo3
The makefile may be sth like:
SUBDIR = foo1 foo2 foo3
.PHONY $(SUBDIR) release debug clean
release: $(SUBDIR)
$(SUBDIR):
$(MAKE) -C $# release
debug: $(SUBDIR)
#below is incorrect. $(SUBDIR) is overriden.
$(SUBDIR):
$(MAKE) -C $# debug
..
Sub directory list are set as phony targets for parallel making. but it lost the information of original target (release, debug, clean etc).
One method is to suffix the names for the directories and recover it in commands, but it is weird. another method might be to use variables, but not sure how to work it out.
The questions is:
How to write the rules for directories, that supports parallel making w/ different targets (release/debug/clean)?
Any hints are greatly appreciated.
Setting variables on the command line certainly works. You can also use MAKECMDGOALS (see the GNU make manual):
$(SUBDIR):
$(MAKE) -C $# $(MAKECMDGOALS)
I would like a makefile where I can call:
'make' / 'make <subdir>' / 'make clean' / 'make <subdir> clean'
But I do not want it to attempt to resolve clean when called on a subdir!
Here's an example of my makefile:
SUBDIRS := a b c
all :
#echo building a b and c
clean :
#echo cleaning a b and c
$(SUBDIRS) :
make - C $# $(MAKECMDGOALS)
All the calls work well except make <subdir> clean which calls make -C <subdir> clean, but then attempts to also resolve target clean separately. How can I get make to stop processing later targets?
To both answers:
thank you for your explanation. it is helpful to know what is and what is not meant to be done. i will not attempt this anymore.
Sigh
Yes, you can do this, but it'll be an ugly hack and totally contrary to the way Make is designed to work.
The set of targets you pass to Make is a set of targets, not a structured command with syntax. Make is expected to build them all. If the makefile includes a recipe for the target foo, then Make should build the target foo a certain way, regardless of whether it is invoked as Make foo or Make foo bar or Make bar foo. What you are attempting to do breaks the accepted behavior of Make, so you should try a different approach.
If you still wanted to do it, you could do it like this:
SUBDIRS := a b c
.PHONY: clean
ifneq ($(filter $(SUBDIRS), $(MAKECMDGOALS)),)
$(SUBDIRS) :
#echo make - C $# $(MAKECMDGOALS)
clean:
#: # do nothing
else
all :
#echo default
clean :
#echo cleaning
endif
I fully agree with Beta's statements on misusing make. Another way of achieving what you want, would be to introduce explicit targets for cleaning the subdirectories. This way, for instance, you can call make clean_<subdir>.
SUBDIRS := a b c
all:
#echo building a b and c
clean:
#echo cleaning a b and c
$(SUBDIRS):
make - C $#
$(addprefix clean_, $(SUBDIRS)): clean_%:
make -C $* clean