How to get Target name from inside its' dependency Target? - makefile

Let us say that there is a Makefile with Targets such as:
.PHONY: app
target-a: my-dependency
...
target-b: my-dependency
...
my-dependency:
# Print the name of the target which depends on this during run-time
For example, when this command is made, I would like my-dependency to print target-a:
make target-a
For example, when this command is made, I would like my-dependency to print target-b:
make target-b

I think you shouldn't do that.
What you are saying is that my-dependency depends on target-a or target-b.
Depending on what exactly your real code looks like, you should consider having one instance of my-dependency, i.e. my-dependency-target-a and my-dependency-target-b, modify them according to your wishes and use the appropriate one for each target.
P.S.: If you just want to print the target name you could print the target name in target-a and target-b and then read in reverse. I.e. the my-dependency is from the target next on the console.

Related

How the location of target impacting the behaviour of makefile

I wrote a simple Makefile as below:
.PHONY: all A B
A:
#echo "in target A"
B:
#echo "in target B"
all: A B
the output is
in target A
but if I modified the Makefile as below:
.PHONY: all A B
all: A B
A:
#echo "in target A"
B:
#echo "in target B"
the output become
in target A
in target B
what part of Makefile manual should I read more carefully to understand the difference?
what part of Makefile manual should I read more carefully to understand the difference?
Which part of the manual to study depend on which make manual you are reading, but the explanation for the behavior you observe is simple: when you run make without designating any targets to build, make builds the default target, which is the first target appearing in the makefile whose name does not consist of a period ('.') followed by uppercase letters.
In particular, the target name "all" has no special significance to make. Its use is simply a widespread convention, and to make the all target work as you expect (that is, for it to be the default target), it must be positioned first in the makefile. There are makefiles that have an "all" target that is intentionally positioned elsewhere so that a different one is the default. When it's not the default, you can still build it explicitly, of course, by naming it on the command line: make all.
when running make without any goal, the first goal in out Makefile will be exectued.
You can manage the default goal using .DEFAULT_GOAL variable.
Read https://www.gnu.org/software/make/manual/html_node/Goals.html for more information

Is it ok to have a GNU Make target that claims to generate / update a certain target file but actually doesn't?

At present, I have a makefile that has:
a target which links an executable image file from a bunch of object files
a pattern rule target that compiles the various object files the linker target depends on
I want to make the following changes.
Instead of compiling the object files outright, I want the pattern rule target mentioned above to create (for each object file that needs updating) an empty object_file_name.update file. Essentially, this target's job would be to take stock of all object files that actually need to be recompiled.
Write a new target that launches a Perl process which finds all these object_file_name.update files and, for each object file that must be recompiled, compiles it in this Perl process.
I know how to do 2) ... that part is not giving me any trouble. The part I'm worried about is 1). The reason is that that target would basically have to claim to update any needed object files while, in truth, merely creating an .update file for each such object file but not the object file itself.
I think I could trick GNU Make into not starting to try to link anything before all the object files have been built by declaring my dependencies accordingly (pseudo-code, not a valid GNU Make snippet):
# Phony target that reads the *.update files created by the pattern rule target below and then
# compiles each object file for which an *.update file exists.
COMPILE_OBJECTS :
...
# Pattern rule target to take stock of all object files that need updating. Creates an *.update file for
# each object file that needs recompiling.
%.o : %.c :
...
$(EXE_FILE_TO_LINK) : $(LIST_OF_OBJECT_FILE_PATHS) COMPILE_OBJECTS
...
but I still worry that this might result in undefined behavior because my pattern rule target would basically be lying to GNU Make about updating the needed object files. Is my worry justified?
Basically, I want to interject an intermediate layer between GNU Make and the compiler so that GNU Make doesn't compile each object file separately. Instead, the compiling would be done in a single Perl process that has access to the complete list of object files that need to be compiled, allowing me to do various fancy things that I couldn't do if GNU Make controlled compilation directly.
Yes, it's legal and I often use this pattern.
Consider the case where you only want to kick off a long build step if a file has changed.
target: config-file
target-creator $< -o $#
Now let's say we can't give make the dependencies for config-file (because the config file creation step lacks a dependency listing ability (BAH!)).
.PHONY: FORCE
FORCE: ;
config-file: FORCE
config-creator -o $#.tmp
cmp $#.tmp $# || mv $#.tmp $#
We ask make to build target
Make first has to build config-file
Make will always run the recipe for config-file,
as its dependency FORCE is out of date (being phony)
CRUCIALLY we only update config-file if config-creator decides something has actually changed
If cmp decides config-file.tmp and config-file are the same, and the last line of the recipe completes with no error
OTOH if cmp detects a mis-compare, it fails, and the shell goes on to execute the mv.
After running the recipe for config-file, make does actually check config-file's modification time. IF config-file has become younger than target, only then will target-creator be run.
The subtlety here is that even though config-file's recipe runs every time, config-file itself is not phony.

Recipe that produces multiple targets

In our makefile, we have one recipe that links together all our object and library files to make an executable (an .elf file). As a side effect, this step also produces a map-file and an Intel .hex file:
$(ELF_FILE) : <list of dependencies here>
<linker command line>
Until now, since we never actually had a $(MAP_FILE) or a $(HEX_FILE) target, when ever another target depended on one of the $(ELF_FILE)'s side products, we simply declared it to be dependent on $(ELF_FILE), even if the recipe of that target didn't want to access the $(ELF_FILE) itself at all. For instance:
# Target that needs map-file, which is a side product of the $(ELF_FILE) target.
$(TARGET_THAT_NEEDS_MAP_FILE) : $(ELF_FILE)
<build-recipe>
# Target that needs hex-file, which is also a side product of the $(ELF_FILE) target.
$(TARGET_THAT_NEEDS_HEX_FILE) : $(ELF_FILE)
<build-recipe>
We have recently found out that a recipe can be used for more than one target, like so:
$(MAP_FILE) $(HEX_FILE) $(ELF_FILE) : <list of dependencies here>
<linker command line>
With this new-found knowledge, we figured we could get rid of the above "hack" and just directly state each target's direct dependencies:
$(TARGET_THAT_NEEDS_MAP_FILE) : $(MAP_FILE)
<build-recipe>
$(TARGET_THAT_NEEDS_HEX_FILE) : $(HEX_FILE)
<build-recipe>
Having implemented these changes, we now observe an odd effect that makes us suspect that we've either misunderstood this multiple-targets-one-recipe feature of make, or we're not using it correctly. The odd effect is that the recipe that produces the .elf, .map and .hex files now appears to run twice. This doesn't seem to have caused any immediate problems, but it does seem to indicate that something is fishy here. So my question, can our new approach work at all, or should we stick to the hack I described above?
EDIT: We're running our make in a multi-threaded manner (i.e. with -j).
It might be that when make is trying to update a target (whether it is $(MAP_FILE), $(HEX_FILE) or $(ELF_FILE), it does not know that its recipe will also update another target, therefore it starts a recipe for that one too, even if it's the same.
Of course, that would only happen when using the -j option. (Did you had the possibility to try without ?)
To illustrate :
$(TARGET): $(ELF_FILE) $(MAP_FILE)
<update target>
Here make will try to update $(ELF_FILE) and $(MAP_FILE) and fire the recipe twice. (That should also applies if the dependencies are on different target, as long as the targets are updated by a one execution of make and that there is no bottlenecks between them.
I'm not completely sure about that, though, make might be able to know that this is the same recipe.
======
This answer might be of use to you.
Specifically :
However, if your output files and your input file share a common base,
you CAN write a pattern rule like this:
%.foo %.bar %.baz : %.boz ; $(BUILDIT)
Strangely, for implicit rules with multiple targets GNU make assumes
that a single invocation of the recipe WILL build all the targets, and it will behave exactly as you want.
MadScientist
It refers to that part of the make manual :
Pattern rules may have more than one target. Unlike normal rules, this
does not act as many different rules with the same prerequisites and
recipe. If a pattern rule has multiple targets, make knows that the
rule’s recipe is responsible for making all of the targets. The recipe
is executed only once to make all the targets. When searching for a
pattern rule to match a target, the target patterns of a rule other
than the one that matches the target in need of a rule are incidental:
make worries only about giving a recipe and prerequisites to the file
presently in question. However, when this file’s recipe is run, the
other targets are marked as having been updated themselves.
EDIT:
Gnu Make has now gained a feature that would support this usecase (in version 4.3) : grouped explicit targets. It allows make to be aware that one recipe generate several targets, and it used like this (from the gnu make manual) :
foo bar biz &: baz boz
echo $^ > foo
echo $^ > bar
echo $^ > biz
foo, bar, and biz are generated by this rule (note the use of &: instead of :.
Full documentation : https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html ("Rules with Grouped Targets")

How to create a generic Makefile that checks sources for any given target name?

I want to have a generic Makefile that takes any target name and for that target name, checks to see if certain sources exist and then executes some commands. So for example I want to be able to enter:
make mytarget
then make should check to see if mytarget.src1 and mytarget.src2 exist, and if so execute some commands.
I have the following makefile:
%:
$(MYCOMMANDS) $*.scr1 $*.scr2
the only problem with this is that it doesn't check to see if $.scr1 and $.scr2 exist before running $(MYCOMMANDS). This is understandable because I haven't specified any dependencies. However when I try:
%: $*.src1 $*.src2
$(MYCOMMANDS) $*.scr1 $*.scr2
it now doesn't ever run $(MYCOMMAND) and says no rule to make the specified target.
Can someone please explain why in my second code make cannot find the target? Also, how can I achieve the behavior that I want?
The correct way to write a pattern rule is to use the pattern (%) in both the target and the prerequisites:
%: %.src1 %.src2
$(MYCOMMANDS) $^
See Pattern Rules in the GNU make manual. Also see Automatic Variables. By the way, the third paragraph in the second link will explain why your second attempt, using $* in the prerequisites, cannot work.
I was able to get the behavior I want using the MAKECMDGOALS variable. So:
$(MAKECMDGOALS): $(MAKECMDGOALS).src1 $(MAKECMDGOALS).src2
$(MYCOMMANDS) $(MAKECMDGOALS).scr1 $(MAKECMDGOALS).scr2
does what I am looking for. It checks to make sure .src1 and .src2 exist. If they don't make will report an error and if they do it will run $(MYCOMMANDS).

make variables that depend on a target

I have a Variable in make that is dependant on a file that must be built before the variable can be set, is there a way to get this to work?
parsable_file: dependancies
commands to make parsable_file
targets=$(shell parse_cmd parsable_file)
$(targets): parsable_file
command to make targets
.phony: all
all:$(targets)
If I run $ make parsable_file && make all this will work (I get an error that parse_cmd cant find parsable_file but it works), but just make all will not work. Is there a Make idiom for this?
Set the variable in a file that you include in the main makefile and include a rule in the main makefile for how to build it (the one you already have should be fine).
I believe that will do what you want.
See Including Other Makefiles and How Makefiles Are Remade (which is linked from the first section) for more details on this concept.
Also, unless parseable_file has a usage independent from that parse_cmd call, it should be possible to do the creation and the parsing at the same time and just have the resulting makefile contain the correct value for $(targets) in one step.

Resources