make command execution from the Makefile - makefile

Consider the following Makefile:
CURRENT = $(shell uname -r)
KDIR = /lib/modules/$(CURRENT)/build
PWD = $(shell pwd)
TARGET1 = md1
TARGET2 = md2
TARGET3 = md3
obj-m := $(TARGET1).o $(TARGET2).o $(TARGET3).o
default:
make -C $(KDIR) M=$(PWD) modules
Is it true that the variables which declared in the current Makefile is coming to the $(KDIR)/Makefile.

Probably not. In general make variables are internal to make, and are not available in recursive invocations of make.
If you want the variable to be available in the sub-make, you need to either pass it on the command line for the sub-make, or else export it from the parent make; the latter will put it in the environment when the sub-make is invoked.
Note, though, that assignments in makefiles override values taken from the environment. So the $(KDIR)/Makefile will need to be careful to test the value before setting it, if it does.
By the way, you should never invoke a recursive make with the literal make. Always use the variable $(MAKE).

Related

Makefile target name compared to string

In a makefile I'm trying to compare the target name with a string, and depending on this set a variable with a string or another.
This example illustrates what I'm trying to do:
ifeq ($#,"Target_A")
THE_PATH="Path_a"
THE_TARGET=$#
else
THE_PATH="Path_b"
THE_TARGET=$#
endif
Target_A:
#echo $(THE_PATH)
#echo $(THE_TARGET)
Target_B:
#echo $(THE_PATH)
#echo $(THE_TARGET)
This is the output when I call make passing Target_A and when I call it passing Target_B:
$ make Target_A
Path_b
Target_A
$ make Target_B
Path_b
Target_B
The fact that I always get "Path_b" indicates the ifeq always evaluates to false, but you can see that $# contained the right string.
Why doesn't this work?
You probably want target-specific variables:
Target_A: THE_PATH="Path_a"
Target_A:
#echo $(THE_PATH)
Since contents of a (regular) variable are expanded each time it's used, THE_TARGET=$# can be made global.
Target-specific variables are only accesible in a target they belong to, and its dependencies.
Normally this is enough, but if you need to have global variables, you can use the same code you have in the question, with the condition changed to this:
ifneq ($(filter Target_A,$(MAKECMDGOALS)),)
$# (which you tried to use) only works inside of a recipe, and expands to a target name that the recipe builds.
$(MAKECMDGOALS) is a global variable that contains all targets specified (as command-line parameters) when invoking make.
This option will only work if the target you're looking for was specified as a command-line parameter.

Export preprocessor macro in makefile

I want to export preprocessor macro to an internal makefile from the main makefile in a particular target.
example:
Main_Makefile
target1 :
CXXFLAGS+=-DNewFlag=NewFlag
cd some_directory; make
Here I want to use value of CXXFLAGS which is -DNewFlag=NewFlag and is only defined under target1 in some_directory/make
Please let me know how can I achieve this.
There is no way to append to a variable from the command line, unless you've made arrangements for it in the makefile of the subdirectory.
The simplest thing to do is use a different variable, like this:
target1:
cd some_directory && $(MAKE) EXTRA_CXXFLAGS=-DNewFlag=NewFlag
(note you should always use $(MAKE) or ${MAKE} when invoking a sub-make, never make directly.)
Then in the subdirectory makefile you do something like this:
CXXFLAGS += $(EXTRA_CXXFLAGS)

Pass Arguments to make call in Makefile

I have a Makefile with a large number of possible variables set on the command line. I'd like to be able to have one target in my makefile that uses the arguments and then call it from Make with various options:
GUI ?= 0
DEBUG ?= 0
VERBOSE ?= 0
run_prog:
$(MYPROG) $(GUI) $(DEBUG) $(VERBOSE)
run_prog_gui:
$(MAKE) run_prog GUI=1
run_prog_debug:
$(MAKE) run_prog DEBUG=1
The problem is that I can't tell whether a user has overridden one of the variables:
% make run_prog_debug VERBOSE=1
I'd like to have a way of passing all the variables that were passed to me to the run_prog target in run_prog_gui for example.
Is there a variable in make that gives you a string of all the variables set on the command line?
It turns out this happens automatically. Recursive calls to make happen in a shell with the variables set.
https://www.gnu.org/software/make/manual/make.html#Recursion

Setting OS variable from rule

I am trying to build a shared library with one set of code, and everything works, except for this issue with my Makefile. Here's my (simplified) Makefile thus far:
OBJS = bar.o
libfoo.so: OS = LINUX # These don't seem to happen
libfoo.dll: OS = WINDOWS
# Linux
ifeq ($(OS), LINUX)
CC = gcc
...
# Windows
else ifeq ($(OS), WINDOWS)
CC = i686-pc-mingw32-gcc
...
endif
all: libfoo.so libfoo.dll
libfoo.so: clean $(OBJS)
...
libfoo.dll: clean $(OBJS)
...
bar.o: bar_$(OS).c bar.h
...
So, when you type make libfoo.so, I expect it to set OS = LINUX first. Then, when it gets to bar.o (it is a dependency of libfoo) it should know which bar_$(OS).c to use. However, I get the error:
make: *** No rule to make target `bar_.c', needed by bar.o. Stop.
Which tells me that when it tries to make bar.o, $(OS) is not set. But shouldn't that be the first thing that happens when I try to make libfoo.so, and that rule is evaluated?
Target-specific variables are available in the body of the rule, not in its prerequisites. But even if you could get this to work, you'd be asking for trouble: if you build one library and then the other, there's no way for Make to know that the bar.o that was made for the first is wrong for the second and should not be used.
There are several ways to get the effect you want, but none is perfect. I'd suggest using two different object file names, like bar_unix.o and bar_windows.o.
If you want to set a target-specific variable, and then have that variable available outside the body of that rule, you can recursively call the Makefile, after exporting the variable:
OBJS ?= foo.o # Use ? so it isn't blown away on recursive call
libfoo.so: OS = LINUX
libfoo.so: OBJS += linux_only.o
libfoo.so:
$(MAKE) -s build_libfoo_linux
build_libfoo_linux: $(OBJS)
#echo "OS = $(OS)" # Should print "OS = LINUX"
export OS # Can be anywhere
You have to remember to export the variables you want to "persist" after the recursive make call. And also, as shown above, if you append to any variables before the call, you'll want to make their initial assignment with ?= so they aren't set the second time.
You might want to detect the OS using uname and then conditionally compile. This explains

Passing additional variables from command line to make

Can I pass variables to a GNU Makefile as command line arguments? In other words, I want to pass some arguments which will eventually become variables in the Makefile.
You have several options to set up variables from outside your makefile:
From environment - each environment variable is transformed into a makefile variable with the same name and value.
You may also want to set -e option (aka --environments-override) on, and your environment variables will override assignments made into makefile (unless these assignments themselves use the override directive . However, it's not recommended, and it's much better and flexible to use ?= assignment (the conditional variable assignment operator, it only has an effect if the variable is not yet defined):
FOO?=default_value_if_not_set_in_environment
Note that certain variables are not inherited from environment:
MAKE is gotten from name of the script
SHELL is either set within a makefile, or defaults to /bin/sh (rationale: commands are specified within the makefile, and they're shell-specific).
From command line - make can take variable assignments as part of his command line, mingled with targets:
make target FOO=bar
But then all assignments to FOO variable within the makefile will be ignored unless you use the override directive in assignment. (The effect is the same as with -e option for environment variables).
Exporting from the parent Make - if you call Make from a Makefile, you usually shouldn't explicitly write variable assignments like this:
# Don't do this!
target:
$(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
Instead, better solution might be to export these variables. Exporting a variable makes it into the environment of every shell invocation, and Make calls from these commands pick these environment variable as specified above.
# Do like this
CFLAGS=-g
export CFLAGS
target:
$(MAKE) -C target
You can also export all variables by using export without arguments.
The simplest way is:
make foo=bar target
Then in your makefile you can refer to $(foo). Note that this won't propagate to sub-makes automatically.
If you are using sub-makes, see this article: Communicating Variables to a Sub-make
Say you have a makefile like this:
action:
echo argument is $(argument)
You would then call it make action argument=something
From the manual:
Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value. However, an explicit assignment in the makefile, or with a command argument, overrides the environment.
So you can do (from bash):
FOOBAR=1 make
resulting in a variable FOOBAR in your Makefile.
It seems command args overwrite environment variable.
Makefile:
send:
echo $(MESSAGE1) $(MESSAGE2)
Example run:
$ MESSAGE1=YES MESSAGE2=NG make send MESSAGE2=OK
echo YES OK
YES OK
There's another option not cited here which is included in the GNU Make book by Stallman and McGrath (see http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html). It provides the example:
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
It involves verifying if a given parameter appears in MAKEFLAGS. For example .. suppose that you're studying about threads in c++11 and you've divided your study across multiple files (class01, ... , classNM) and you want to: compile then all and run individually or compile one at a time and run it if a flag is specified (-r, for instance). So, you could come up with the following Makefile:
CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread
SOURCES = class01 class02 class03
%: %.cxx
$(CXX) $(CXXFLAGS) -o $#.out $^ $(LDLIBS)
ifneq (,$(findstring r, $(MAKEFLAGS)))
./$#.out
endif
all: $(SOURCES)
.PHONY: clean
clean:
find . -name "*.out" -delete
Having that, you'd:
build and run a file w/ make -r class02;
build all w/ make or make all;
build and run all w/ make -r (suppose that all of them contain some certain kind of assert stuff and you just want to test them all)
If you make a file called Makefile and add a variable like this $(unittest)
then you will be able to use this variable inside the Makefile even with wildcards
example :
make unittest=*
I use BOOST_TEST and by giving a wildcard to parameter --run_test=$(unittest)
then I will be able to use regular expression to filter out the test I want my Makefile
to run
export ROOT_DIR=<path/value>
Then use the variable, $(ROOT_DIR) in the Makefile.

Resources