Dry run Makefile when "Nothing is to be done for 'all'" - makefile

I would like to dry run Makefile with "make -n", but the project has been compiled, with "Nothing to be done for 'all'" when I use "make -n". How would I do a dry run in this situation ? To do "make clean" is not an option here.

You could do make -B -n. The option -B is short for --always-make, which unconditionally re-runs the makefile. Combining it with the -n option simply simulates what the makefile would do, which is what it looks like you're going for.

Related

Using Make, how to build multiple configuration in one make command

Thanks for all your time and response -
Currently, we are using the nested build, multiple Makefiles, and individual subdirectories having their own Makefile, all are connected with a top-level Makefile. We are running
make xxxxx_yyyy_defconfig
make
this builds and creates an output file which is xxxxx.elf file. --- Till here everything works fine.
Now we are having multiple def-configs(around 50), I want to build all configurations using one "make all" command. is that possible?
This is not a simple case where we can put all "all: prog01 prog02 prog03" as every program needs to have a different configuration. Configuration can be achieved by using "make xxxxx_yyyy_defconfig". The output of "make config" is the .config file, which is used during the "make" command.
Based on .config file many variables are exported which is used at the subdirectory level.
So How can I build multiple configurations using a single "make all" command?
Environment - Ubuntu, Cross compile for ARM, output file xxxx.elf.
With the use of script and make file I am able to solve, But I have to solve only using Makefile.
in Makefile add one PHONY target
all:
./build_all.sh #shell script calling.
Created one shell script like this
#! /usr/bin/bash
echo "Make All"
for entry in `ls conf`; do
make $entry
wait
make
if [ $? -eq 0 ] ; then
for xxxfile in `ls xxx*_*` ; do
xxxdir=$(echo $xxxfile | cut -b yy-zz)
mkdir -p $xxxdir
mv $xxxfile $xxxdir/
done
else
break
fi
done
If you want to build several configurations you must do this out of tree in separate build directories (make O=/tmp/builds/foo foo_defconfig; make -C /tmp/builds/foo) to avoid conflicts. A shell script could do this as well as a Makefile but if you insist on using a Makefile you could try the following that assumes your source tree is in /src/kernel and you want to build configuration foo in /tmp/builds/foo; adapt to your needs:
$ pwd
/tmp/builds
$ cat Makefile
CONFIGS := uuuu_vvvv xxxx_yyyy ...
BUILD := /tmp/build
KERNEL := /src/kernel
.PHONY: $(CONFIGS) all
all: $(CONFIGS)
$(CONFIGS):
rm -rf $#
mkdir -p $(BUILD)/$#
$(MAKE) -C $(KERNEL) O=$(BUILD)/$# $#_defconfig
$(MAKE) -C $(BUILD)/$#
$ make

Makefile: Calling a recipe within another recipe will not run-dry it

Let's say I have a Makefile looking like this
file1:
$(MAKE) unittest
#echo "Making test file"
touch file1
unittest:
#echo Running test. In reality recipe will include many lines
.PHONY: unittest
My goal is to have a recipe to only run unit tests, but I also want to run them before creating the file (file1) and I don't want to run them if file1 exists.
This works when I run make, but I notice when I try
make file1 -n
file1 will be created and it is somehow due to having the make unittest call in the recipe.
Any clue about what is going on? Thanks in advance.
Either one of us is confused, or there's something about your makefile or environment you didn't share, or you have a buggy version of GNU make (what version do you have and what OS are you using? The version of GNU make that ships with MacOS is known to be old and Apple has made changes to it that have added bugs).
Doesn't reproduce on my system:
$ cat Makefile
file1:
$(MAKE) unittest
#echo "Making test file"
touch file1
unittest:
#echo Running test. In reality recipe will include many lines
.PHONY: unittest
$ ls file1
ls: cannot access 'file1': No such file or directory
$ make -n
make unittest
echo Running test. In reality recipe will include many lines
echo "Making test file"
touch file1
$ ls file1
ls: cannot access 'file1': No such file or directory
ETA
It's clear you don't want the file1 to be created if you run make -n.
But, your question didn't make clear whether you want the sub-make invocation of unittest to happen when you run make -n, or whether you don't want it to happen.
If you want unittest to be run but you don't want file1 to exist, but you do want to use .ONESHELL, then you're out of luck.
If you don't want unittest to run or file1 to exist when you run with -n, you can prevent it by fooling make into not noticing that the recipe is a recursive make invocation; all you have to do is not use the variable MAKE in the recipe. However, note that this has other side-effects particularly if you use -j to enable parallel builds:
NR_MAKE = $(MAKE)
file1:
$(NR_MAKE) unittest
#echo "Making test file"
touch file1

'make run clean' shell script that properly handles interupts

My first jab at writing a shell script that would run my makefile, run the executable, and then remove the executable looked like:
make
if [ -e a.out ]; then
./a.out
rm a.out
fi
after realizing that the script didn't clean up a.out when I pressed ^C, I tried modifying it like so:
onintr foo
make
if [ -e a.out ]; then
./a.out
rm a.out
fi
foo:
rm a.out
but it did not solve my problem. If any of you know how I can accomplish what I'm trying to do that would be very helpful.
Add an infinite loop at the top of your script, print out a line in your onintr routine and test that you hit it when you break the loop with Ctrl-C. Remove the extra ouput and the infinite loop. Read your man pages on make, you probably don't have much control over what happens when it gets interrupted. That's why so many make files have a Clean target in them, so you can rerun make to clean-up all of its outputs.

GNU Makefile equivalent of shell 'TRAP' command for concise identification of build failure on exit

Criteria: Makefile is a GNU Make Makefile - I'm not interested in makepp, qmake, cmake, etc. They're all nice (especially cmake), but this is for work and at work we use GNU Make. The optimal solution is a pure Makefile solution rather than a shell script that parses make for you.
I also don't want to do a 'continue on failure' solution - if it's broken, it's broken and needs to be fixed.
The situation is this, I've got a makefile that builds several directories in parallel - if one of them fails, of course the whole build fails, but not until all the running makes run to completion (or failure). This means that the reason why make actually failed is buried somewhere arbitrarily far from the end of make's output.
Here's an example of what I've got:
all: $(SUBDIRS)
SUBDIRS = \
apple \
orange \
banana \
pineapple \
lemon \
watermelon \
grapefruit
$(SUBDIRS):
cd $# && $(MAKE) $(MFLAGS) 2>&1 | sed -e "s/^/$(notdir $(#)): /g"
If I run 'make -j 5' and 'orange' happens to fail - I'd like to see a table like this at the end
of the make process
apple - passed
orange - FAILED
banana - passed
pineapple - passed
lemon - passed
I've considered having an && echo "passed" >.result || echo "FAILED" >.result, but make still needs some sort of TRAP or __onexit() cleanup command to print at them on exit.
Any Makefile ninjas out there have a pure-makefile solution for this?
un-edit - my solution wasn't actually working the way I had hoped.. STYMIED!
When you want make to abort at the first failure, end immediately and kill all in-flight jobs instead of waiting for them to finish, you need to patch GNU Make like this
http://lists.gnu.org/archive/html/bug-make/2009-01/msg00035.html
Then you need to set a trap for every shell that make invokes (as well as set -o pipefail if you use a pipe), as described in this post http://lists.gnu.org/archive/html/help-make/2009-02/msg00011.html
In a nutshell:
target1:
trap 'kill $$(jobs -p)'; command && something || something-else
target2:
trap 'kill $$(jobs -p)'; set -o pipefail; command | sed '...'
The only way I see is self-execution with a sub-make:
all : subdirs
subdirs :
$(MAKE) -f $(lastword $(MAKEFILE_LIST)) subdirs-recursive || cat log
subdirs-recursive: $(SUBDIRS)

Suppress messages in make clean (Makefile silent remove)

I'm wondering how I can avoid some echo in a Makefile :
clean:
rm -fr *.o
this rule will print:
$>make clean
rm -fr *.o
$>
How can I avoid that?
To start with: the actual command must be on the next line (or at least that is the case with GNU Make, it might be different with other Make's - I'm not sure of that)
clean:
rm -rf *.o
(note, you need a TAB before rm -rf *.o as in every rule)
Making it silent can be done by prefixing a #:
so your makefile becomes
clean:
#rm -rf *.o
If there are no *.o files to delete, you might still end up with an error message. To suppress these, add the following
clean:
-#rm -rf *.o 2>/dev/null || true
2>/dev/null pipes any error message to /dev/null - so you won't see any errors
the - in front of the command makes sure that make ignores a non-zero return code
In fact I was looking for something else, adding this line to the Makefile :
.SILENT:clean
while execute every step of the "clean" target silently.
Until someone point some drawback to this, I use this as my favourite solution!
I'm responding to this ancient topic because it comes up high in search and the answers are confusing. To do just what the user wants,all that is needed is:
clean:
#rm -f *.o
The # means that make will not echo that command.
The -f argument to rm tells rm to ignore any errors, like there being no *.o files, and to return success always.
I removed the -r from the OPs example, because it means recursive and here we are just rming .o files, nothing to recurse.
There's no need for the 2>&1 >/dev/null because with the -f there will be no errors printed.
.SILENT: clean
works in place of the #, but it isn't at the same place in the Makefile as the command that it affects, so someone maintaining the project later might be confused. That's why # is preferred. It is better locality of reference.
If you put an # in front of the command, it doesn't echo onto the shell. Try changing rm to #rm. (Reference)
From the manual: .SILENT is essentially obsolete since # is more flexible.
Much worse is that make prints far too much information. Warning/error/private messages are buried in the output. On the other hand -s (.SILENT) suppresses just anything. Especially the "nothing to be done" and "up to date" messages can be a pain. There is no option to suppress them. You have to filter them out actively or use something like colormake. Here is a solution for grep:
make | egrep -hiv 'nothing to be done|up to date'
But the output will have line numbers. The Perl solution is therefore better, because it suppresses line numbers and flushes stdout immediately:
make | perl -ne '$|=1; print unless /nothing to be done|up to date/i'
Make's a flawed tool. "What’s Wrong With GNU make?" explains this better than I can.
There's a great article on using .SILENT that explains how to conditionally activate it.
I have used that information to put this in my Makefile:
# Use `make V=1` to print commands.
$(V).SILENT:
# Example rule, only the #echo needs to be added to existing rules
*.o: %.c
#echo " [CC] $<"
gcc ...
What this does is if you run make normally, normal output is silenced and instead the echo commands work:
$ make
[CC] test.c
[CC] test2.c
But it allows you to debug problems by passing the V=1 parameter, which still shows the [CC] messages as it helps break up the output, but the traditional Makefile output is also visible:
$ make V=1
[CC] test.c
gcc ...
[CC] test2.c
gcc ...

Resources