Include Makefile and Echo Variables Inside Multiple Makefiles - makefile

Inside a Makefile I have recently had to look at, it includes this include $(MAKERULES)
Now to me, I would think somewhere at the top of the makefile it has MAKERULES = xyz but it does not. So I print out MAKERULES
test:
#echo "Rules: $(MAKERULES)"
Then I do make test. It runs and it prints out another Makefile Location, Makefile2.
X/Y/Z/Makefile2 path. I go inside this Makefile and attempt to write out some echo statements so I can see what is printing, but nothing prints out.
Is it possible to print out variables from another Makefile (Makefile2) that my local Makefile (Makefile) references to?

Yes, it is possible. You haven't shown us your attempt to display those variables, so we can't tell you why it didn't work. (Well, I can't.)
Here is how I'd do it:
$(info the variable FOO contains $(FOO))
If you want to do this for several variables:
$(foreach X, FOO BAR BAZ, $(info $(X) is $($(X))))
And the list of all currently defined global variables is .VARIABLES, so you can use "$(.VARIABLES)" in place of "FOO BAR BAZ" to print all of them.

Related

Accessing exported variables in a shell function

Is there a way to make use of exported variables in shell function without the need for sub-make?
Take the following example.
FOO := BAR
.EXPORT_ALL_VARIABLES:
.PHONY: buzz
buzz:
$(info buzz)
$(error finish)
.PHONY: fizz
fizz: $(if $(shell echo $$FOO),buzz,)
$(info fizz)
$(MAKE) fizz
If I run the fizz target like so I get the following output.
$ make fizz
fizz
make fizz
make[1]: Entering directory '/home/jshbrntt/test'
buzz
Makefile:8: *** finish. Stop.
make[1]: Leaving directory '/home/jshbrntt/test'
make: *** [Makefile:13: fizz] Error 2
As you can see only the second run of make fizz had the shell function expanded and cause the buzz target to also run.
Is there a way to make use of exported variables in shell function without the need for sub-make?
No.
Remember always that GNU make functions such as $(shell) are evaluated while the makefile is being parsed, not when make runs recipes (refer to section 3.7 of the manual), regardless of where in the makefile the $(shell) invocation appears. make determines which variables are exported based on its own environment and the combination of all rules and export / unexport directives in the makefile, potentially including rules and / or directives generated via $(shell) and other functions. In this way it ensures that it is consistent about the environment used to execute recipes.
Although it is conceivable that make would expose expose intermediate forms of its export list to the $(shell) function (and its documentation doesn't clearly specify whether it does so), as a practical matter it would be surprising for it to do so, and your experiment shows that it does not do. And although the manual does not explicitly speak directly to the question, it should be noted that its documentation of export, etc. is in a section entitled Communicating Variables to a Sub-make.
Personally, I recommend avoiding $(shell) (and $(wildcard)) altogether. If you do use $(shell) then I recommend reserving such use to outside recipes. Inside recipes, use shell code directly. This is clearer, certainly in terms of makefile semantics (what is evaluated when), but often in terms of the actual code, too. For your particular example, that might look like so:
FOO := BAR
.EXPORT_ALL_VARIABLES:
.PHONY: fizz
fizz:
#echo fizz
#if test -n "$$FOO"; then echo FOO found; else echo FOO missing; make fizz; fi
In all current versions of GNU make, exported variables are not sent to the shell function. There are some very nasty recursive behaviors that can happen (what if you write export BAR = $(shell echo $$FOO) ???)
In the next release of GNU make, make variables will be exported to the shell function.
However, there's never any good reason to use shell in a recipe. The recipe is running in a shell, so you can just write the commands that you want directly. So if your example is accurate in that you want to use this facility in a recipe, just take out the shell invocation:
.PHONY: fizz
fizz:
#echo fizz
#test -n $$FOO && echo FOO found || echo FOO missing

Is there a way to print all variables defined/visible within a makefile?

let's assume the following Makefile:
FOO=1
BAR?=test
BLAH:=$(BAR)
target:
#echo "helloworld"
Is there a way it can show me variables like this (\n or \s) ?
FOO
BAR
BLAH
bonus question:
if it is possible, is there a way to also get external variables?
make target BLABLAH=toto or export BLABLAH=toto; make target
FOO
BAR
BLAH
BLABLAH
You don't say so specifically but because of the syntax I'll assume you're using GNU make. In that case you can use the .VARIABLES special variable:
$(info Variables: $(.VARIABLES))
Note, that make target BLABLBAH=toto does not create an "external variable" (that term is not well-defined so I'm just guessing that by this you mean variables that are inherited from the environment and not set in the makefile). Setting a variable on the command line creates a real make variable and it will be shown in the list above.
Variables obtained from the environment are imported into make as makefile variables and will also appear in the above list.

Ordering in makefiles

I've two targets foo and bar. Neither depend on the other, but if bar has to be rebuilt, it has to be done before foo. They are what gnu-make calls phony targets, their rules have always to be executed when they are specified.
Currently, we express a main target which depends on both like this:
# user level targets
all: bar
#$(MAKE) foo
#echo all
alt: foo
#echo alt
# internal targets
foo:
#echo foo
bar: qux
#echo bar
qux:
#echo qux
#touch qux
and we have the required behavior: if qux is not up-to-date: make bar outputs qux bar foo all (in that order) and make alt outputs foo alt; if qux is up-to-date, make bar output bar foo all and make alt outputs foo alt.
This is increasingly uncomfortable as foo has to be handled specifically (all targets which depend on both have to be handled that way, foo can't be put in a variable describing dependencies if bar is also there, the submake is itself an issue and the command line has to be maintained to pass additional variables). We now have another target which has to be handled in the same way and I'm looking for other, more convenient, ways to handle the structure.
Note 1 : In practice, I'm currently using only gnu-make but the only known dependency on a gnu-make extension over POSIX is the possibility to include files (which is quite widely available). I'd prefer something which keep the current state (i.e. widely supported constructs), but if it is not possible, the use of a gnu-make only extension is acceptable.
Note 2: gnu-make has a notion of order-only-prerequisites, but it apparently doesn't provide what we need. With
# user level targets
all: bar foo
#echo all
alt: foo
#echo alt
# internal targets
foo: | bar
#echo foo
bar:
#echo bar
make alt also build bar (if a file bar exist, its date doesn't influence the decision of rebuilding foo, which is the documented behavior).
Note 3: The more I think about it, the less I think it is possible to solve this problem with make without using a recursive call. It seems to me that it need two passes on the dependency graph, one to determine what has to be built, one to determine the ordering and I know nothing in make behavior which can't be done with a one pass algorithm.
Hmmm, how about this hack (for a hack it undoubtedly is :-)).
Basically, you could run make -d -n plus your command arguments. The output will contain several lines like Must remake target 'clean'. This information tells you whether this run of make will attempt to build both foo and bar. If this turns out to be the case, just add a rule to cause the serialisation you want.
A sketch:
this := $(lastword ${MAKEFILE_LIST})
ifndef DONTRECURSE
targets-that-will-get-remade := $(patsubst %',%,$(shell ${MAKE} -f ${this} ${MAKECMDGOALS} --debug=b -n DONTRECURSE=nosiree | grep -Po "Must remake target '\K.*'"))
endif
ifeq (bar foo,$(sort $(filter bar foo,${targets-that-will-get-remade})))
foo: bar
endif
.PHONY: foo bar
foo bar:
sleep 3
: $#
So, you run make. DONTRECURSE is not set so the $(shell …) runs. That runs make a second time with the same makefile and goals, but adds the -d (debug) and -n (don't actually run the recipes) flags. DONTRECURSE is set to prevent a third copy of make running.
The expansion of all that is a list of the targets this run of make will attempt to build on this run. (Extracting the target names is pretty tiresome—there is probably a cleaner way.)
If this list of targets includes both foo and bar, simply add a foo: bar dependency. Job done. The sleep 3 lines show this serialisation working when you use -j4 (say).

How to have variables of one included makefile available in another makefile included later?

I have the Makefile below,
include settings.mk
include main.mk
where settings.mk has the following content,
FOO=foo
BAR=bar
and main.mk is as follows:
THIS_MAKEFILE:=$(lastword $(MAKEFILE_LIST))
.PHONY: all
all:
$(MAKE) -f $(THIS_MAKEFILE) display
.PHONY: display
display:
#echo "FOO=$(FOO)"
#echo "BAR=$(BAR)"
The problem is that make all results in the following output
FOO=
BAR=
instead of
FOO=foo
BAR=bar
How to have the variables FOO and BAR available in main.mk?
When you execute just make -f main.mk (in the all target), the values are not set because you've just reread main.mk without pre-reading settings.mk.
In the Makefile, the variables are set. If you add a rule such as:
check:
#echo "FOO=$(FOO); BAR=$(BAR)"
to the Makefile, and then run make check, you'll see that FOO and BAR are indeed set.
So, the question becomes: why on earth are you doing what you are doing — and why are you expecting just make -f main.mk to know about stuff set in a makefile that the second invocation of make hasn't read? I think this is probably an XY Problem.
You could add include settings.mk to main.mk; that might make sense (but then the main Makefile would only need to contain include main.mk, leaving open the question of why you have both).
They are available in main.mk. They aren't available in the sub-make that you are spawning because you haven't exported them.
Use $(info FOO:$(FOO))/etc. in main.mk and you'll see them print out correctly.

.PHONY in linux makefile

SUBDIRS = foo bar baz
.PHONY: dirs $(SUBDIRS)
dirs: $(SUBDIRS)
$(SUBDIRS):
#echo $#
#ls $#
Anybody can just help me out to understand this make-file?
If possible explain me each statement (why do we need it?, what is the purpose? etc.)
And how exactly this make-file works?
It have wrong formatting, so i can only guess what it was before... Well, so it is:
first line assignes list "foo bar baz" to variable named SUBDIRS
second line is special command that makes all specified targets 'phonetical' - you can invoke "make dirs" or "make foo", and it will find target with that name and execute it, but it's no actual file with this name (like usual non-phony targets)
third one - creates target named 'dirs' which depends on value of SUBDIRS variable. space-separated list. this target have no real actions
fourth line creates rules for SUBRIDS variable contents, with no dependencies. The rest of text is actions that have to be performed to 'make' this target (so, in your case - if you just call "make", it will call "make dirs" (because it's the first target), which depends on foo, bar and baz - so these targets will be invoked. to perform each of these targets, make will call echo and ls - so eventually you'll get these three directory names and list of their files)

Resources