How to trace a recursive make? - makefile

I need to work on a system that uses automake tools and makes recursively.
'make -n' only traces the top level of make.
Is there a way to cause make to execute a make -n whenever he encounters a make command?

Use $(MAKE) to call your submakefiles, instead of using make. That should work. Check out How the MAKE variable works in the manual. Here's a quick example:
Makefile:
all:
#$(MAKE) -f Makefile2
Makefile2:
all:
#echo Makefile2
Command line:
$ make
Makefile2
$ make -n
make -f Makefile2
echo Makefile2
$

Does your recursive makefile look like this:
foo:
make -C src1
make -C src2
Or like this:
foo:
${MAKE} -C src1
${MAKE} -C src2
I think you need to use the second style if you want flags passed to child make processes. Could be your problem.

Setting the environment variable "MAKEFLAGS" to "n" may do what you need.
There are some more advanced tricks for tracing make commands here:
http://www.cmcrossroads.com/ask-mr-make/6535-tracing-rule-execution-in-gnu-make
The simplest of these tricks comes down to adding SHELL="sh -x" to your make command (running without "-n" in that case).

Related

GNU make - how to serialize calls to foreach $(MAKE)

I have
$(foreach ___project___, $(UNIT_TEST_STUBS),$(MAKE) -C ../../$(___project___) $(UT_CMD) || exit 1;)
I want make to be parallel INSIDE each submake but I don't want the submakes to be executed in parallel.
How do I do this?
As #Michael Livshin points out, you already seem to have answered your own question.
Might be neater to rely on make rather than shell syntax to tie a load of commands together though.
Basically you want make to see something like this:
.PHONY: all
all:
${MAKE} -C ../../foo/ -j9 ut-cmd
${MAKE} -C ../../bar/ -j9 ut-cmd
${MAKE} -C ../../bum/ -j9 ut-cmd
Auto generation from a list is fairly straight-forward.
submakes := foo bar bum
define generate-submake
${MAKE} -C ../../$1/ ut-cmd
endef
.PHONY: all
all: ; $(foreach _,${submakes},$(call generate-submake,$1))
Note the blank line in the definition of generate-submake. It's important.
Run this with make -j9.
If you really want everything in this makefile to run serially (but the sub-makes to be parallel), then just introduce a .NOTPARALLEL target.
.NOTPARALLEL:

How to pass down option -f SomeMakefile to a sub-make? [here with GNUMake]

When invoking itself recursively via some $(MAKE) foo in recipes, GNUMake passes down some of the options it was called with, but not all of them. In particular it does not pass down a -f SomeMakefile option. See section 5.7.3 of manual.
How can I find whether make was invoked with some -f option and how can I pass it down to a sub-make ?
To make the question concrete, here is what my SomeMakefile contains:
%.pdf : %.tex
pdflatex $(PDFLATEXFLAGS) $*
#if [ -f $*.log ] ; then $(MAKE) --silent $*.slw; fi
The problem is that how to make foo.slw is defined in SomeMakefile and the recursive make won't use it.
You can get the name of the makefile from MAKEFILE_LIST variable. E.g.:
${MAKE} -f $(lastword $(MAKEFILE_LIST))
If your makefile includes other makefiles you may like to store the name of the makefile early into an immediately assigned variable, e.g.:
# Somewhere at the top of your makefile, before any includes
this_makefile := $(lastword ${MAKEFILE_LIST})
# and use it later
some_rule :
${MAKE} -f ${this_makefile}
Alternatively, if you know that your makefile is always the first one read by make, then it is going to be in the front of MAKEFILE_LIST, e.g. $(firstword ${MAKEFILE_LIST}).

Makefile and computed variable names

I got the following Makefile with several compilers, and I would like to invoke them in a loop through the variable cc:
cc_x64=x86_64-linux-gnu-gcc
cc_mips=mips-linux-gnu-gcc
all:
for arch in "x64" "mips" ; do\
cc="cc_$$arch";\
$($(cc)) some_file -o some_bin
By $($(cc)), I am trying to substitute $(cc) with cc_xxx, and in turn, substitute it with the actual command I am trying to execute. This is called a computed variable name in GNU Make's documentation: https://www.gnu.org/software/make/manual/html_node/Computed-Names.html
For some reason, I cannot get this to work. What am I missing ?
You can't cross shell/make boundaries like that. You are trying, in the shell context, to create and evaluate a make variable on-the-fly. That can't work.
You either need to do all the work in make or in the shell. Export those make variables to the shell and then something like this should work:
all:
for arch in x64 mips; do\
cc=cc_$$arch;\
${!cc} some_file -o some_bin.$$arch;\
done
But it would probably be better to do this in a more make idiomatic way.
Which would look something more like this (untested):
all: $(addprefix some_file.,x86 mips)
some_file.%: some_file
$(cc_$(*)) $^ -o $#
If I felt compelled to use a loop, I'd do it like this:
COMPS = x86_64-linux-gnu-gcc mips-linux-gnu-gcc
all:
for comp in $(COMPS); do\
$$comp some_file -o some_bin; \
done
Your question is "What am I missing?" The answer is, you don't realize, that a Makefile works differently than a shell script. You are trying put a shell script on a Makefile. It is like you trying to put a saddle on a cow. Both you and the cow will be unhappy with the result.
The way you are trying to do it, you don't need Make. Just use the shell script you have there under "all:" and forget about Make. Why try to put a saddle on a cow?
If you do want to learn how to use Make, then please read more carefully the Make manual, and especially study the examples given there. Then you will understand the difference between shell scripts and Makefiles, and everything will be clearer.
I will show you how to do what you want, in the correct way that Makefiles are designed to work. But please, do study the manual more carefully.
RESULTS := $(addprefix some_bin., x86_64 mips)
.PHONY: all
all: $(RESULTS)
$(RESULTS): some_file Makefile
$(patsubst .%,%-linux-gnu-gcc,$(suffix $#)) $< -o $#

Change make's working directory without long command line

I would like to change the working directory of a makefile.
(Extraneous info: I have a legacy makefile that I mostly want to reuse, though many targets and generated deps files make assume that the working directory will not be different. My idea is to create a makefile for my newer project, which is in a different directory, and include the old one, and set the working directory to the old directory.)
I easily can do this from the command line with
make -f /path/to/new/makefile -C /path/to/old/makefile
The users of this makefile would like not to type that out every time.
Attempt 1
Use MAKEFLAGS in the makefile itself. But neither of these seem to have any effect. (I understand why -f couldn't have an effect; I'm really wondering about -C.)
I've looked at http://www.gnu.org/software/make/manual/html_node/Options-Summary.html, but I can't find anything about what is allowed in MAKEFLAGS and what isn't.
Attempt 2
Create a makefile2 with the new targets
include path/to/old/makefile
foo: bar
and then makefile passes everything through
%:
$(MAKE) -f $(abspath makefile2) -C path/to/old/makfele /$*
I don't get nice autocompletion, parallel jobs don't work, and debug options (dry run) doesn't work.
So
(1) Why doesn't -C work MAKEFLAGS (it does work, but I made a mistake; it doesn't work, and it is documented; it doesn't work, and it is not documented but it is intentional; it doesn't work, and it is a bug)?
(2) Is there a better way of change a makefile's working directory?
Some things are wrong here :
make -f /path/to/new/makefile -C /path/to/old/makefile
The -f options specifies the name of the Makefile to be found when searched in the directory specified with -C (or the current directory if not provided). So it is more :
make -C /path/to/old/Makefile -f name_of_old_makefile
If the name is simply Makefile or makefile, there is no need to provide the -foption.
The MAKEFLAGS variable does not contains -f or -C in the called sub-Makefile.
To be able to pass multiple targets to another makefile, you need the MAKECMDGOALS variable.
Ultimately, all you have to do in your new Makefile is to have someting like this :
all:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $#
%:
$(MAKE) $(MAKEFLAGS) -C /path/to/old/Makefile -f old_Makefile_name $(MAKECMDGOALS)

Make recursive dry-run

I need to look at which commands are being used by make, but running command make --dry-run does not show the commands used by an internal make -C /foo.
Is there any way to make this work recursively?
To allow -n to work recursively, invoke make recursively with $(MAKE) instead of just make.
foo:
$(MAKE) -C /foo

Resources