Using Makefile variable before definition in included file - makefile

I've encountered a little problem during my Makefile learning adventure.
I have prepared two scripts. The first one is the main Makefile:
all:
#echo $(COMPONENTNAME)
include ~/Projects/tests/mk
And here's the mk file
COMPONENTNAME:=ISeeYou
Now, when I run
make all
I get
ISeeYou
I am not sure why... I was convinced that a variable must be defined before it is used. And the include is after COMPONENTNAME is being used. My suspicion is that all of the includes are done first, and then the target creation is started. Is that the case?

My suspicion is that all of the includes are done first, and then the target creation is started.
Yes, you are right.
All global sections in Makefile should be completely parsed before make is able to decide, which targets(and in which order) should be built. Target's recipes are evaluated only when it is needed to build target. This is explicitely stated in make manual:
The other way in which make processes recipes is by expanding any variable references in them. This occurs after make has finished reading all the makefiles and the target is determined to be out of date; so, the recipes for targets which are not rebuilt are never expanded.

Related

Makefile dynamic variables as prerequisites

Perhaps it's something that I'm getting wrong. Basically my task is to use make to automate a build, deploy, starting, stopping of different services.
One of the things that I'm trying to do is to have a variable as a target prerequisite, however that variable has to be changed in another target.
Here's a basic sample of what I'm trying to do:
IMAGE_COUNT=-1
count_images:
$(eval IMAGE_COUNT=5)
_should_build: $(if $(findstring $(IMAGE_COUNT),0), build,)
build:
...some procedure to build...
start: _should_build
...some procedure to start a service...
Obviously the $(IMAGE_COUNT) in _should_build check will stay as -1, but what I want is to have the $(IMAGE_COUNT) become a 5 during the prerequisite check. A thing to note is that I cannot place the counting of images outside the count_images target.
Does anyone know if this is possible at all?
Perhaps it's something that I'm getting wrong.
That "something" is called an evaluation order.
One of the things that I'm trying to do is to have a variable as a target prerequisite, however that variable has to be changed in another target.
Not a target, but a recipe. The recipes are preprocessed before execution. While the prerequisites are preprocessed on the first pass. In fact, changing the value of a make's variable inside a recipe in 90% of cases is a mistake. (Also remember that all preprocessing is done before feeding the recipe to the shell).
Does anyone know if this is possible at all?
Everything is possible, of course, but not this way.
A thing to note is that I cannot place the counting of images outside the count_images target.
Most probably, you can.
Anyway, the point is that some shell script (a recipe, or a part of a recipe) should return a number. However, such return values cannot be stored in a make's variable. Re-think your design and find another way for communication between your targets.

Makefile - does using .PHONY for running commands was intended when creating make?

I know we can set up commands such as all, clean, install etc in makefile and use .PHONY to tell make they're not associated with files.
But I was wondering - when creating make and makefile - was this kind of use (to run such commands) combined with .PHONY designed for that purpose? Or maybe .PHONY was added later to easily extend make to support those kind of commands?
I also read this but there wasn't anything else there except the regular known usage.
Thanks!
I do not know the history of GNU make.
The use of .PHONY is exactly what you suspect: have targets (which can thus be goals, or commands, if you wish) that are not files, and that work even if, by accident, a file with the same name exists. It is one single and clearly defined purpose.
In certain cases you want to force a target file to be re-built even if it is up-to-date, and you can declare it a prerequisite of .PHONY for this purpose, but it is frequently the sign that your makefile is not what it should be.
Another frequent situation is the grouping of several targets (real or phony) as prerequisites of one single other phony target.
But in both cases, we can say that the resulting phony target is a kind of command. In the first case it is a command that forces the build of a file. In the second it is a kind of alias for a series of actions.

Makefile: how to detect changes within the makefile itself?

I'm aware of the idea of using recursive makefiles. Will the subsequent makefiles such as the following be called be updated solely on any changes to the subsequent makefiles themselves?
e.g.:
#parent makefile. no changes here.
subsystem:
cd subdir && $(MAKE)
If the makefile within subdir was changed such that the following does not hold (e.g. only a gcc flag was changed), then will the object files be updated?
The recompilation must be done if the source file, or any of the
header files named as dependencies, is more recent than the object
file, or if the object file does not exist.
The only reason that, as written, make even runs that rule at all is because subsystem and subdir do not match.
If a subsystem file or directory were ever to be created in that directory that rule would cease to function.
If .PHONY: subsystem1 were added that problem would be fixed and that rule would always be run when listed on the command line (i.e. make subsystem). (As indicated in the comments .PHONY is a GNU Make extension. The section following the linked section discusses a portable alternative. Though it is worth noting that they are not completely identical in that .PHONY has some extra benefits and some extra limitations.)
In neither of those cases is the subsystem target paying any attention to modification dates of anything (as it lists no prerequisites).
To have a target depend on changes to a makefile you need to list the makefile(s) as prerequisites like anything else (i.e. subsystem: subdir/Makefile). Listing it as .PHONY is likely more correct and more what you want.
No, nothing in make itself tracks non-prerequisites. So flag changes/etc. do not trigger rebuilds. There are ways to make that work for make however (they involve storing the used flags in files that themselves are prerequisites of the targets that use those flags, etc.). There are questions and answers on SO about doing that (I don't have them ready offhand though).
Other tools do handle flag changes automatically however. I believe Electric Cloud's tools do this. I believe CMake does as well. There might also be others.
Recursive makefiles are executed whether or not anything changed. This is exactly one of the objections pointed out by Paul Miller in his Recursive make considered harmful paper from almost 20 years ago.
With that said, a makefile is just like any other dependency and can be added to a production rule to trigger that rule if the makefile is altered.
You can include the makefile as a dependency, the same as any other file:
mytarget.o: mytarget.c Makefile

how do makefile dependencies work?

I am currently confused as to how makefile targets work. I have a current understanding, and I don't know if it is correct because the tutorials I've been reading aren't very clear to me. Here is my current understanding
when you run 'make' in the terminal, the makefile utility finds the first target in the makefile and tries to run it, but before doing so it looks at all of the dependencies in the file
(this is where I start getting confused): If the dependency is a target in the makefile, but does not exist as a file in the makefile's directory, make simply runs the target. If the dependency is a file name, but not a target in the makefile, the utility checks for the existance of the file, and if the file doesn't exist, the utility yells at you. If the dependency is a file that exists in the directory AND a target, the target is run provided that any of the files that the file-target depend on are newer than the associated file.
Do I have it down right? Is it simpler than I'm making it out to be?
You have it right, more or less, but it can be stated a little more clearly. You're right about how make chooses the initial target, except of course if the user specifies a specific target on the make command line then that one is used instead of the first one.
Then make basically implements a recursive algorithm for each target, that works like this:
Find a rule to build that target. If there is no rule to build the target, make fails.
For each prerequisite of the target, run this algorithm with that prerequisite as the target.
If either the target does not exist, or if any prerequisite's modification time is newer than the target's modification time, run the recipe associated with the target. If the recipe fails, (usually) make fails.
That's it! Of course, this hides a number of complex issues: in particular item #1 (finding a rule) can be complex in situations where you have no implicit rule for the target. Also behaviors such as what to do when a rule fails can be modified.
But that's the basic algorithm!
for the question you asked your understanding is correct !!
If you are still confused have a look at this :: http://www.jfranken.de/homepages/johannes/vortraege/make_inhalt.en.html
once comfortable move to other more complete manuals like the GNU manual for make.

Multiple instances of the same target for make

I am working on a Makefile written by someone else in my lab and I see the following:
include /path/to/Makefile.inc
TARGET_A: pre_req_1 pre_req_2
cmd_1;
cmd_2;
...
When I look at /path/to/Makefile.inc I see that it also includes a target TARGET_A
with other pre-requisites and recipes.
Is this a normal practice? (and would it work?) Would make treat the two rules separately? Can we safely make any assumptions about which one is considered first?
It is a dangerous practice since it is confusing to know which one is applied.
The "include" will act has if the included file content was in the Makefile, and the targets will be overrided while reading the Makefile. So, the last target will be honored, and the first one (in the included file) will be ignored.

Resources