How to ignore dependency check in makefile - makefile

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.

Related

Invoke target inside ifeq/ifneq in another target

I am new to writing Makefiles, is it common or "good practice" to invoke targets inside ifeq or ifneq from another target?
This is the original Makefile. I can run my_test by make my_test:
build : target1 target2
...
my_test : | prereq1 prereq2
COMMAND_TO_RUN_MY_TEST
Now, I want to add a condition such that every time it builds, it checks the condition first and then decide whether or not to run the test:
build : target1 target2 run_check
...
my_test : | prereq1 prereq2
COMMAND_TO_RUN_MY_TEST
OLD_VERSION := $(shell COMMAND_TO_RETRIEVE_THE_OLD_VERSION)
NEW_VERSION := $(shell COMMAND_TO_RETRIEVE_THE_NEW_VERSION)
run_check :
ifneq ($(NEW_VERSION), $(OLD_VERSION))
echo "Version updated. Run test"
$(MAKE) my_test
else
echo "Same version. Skip test"
endif
This works but it feels unncessary calling another instance of make here. It does not look like any Makefile has logics like this from the examples I see. From my understanding, "target" is like a function. All I want to do is to call a function inside another function in an "if" statement. This feels normal in other languages but seems to be not so common in Makefile. Want to see if there are other ways to achieve this. All suggestions are appreciated!
If you already know whether you want to run the tests when you invoke make, before you start to build anything, you can just do this:
OLD_VERSION := $(shell COMMAND_TO_RETRIEVE_THE_OLD_VERSION)
NEW_VERSION := $(shell COMMAND_TO_RETRIEVE_THE_NEW_VERSION)
ifneq ($(NEW_VERSION), $(OLD_VERSION))
CHECK = run-check
else
CHECK =
endif
build : target1 target2 $(CHECK)
All I want to do is to call a function inside another function in an "if" statement. This feels normal in other languages but seems to be not so common in Makefile.
A makefile is not a programming language. It's a language for defining a directed acyclic graph. It's a mistake to think of it like a procedural language where rules are "functions" that you can "call". That leads you down all sorts of incorrect mental pathways.
A makefile defines a graph: when you run make it will first read all the makefiles to create a representation of that graph in memory. Then after it's complete, it will walk the graph starting at whatever goal target node(s) were given, and operate on those nodes.

How can I pass a argument to a makefile dependency?

I have the following Makefile where the all make target depends on a separate setup make target that also takes an argument. However when I make all the setup target is not invoked with the argument
setup:
...command
clean:
...command
all: setup myarg=value clean myarg=value
#echo "setup & clean"
I think what you're asking is if a prerequisite can inherit a target-specific variable. In which case, yes it can -- Note, in your example you tried to intersperse the target specific variables and the prerequisites, which you can't do. But beware -- this has sharp sticks attached. Consider the following makefile:
all:
setup:
#echo "building $#: myarg=$(myarg)"
all: myarg:=value
all: setup
#echo "building $#: myarg=$(myarg)"
blah: setup
#echo "building $#: myarg=$(myarg)"
If I do make all, I get:
tmp> make all
building setup: myarg=value
building all: myarg=value
Which is what you want. But if I do make blah, then setup is run as a prerequisite of blah, and does not have the value set as you might expect. It will not be rebuilt for main, even though the variable is different:
tmp> make blah all
building setup: myarg=
building blah: myarg=
building all: myarg=value
See the make manual for more details
The command line of the make program is not free-form. You can't just pass it a bunch of stuff and have that "stuff" passed through make to appear somehow inside your recipes. make can only take arguments that it's defined to take: all arguments (not options) are either targets or variable assignments. See the documentation or the man page.
It is not possible in general to pass arbitrary values on the make command line. However, as I said, make does allow variables to be set on its command line.
If you run make setup myarg=value then this will set the make variable myarg to have the value value, and ask make to build the setup target.
So, if you write your makefile:
setup:
...command $(myarg)
referencing the make variable myarg, then it will "work" (I guess, you haven't made clear exactly what you want to run using myarg).

copy value of an automatic variable to another variable in makefile

I'd like to do rule variable contain the value of $# in the attribution line, instead of the reference. Example:
rule=$#
all:
#echo "Running Rule: $(rule)"
rule1: all
#echo "Do something here"
rule2: all
#echo "Do another thing here"
My expected result would be:
Running Rule: rule2
Do another thing here
when run make rule2. But the result I have is:
Running Rule: all
Do another thing here
Is it possible to make this attribution?
[edit]
In others words, what I need is get parent target name, i.e. the parameter of the make command typed by the user in the terminal console.
No. $# is always set to the current target, never to the parent target (why would it do that?)
The best option available to you (given the limited description we have of what you're really trying to do) is to use target-specific variables:
all:
#echo "Running Rule: $(rule)"
rule1: rule = rule1
rule1: all
#echo "Do something here"
rule2: rule = rule2
rule2: all
#echo "Do another thing here"

Makefile to execute a sequence of steps

I use make to execute a series of process steps. Each step depends on the success of the previous one. Once completed a step, I touch a file with the name of the step into a separate directory.
Here is one example to explain the concept:
VPATH=steps
step1:
#echo "do some actions with $#"
#touch $(VAPTH)/$#
step2: step1
#echo "do some actions with $#"
#touch $(VPATH)/$#
step3: step2
#echo "do some actions with $#"
#touch $(VPATH)/$#
It basically works, however there is a weakness: it checks for targets either in "." and in VPATH. If you erroneously touch ./step1 in the working directory "." make gets confused. I'd like to know if I can avoid any ambiguity on checking the targets/prerequisites, but I'd like to keep using
make step3
and not
make steps/step3
Any other Makefile example to get the same objective is welcome. Thanks in advance for the help!
A fundamental rule of makefiles is that you cannot create targets that are different from what makes thinks they should be. Make puts the name of the target that it wants you to build in the $# variable. Your rule must create a target with that name, or make will not work properly. In your example you're creating a target with the name $(VPATH)/$# which is not the same as $#, so that's not right.
Another rule of makefiles is that VPATH cannot be used (correctly) to find derived targets. It can only be used to find source files.
I recommend you change the variable name from VPATH to something like STEPDIR, just to avoid confusion. Then you can write a makefile like this (note this is untested and may need to be tweaked). Look up Static Pattern Rules in the GNU make manual to understand what I'm doing in the commented part:
STEPDIR := steps
STEPS := step1 step2 step3
# Translate from local to subdirectory
.PHONY: $(STEPS)
$(STEPS): %: $(STEPDIR)/%
$(STEPDIR)/step1:
#...
#touch $#
$(STEPDIR)/step2: $(STEPDIR)/step1
#...
#touch $#
$(STEPDIR)/step1: $(STEPDIR)/step2
#...
#touch $#

Why Makefile include should be after all: target?

I've been using Makefile and to keep some stuff sepparate I decided to include a new common makefile. The problem I faced is that my First makefile looks like this:
Filename Makefile.test
include ./Makefile.a
all: a b c
b:
#echo "b"
c:
#echo "c"
Filename Makefile.a
a:
#echo "a"
When I execute my makefile: make -f Makefile.test I only get "a" printed out and it finishes.
The only way to make it work is place the include bellow (anywhere) the all: target
Is there a reason why this behaves liks this?
Thanks!
When you say this:
include ./Makefile.a
make just pulls Makefile.a into the current Makefile in the same way that #include <x.h> does in C: it inserts the contents of Makefile.a to replace the include statement and keeps going. The result is that make sees this when it starts figuring out what to do:
a:
#echo "a"
all: a b c
b:
#echo "b"
c:
#echo "c"
So the first target in source-order will be a and since you didn't specify a target, make will use the first one. That's where your result comes from.
You could explicitly specify the all target if you wanted:
make -f Makefile.test all
That would use the all target regardless of where it appears in the Makefile.
If you're using GNU Make, then you could use .DEFAULT_GOAL to specify a default target inside Makefile.test and then you wouldn't have to worry about the order:
include ./Makefile.a
all: a b c
b:
#echo "b"
c:
#echo "c"
.DEFAULT_GOAL := all
Thanks to Idelic for the reminder about this.

Resources