`make -n` starts a config.status - makefile

I start a make -n of big project (multiple directories; Makefile and configure created with autotools); I think that nothing can be changed by this make; but it starts a config.status --recheck and regenerates some Makefiles and config.h.
Why does make -n starts anything?

Have you read the manual? If you look at this section, you will see that recipe lines that start with a + and ones containing the $(MAKE) variable are always executed. Perhaps your Makefile contains such lines.

Related

make runs command even if underlying files have not changed

I want to recompile Unix.zwc, if any of the files in Unix/ directory has changed. I have created this Makefile:
all: Unix.zwc
zsh -c 'zcompile -Uz Unix.zwc Unix/*'
Unix.zwc: Unix/*
but when I run make, it always recompiles the file Unix.zwc even when none of the files Unix/* have changed.
What am I doing wrong?
Make works by comparing timestamps of files. This rule:
all: Unix.zwc
says that the all file will be updated if either (a) it doesn't exist or (b) it exists but its last modified time is older than the file Unix.zwc.
Maybe you can now see why everything is always rebuilt: the file all never exists, and so it's always considered out of date, so the recipe is always run. I don't know what the zcompile command actually does, but either the name of this target should not be all it should be whatever file the zcompile command generates, or else you'll have to create the all target by hand using touch $# for example.
Second, this rule doesn't do what you expect:
Unix.zwc: Unix/*
You don't have a recipe here, which means that make will never update Unix.zwc, which means that all will not be out of date when a file in Unix changes. If the all target depends on both the Unix.zwc file and the files in the Unix directory (which it appears it does) then you should remove the above prerequisite statement and write all as:
all: Unix.zwc Unix/*
zsh -c 'zcompile -Uz Unix.zwc Unix/*'
touch $#
What am I doing wrong?
You are putting the command for compiling Unix.zwc into the recipe for (phony) target all, instead of the recipe for its own target.
Since all does not exist, its recipe is always run. With GNU make, it is advisable to go even farther by explicitly declaring it phony to ensure that the recipe is run even if a file named all actually is created.
What you want is this:
all: Unix.zwc
Unix.zwc: Unix/*
zsh -c 'zcompile -Uz Unix.zwc Unix/*'
.PHONY: all

how to set the directory where Makefile exists so that I can run make from different directory using `make -C` option?

Say in ~/prj/abc/abcsim/abctsim/abcxyz/Makefile there is a line below.
TOOLCHAIN_DIR := $(PWD)/../../../prj1/tools/gcc_tools
If I'm in directory ~/test, and if I run make -C ~/prj/abc/abcsim/abctsim/abcxyz, this doesn't work because the $(PWD) variable is set to ~/test, not ~/prj/abc/abcsim/abctsim/abcxyz. How can I get the directory path where the Makefile exists?
In bash there's something for this : How can I get the source directory of a Bash script from within the script itself?
If you really use make -C (not make -f) and your Makefile is not included in another, you can simply use the CURDIR variable. GNU make sets it to the absolute path of the current directory when it starts, "after it has processed any -C options". So, in your case it should do exactly what you want.
Else, if you sometimes use make -f or if you have included Makefiles, you can put this as the first line of any of your Makefiles (or, at least, before any include statement):
HERE := $(dir $(lastword $(MAKEFILE_LIST)))
and then use $(HERE) to refer to this Makefile's directory. See the GNU make manual for the details.
Note: I was almost sure this question would be a duplicate. Surprisingly I searched SO for a clear answer and found only old answers that first suggest shell calls before using make built-ins or wrong answers (using firstword instead of lastword, for instance).

How to unhide commands in Makefile?

I want to troubleshoot Makefile. A lot of commands are hidden using the # prefix. e.g.
all:
#echo "building..."
how can I tell make to show all the commands? I tried the -d option and it does not show hidden commands.
Maybe try running make with V=1 or VERBOSE=1
I'm not exactly sure this is what you are looking for, but here is a related technique:
Prefixing commands with # in a makefile recipe can be convenient, so output does not get too much cluttered, but, as you may have discovered, in some situations it can be useful to actually see what command is executed.
One solution is to avoid using the # character in a makefile but use instead a variable. Say, a one-letter one. Say L, for "log output" (but its your choice).
Then, prefix all your commands in your makefile with that variable:
target: prerequ
$(L)do_this $< $#
$(L)do_that $< $#
An simply define the variable, using some command-line switch:
ifeq "$(LOG)" ""
LOG=no
endif
ifeq "$(LOG)" "Y"
L=#
endif
Then, you can launch make from the shell like this $make target (no logging) or like this:
$ make target LOG=Y
And all the executed commands will show up!

How to prevent 'make clean' from building files scheduled for removal

If I run make clean twice the second invocation will build the dependency Makefiles that are scheduled for removal. How can I get Makefile to recognize the files scheduled for removal and skip the recursive call to make for that directory? In other words, only make clean in sub directory if the makefile already exists in each sub directory, on a per sub directory basis. I don't know the GNU-Make syntax but I'm looking for something like:
Dependencies=[dependency1,dependency2,dependency3,dependency4]
DoNotMake=[bool1,bool2,bool3,bool4]
for all (i < 4):
if (! Dependencies(i)/Makefile):
DoNotMake(i)=true
The current rules for make clean are as follows:
.PHONY: clean
clean:
$(MAKE) MAKEDEPEND=off SUBDIR_ARGS=clean
rm -f dependency1/Makefile
rm -f dependency2/Makefile
rm -f dependency3/Makefile
rm -f dependency4/Makefile
rm -f dependency4/src/config.h.in
I can't give you a definite answer since there's still a lot of your makefile that you haven't posted, but here are some things that we do to solve similar problems.
The make variable MAKECMDGOALS contains the current make target. If you want to avoid doing something when you run make clean, you can do something like this:
ifeq (,$(findstring $(MAKECMDGOALS),clean))
# Whatever you place here won't be run when you run 'make clean'
endif
You can also add a bit of shell script to only invoke a sub-makefile when it exists:
some_target:
[ -f $(SUB_FOLDER)/Makefile ] && $(MAKE) -C $(SUB_FOLDER)
If your makefiles are being created implicitly, then these may not work. You may be able to use the --assume-old= option to prevent make from re-building the makefiles (I've never tried to use that on a file that doesn't exist, so YMMV).

Is there a configuration file for gnu make?

I want to tell make that it shall always use -j4 option even if I didn't specify it vie command line. Normally i would do this in some configuration file (i.e. ~/.makerc).
Does such file exist for gnu make?
Have a read about the $(MAKEFLAGS) variable:
export MAKEFLAGS=j4
However this will likely interfere with recursive-make-based builds (not that sensible people are using recursive make anyway!), by interfering with GNU make's ability to communicate with its sub-makes.
So the more sensible approach is probably a wrapper script or an alias or shell function.
Well, yes and no --- normally you would use an include file. Put your common configuration items together in a file, say common.mk and add
include common.mk
at the top of your makefile. If the flag doesn't have a matching way to configure it from inside the make file, you can use a function
function mk {
make -j4 $*
}
It doesn't exist, but you can do this by having a recursive call into make.
For example:
Makefile:
-include $(HOME)/.makerc
.DEFAULT_GOAL: all
# This will handle a default goal if make is just called without any target
all:
$(MAKE) $(MAKE_OPTIONS) -f Makefile.real $(MAKECMDGOALS)
# This handles all targets and passes it through
%:
$(MAKE) $(MAKE_OPTIONS) -f Makefile.real $(MAKECMDGOALS)
$(HOME)/.makerc:
MAKE_OPTIONS := -j4
I would like to expand a bit on the solution hinted in John Marshall's answer.
You can simply put a one-line wrapper script somewhere earlier in the $PATH with the following contents:
#!/bin/bash
$(type -ap make | sed -n 2p) -j4 "$#"
(The script doesn't have to be named make, and that would make it simpler, but I find it convenient if it is.)
I would argue that this is better than the other approaches for the following reasons:
Unlike MAKEFLAGS approach, it does not break recursive builds (which are actually quite common in my experience).
Unlike include .makerc approach, it can be applied locally without changing any existing makefiles or your workflow in any way.
Unlike shell alias or function approach, it is shell-agnostic (doesn't tie you to any particular shell) and works in any additional build scripts that you might have to use, too, as long as you launch them in the same environment.
I like the MAKEFLAGS approach suggested by John Marshall in lieu of make supporting something like an automatic .makerc project config file. However, I didn't want to have to remember to source a .env or similar environment variables beforehand (and unsetting them afterward).
A solution to this is to put the MAKEFLAGS assignment at the top of the Makefile itself:
#!/usr/bin/env make
MAKEFLAGS=s
.PHONY: foo
foo:
echo "hello, make"
Run it:
$ make foo
hello, make
Compared to running without the MAKEFLAGS=... line:
$ make foo
echo "hello, make"
hello, make

Resources