I'm trying to read a makefile and it uses the variable $(MAKE). I can't see where this is getting defined. Is it a special variable of some sort? We're using GNU make.
It is an automatically defined variable. It is usually used to call make into subdirectories. More info in GNU make manual.
Related
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).
Is there a variable to set, so that make command searches for makefiles in other directories rather than only searching for makefiles in the current working directory?
Update: The scenario is like this, in our project we have a script which mostly defines & sets some of environment variables. Then a make is given in the root folder (to build) which doesn't have a makefile. Hence, I don't think "-c" or other make options can help in this.
I found, after some investigation, that makefile is in internal folders and being invoked. So, my question is are there any environmental varibles which makes the "make" command to search for makefiles in that specified directories (by the environment variable).
The short answer is no, it's not possible to have make search for makefiles in a different directory than the one it was started in (or switched to due to the -C option, for GNU make) by default.
You have two options: one is to use the -f option as above.
The other is to set the MAKEFILES variable to the list of makefiles you want read in before you invoke make. Note this must be the actual files you want read in, not just the directory that contains them. The downside of this is that the default target will never be taken from these makefiles: see https://www.gnu.org/software/make/manual/html_node/MAKEFILES-Variable.html which means you'll need to always specify the target you want to build on the command line.
For root makefile you have to specific the file name, use
make -f mymakefiledir/makefile
for nested makefile, there is make -I MyMakefileDir
$man make
-f file, --file=file, --makefile=FILE
Use file as a makefile.
-I dir, --include-dir=dir
Specifies a directory dir to search for included makefiles. If
several -I options are used to specify several directories, the
directories are searched in the order specified. Unlike the argu‐
ments to other flags of make, directories given with -I flags may
come directly after the flag: -Idir is allowed, as well as -I dir.
This syntax is allowed for compatibility with the C preprocessor's
-I flag.
According to manpage of GNU make.
If no -f option is present, make will look for the makefiles,GNUmakefile,
makefile, and Makefile, in that order.
There are no environmental variables make will refer for searching Makefile in other directory. Why not create a new makefile in root folder to call your makefile in internal folders?
The Makefile is written as the followings:
all:
iceking='$#';
echo $$iceking;
However the output is as the followings:
[root#localhost test]# make
iceking='all';
echo $iceking;
The string 'all' doesn't output. Why?
New sub-shell for each line of the recipe.
From GNU make manual:
When it is time to execute recipes to update a target, they are
executed by invoking a new sub-shell for each line of the recipe...
Set of shell commands, that called by your makefile is equivalent to:
bash -c iceking='all';
bash -c echo $iceking;
The variable iceking is not accessible from the environment of the second invocation of bash. That's why you receive empty output.
.ONESHELL (only since GNU make 3.82)
One way to fix it, is use .ONESHELL special target. From GNU make manual:
If the .ONESHELL special target appears anywhere in the makefile then
all recipe lines for each target will be provided to a single
invocation of the shell.
But there is one problem with .ONESHELL, this feature was added only since version 3.82 of GNU make.
One line recipes.
Another way to fix it, is write recipes in one line, since all commands in the line will be passed to a single invocation of the shell.
all:
iceking='$#'; echo $$iceking;
I have a Makefile which works perfectly called from a new shell, i.e.:
make -C /dir/
However, if I call this Makefile from another Makefile, it fails due to some complicated dependency issues. Make clearly has knowledge of the nested calls, evident by the print of make[1]: etc, and I suspect make is somehow sharing variables with its child process.
Is there anyway to call a clean make from within a Makefile? If my build works from a clean shell, it should be possible to call it from another Makefile without addressing the horrors inside the script! :)
Thanks!
make indeed shares some of its environment when it is recursively called. As suggested in https://www.gnu.org/software/make/manual/html_node/Options_002fRecursion.html#Options_002fRecursion, you might want to write your recursive call that way:
sub-make:
$(MAKE) -C /dir/ MAKEFLAGS=
and see if it helps. You can also control the variables that are exported to the sub-make by using export and unexport directives (https://www.gnu.org/software/make/manual/html_node/Variables_002fRecursion.html#Variables_002fRecursion)
It was a few environment variables in the caller make that broke the callee make (CFLAGS etc...)
My solution was to diff the environment at a clean shell and from the point of call. I then manually added the problem variables to a list and created some save_env/restore_env scripts.
Thanks!
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