GNU make scope of variable - build

I have some makefile:
$(PROGRAM_NAME): index.o
#echo "linking"
#echo $(index_o)
//linking
export index_o:=.
index.o:
$(MAKE) -C some_dir index.o
at some_dir makefile
export index_o:=$(index_o)/index.o
index.o:
#echo "compiling"
#echo $(index_o)
//compiling
output:
compiling
./index.o
linking
.
need output:
compiling
./index.o
linking
./index.o
How to share changes of variable to the parent make thread?
May be I need real global variable...
I have read http://www.gnu.org/software/automake/manual/make/Recursion.html
but not found

You can't push variable back to parent processes.
You may be interested in reading Recursive Make Considered Harmful. Short-short version: recursion isn't necessary for controlling large builds and causes trouble.

Related

Call gnumake on all subdirs in parallel (-j) and only then run the linker-rule last (i.e. order important)

I have a c++ makefile project. It works great for non-parallel building. It works 99% for parallel building... the only problem I have is that I can't get my final executable link-line to run last (it must be the last thing that happens).
I have some constraints: I don't want to have any PHONY dependencies on my link line because this causes it to re-link every time. I.e. once my target is built, when I re-build it should not be re-linked.
Here is (slightly contrived) minimal example. Please don't try to pick holes in it, its really here just to show the problem, its not real, but the problem I am showing is. You should be able to just run this and see the same issue that I am.
# Set the default goal to build.
.DEFAULT_GOAL = build
#pretend subdirs (these don't really exist but it does not matter so long as they always try to be built)
MAKE_SUB_DIRS = 1 2 3
#pretend shared objects that are created by the pretend makefile sub directories (above)
OUTPUTS = out1.so out2.so out3.so
# Top level build goal - depends on all of the subdir makes and the target.out
.PHONY: build
build: $(MAKE_SUB_DIRS) target.out
#echo build finished
# Takes 1 second to build each of these pretend sub make directories. PHONY so always runs
.PHONY: $(MAKE_SUB_DIRS)
$(MAKE_SUB_DIRS):
#if [ ! -f out$#.so ] ; then echo making $#... ; sleep 1 ; echo a > out$#.so ; fi
# The main target, pretending that it needs out1,2 and 3 to link
# Should only run when target.out does not exist
# No PHONY deps allowed here
target.out:
#echo linking $#...
#ls $(OUTPUTS) > /dev/null
#cat $(OUTPUTS) > target.out
# Clean for convinience
clean:
#rm -rf *.so target.out
Now, I don't really care about make working, what I want is make -j to work. Here is me trying to run it:
admin#osboxes:~/sandbox$ make clean
admin#osboxes:~/sandbox$
admin#osboxes:~/sandbox$ make -j - 1st attempt
making 1...
making 2...
linking target.out...
making 3...
ls: cannot access 'out1.so': No such file or directory
ls: cannot access 'out2.so': No such file or directory
ls: cannot access 'out3.so': No such file or directory
makefile:24: recipe for target 'target.out' failed
make: *** [target.out] Error 2
make: *** Waiting for unfinished jobs....
admin#osboxes:~/sandbox$
admin#osboxes:~/sandbox$ make -j - 2nd attempt
linking target.out...
build finished
admin#osboxes:~/sandbox$
admin#osboxes:~/sandbox$ make -j - 3rd attempt
build finished
admin#osboxes:~/sandbox$
So I highlighted my three attempts to run it.
Attempt 1: you can see all 4 dependencies of build are started at the same time (approx). Since each of the makeing x... take 1 second and the linking is nearly instant we see my error. However all the three "libraries" are build correctly.
Attempt 2: The libraries only get created if they don't already exists (that's bash code - pretending to do what a makefile might have done). In this case they are already created. So the Linking passes now since it just requires the libraries to exist.
Attempt 3: nothing happens because nothing needs to :)
So you can see all the steps are there, its simply a matter of ordering them. I would like the the make sub dirs 1, 2, 3 to build in any order in parallel and then only once they are all completed I want target.out to run (i.e. the linker).
I don't want to call it like this though: $(MAKE) target.out because in my real makefile I have lots of variables all setup...
I have tried looking at (from othe answers) .NOT_PARALLEL and using the dep order operator | (pipe), and I have tried order a load of rules to get target.out to be last.... but the -j option just ploughs through all of these and ruins my ordering :( ... there must be some simple way to do this?
EDIT: add an example of ways to pass variables to sub-makes. Optimized a bit by adding $(SUBDIRS) to the prerequisites of build instead of making them in its recipe.
I am not sure I fully understand your organization but one solution to deal with sub-directories is as follows. I assume, a bit like in your example, that building sub-directory foo produces foo.o in the top directory. I assume also that your top Makefile defines variables (VAR1, VAR2...) that you want to pass to the sub-makes when building your sub-directories.
VAR1 := some-value
VAR2 := some-other-value
...
SUBDIRS := foo bar baz
SUBOBJS := $(patsubst %,%.o,$(SUBDIRS))
.PHONY: build clean $(SUBDIRS)
build: $(SUBDIRS)
$(MAKE) top
$(SUBDIRS):
$(MAKE) -C $# VAR1=$(VAR1) VAR2=$(VAR2) ...
top: top.o $(SUBOBJS)
$(CXX) $(LDFLAGS) -o $# $^ $(LDLIBS)
top.o: top.cc
$(CXX) $(CXXFLAGS) -c $< -o $#
clean:
rm -f top top.o $(SUBOBJS)
for d in $(SUBDIRS); do $(MAKE) -C $$d clean; done
This is parallel safe and guarantees that the link will take place only after all sub-builds complete. Note that you can also export the variables you want to pass to sub-makes, instead of passing them on the command line:
VAR1 := some-value
VAR2 := some-other-value
...
export VAR1 VAR2 ...
Normally you would just add the lib files as prerequisites of target.out:
target.out: $(OUTPUTS)
#echo linking $#...
The thing is, this will relink target.out if any of the output lib files are newer. Normally this is what you want (if the lib has changed, you need to relink target), but you specifically say you do not.
GNU make provides an extension called "order only prerequisites", which you put after a |:
target.out: | $(OUTPUTS)
#echo linking $#...
now, target.out will only be relinked if it does not exist, but in that case, it will still wait until after $(OUTPUTS) have finished being built
If your $(OUTPUT) files are build by subsirectory makes, you may find you need a rule like:
.PHONY: $(OUTPUT)
$(OUTPUT):
$(MAKE) -C $$(dirname $#) $#
to invoke the recursive make, unless you have other rules that will invoke make in the subdirectories
Ok, so I have found "a" solution... but it goes a little bit against what I wanted and is therefore ugly (but not that that ugly):
The only way I can fathom to ensure order in parallel build (again from other answers I read) is like this:
rule: un ordered deps
rule:
#echo this will happen last
Here the three deps will be made (or maked?) in any order and then finally the echo line will be run.
However the thing that I want to do is a rule and specifically so, such that it checks if anything has changed or if the file does not exist - and then, and only then, runs the rule.
The only way I know of to run a rule from within the bode of another rule is to recursively call make on it. However I get the following issues just calling make recursively on the same makefile:
Variables are not passed in by default
Many of the same rules will be re-defined (not allowed or wanted)
So I came up with this:
makefile:
# Set the default goal to build.
.DEFAULT_GOAL = build
#pretend subdirs (these don't really exist but it does not matter so long as they always try to be built)
MAKE_SUB_DIRS = 1 2 3
#pretend shared objects that are created by the pretend makefile sub directories (above)
OUTPUTS = out1.so out2.so out3.so
# Top level build goal - depends on all of the subdir makes and the target.out
export OUTPUTS
.PHONY: build
build: $(MAKE_SUB_DIRS)
#$(MAKE) -f link.mk target.out --no-print-directory
#echo build finished
# Takes 1 second to build each of these pretend sub make directories. PHONY so always runs
.PHONY: $(MAKE_SUB_DIRS)
$(MAKE_SUB_DIRS):
#if [ ! -f out$#.so ] ; then echo making $#... ; sleep 1 ; echo a > out$#.so ; fi
# Clean for convinience
clean:
#rm -rf *.so target.out
link.mk:
# The main target, pretending that it needs out1,2 and 3 to link
# Should only run when target.out does not exist
# No PHONY deps allowed here
target.out:
#echo linking $#...
#ls $(OUTPUTS) > /dev/null
#cat $(OUTPUTS) > target.out
So here I put the linker rule into a separate makefile called link.mk, this avoids recursive make calling on the same file (and therefore with re-defined rules). But I have to export all the variables I need to pass through... which is ugly and adds a bit of a maintenance overhead if those variables change.
... but... it works :)
I will not mark this any time soon, because I am hopeful some genius will point out a neater/better way to do this...

My linux c++ gnu makefile variable expansion does not behave as I expected it to

I have created the following little makefile snippet. Note: I have made this a minimal example of my problem so it is a pointless makefile.
TARGET = none
OBJ_BASE_DIR = obj
# Linux x86 c++ compiler
.PHONY: build_cpp_x86Linux
build_cpp_x86Linux: TARGET = x86Linux
build_cpp_x86Linux: build
OBJ_DIR = $(addsuffix /$(TARGET),$(OBJ_BASE_DIR))
$(info TARGET IS: $(TARGET))
$(info OBJ_DIR IS: $(OBJ_DIR))
build: $(OBJ_DIR)/test.o
#echo building, OBJ_DIR: $(OBJ_DIR)
# pattern rule
$(OBJ_DIR)/%.o:
#echo "compiling $#"
Here is the output of calling make:
TARGET IS: none
OBJ_DIR IS: obj/none
compiling obj/none/test.o
building, OBJ_DIR: obj/x86Linux
From the output you can see that it is trying to compile obj/none/test.o, but what I want it to do is try to compile obj/x86Linux/test.o. I am not quite sure what is going on here. I think I understand that the makefile expands the variables on the first pass (which would result in TARGET=none), but I thought that it would re-expand the variables again once I have called the target build_cpp_x86Linux which sets the value of TARGET to x86Linux...
What I am doing wrong here and how should this be done?
You could also use:
TARGET?=none
And then override on the command line TARGET=x86Linux
You can also use ifdef or other scanning if operations to set different variables based on these arguments or environment variables.

make with argument for different executable name

I have a c++ codebase. I have a CMakeLists. When I run make, it creates the binary myexec.
I would like to be able to run, say, make -- v2, and that it creates the exact same binary, but called myexec_v2. It would be great if it did not have to recompile everything to create this binary, but only the modified files.
How can I do that?
myexec myexec_v2: $(prerequisites)
#echo compile $#
observe:
$ make myexec
compile myexec
$ make myexec_v2
compile myexec_v2
if nothing else is needed to compile myexec_v2 then you are done.
see here for more information: https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html
here is a slightly more advanced version
myexec myexec_v2: myexec%: $(prerequisites)
#echo compile $# $*
this is called a static pattern rule. the myexec% in the middle is called the target pattern. in this example we only use it to get the so called stem. the stem would be _v2 and the variable $* expands to the stem.
for more information: https://www.gnu.org/software/make/manual/html_node/Static-Usage.html
observe:
$ make myexec
compile myexec
$ make myexec_v2
compile myexec_v2 _v2
now you can use either $# or $* in the recipe to modify the behaviour to compile on or the other.
but if you want to do if branches in the recipe read this first: Basic if else statement in Makefile

Bizarre behavior observed in make 3.81 when attempting to use a reassigned variable as a dependancy

I'm running into a bizarre problem with a C++ makefile. I rewrote it this afternoon because the old one I was using made me want to kill myself, and I'm running into a weird problem regarding variable reassignment and dynamic dependancies.
for the purposes of this question, assume the following values:
OBJMOD_MODULENAME = obj/lib/foo.o obj/lib/bar.o obj/lib/quux.o
LIBDIR = lib/
CXX = g++
CXXLIBLINK = -shared
LIB = -lm -lpt
I have a target of the following format:
modulename: OBJ_CURRENTMOD = $(OBJMOD_MODULENAME)
modulename: $(OBJMOD_MODULENAME) lib/metrics.so
and later on, another of the following format:
$(LIBDIR)%.so: $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $# $(OBJ_CURRENTMOD) $(LIB)
Lines in code blocks always appear in the order in which they are presented in the code blocks, however over the course of debugging I have changed the position of the blocks relative to each other.
The problem occurs after I change a source file and try to recompile with 'make modulename'. Building the object files works as expected, but rebuilding the library does not happen if the file already exists, i.e. the dependencies specified by $(OBJ_CURRENTMOD) are ignored. Using $(OBJMOD_MODULENAME) in the library dependencies works as expected. I have verified in a number of ways that the value of $(OBJ_CURRENTMOD) is as expected (stick echo
$(OBJ_CURRENTMOD) on the first line of the library target for example), but no matter what I try, the variable does not seem to update in time to trigger a recompile due to dependancy checking.
As I was typing this, I found a workaround:
OBJMOD_MODULENAME = obj/lib/foo.o obj/lib/bar.o obj/lib/quux.o
LIBDIR = lib/
CXX = g++
CXXLIBLINK = -shared
LIB = -lm -lpt
modulename: OBJ_CURRENTMOD = $(OBJMOD_MODULENAME)
modulename: $(OBJMOD_MODULENAME) lib/metrics.so
$(LIBDIR)%.so: herp $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $# $(OBJ_CURRENTMOD) $(LIB)
herp: $(OBJ_CURRENTMOD)
This dummy target tacked in before the variable reference seems to force it to update and solves my problem. Is this a bug in make or something? make --version indicates GNU make 3.81. Can anyone else confirm this weird behavior? Am I just doing something horribly stupid? I've been staring at it for hours, I wouldn't be that surprised.
edit: turns out that wasn't really fixing it, it was just trapping it into running every time regardless of whether or not it needed it.
To verify the altered value:
$(LIBDIR)%.so: $(OBJ_CURRENTMOD)
echo $(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $# $(OBJ_CURRENTMOD) $(LIB)
As I said in one of my comments, I don't see how the $(LIBDIR)%.so pattern will match any pre-requisite of modulename but assuming metrics.so is meant to be lib/metrics.so then it will be used to build lib/metrics.so.
As interjay pointed out, "As with automatic variables, these values are only available within the context of a target's recipe (and in other target-specific assignments)." They can't be used in a target pattern or in a list of pre-requisites, which explains why the target doesn't get rebuilt when one of the pre-requisites in $(OBJ_MODULENAME) changes.
To make $(OBJ_CURRENTMOD) valid in the prerequisites list you'll need to use secondary expansion
.SECONDEXPANSION:
$(LIBDIR)%.so: $$(OBJ_CURRENTMOD)
$(CXX) $(CXXLIBLINK) -o $# $(OBJ_CURRENTMOD) $(LIB)
You are using the target-specific variable value OBJ_CURRENTMOD in the prerequisite list of the $(LIBDIR)%.so rule. This is not allowed: Target-specific variables may only be used in the recipe of a target.
Another issue is that you are defining the variable OBJ_MODULENAME and later accessing a different variable $(OBJMOD_MODULENAME), which hasn't been assigned to.

Make GNU make use a different compiler

How can I make GNU Make use a different compiler without manually editing the makefile?
You should be able to do something like this:
make CC=my_compiler
This is assuming whoever wrote the Makefile used the variable CC.
You can set the environment variables CC and CXX, which are used for compiling C and C++ files respectively. By default they use the values cc and g++
If the makefile is written like most makefiles, then it uses $(CC) when it wishes to invoke the C compiler. That's what the built-in rules do, anyway. If you specify a different value for that variable, then Make will use that instead. You can provide a new value on the command line:
make CC=/usr/bin/special-cc
You can also specify that when you run configure:
./configure CC=/usr/bin/special-cc
The configuration script will incorporate the new CC value into the makefile that it generates, so you don't need to manually edit it, and you can just run make by itself thereafter (instead of giving the custom CC value on the command line every time).
Many makefiles use 'CC' to define the compiler. If yours does, you can override that variable with
make CC='/usr/bin/gcc'
Use variables for the compiler program name.
Either pass the new definition to the make utility or set them in the environment before building.
See Using Variables in Make
Makefile:
#!MAKE
suf=$(suffix $(src))
ifeq ($(suf), .c)
cc=gcc
else
ifeq ($(suf), .cpp)
cc=g++
endif
endif
all:
$(cc) $(src) -o $(src:$(suf)=.exe)
clean:
rm *.exe
.PHONY: all clean
Terminal:
$ make src=main.c