I need a variable in makefile that can be shared across subdir makefiles ( recursive build strategy), and finally use it for some decision making. I had earlier thought export is the way to do it, but I am not getting desired results.
following are my makefiles:-
Target.mk (common include for both Makefile.mk & Subdir.mk)
Makefile.mk
Subdir.mk
FILE : Target.mk
export TARGET_PROPERTIES :=
FILE : Makefile.mk
-include Target.mk
.PHONY : all
all :
$(MAKE) -C $(PWD) -f Subdir.mk all
#echo "#------------------------------------------------------------#"
#echo "Target build properties"
#echo $(TARGET_PROPERTIES)
#echo "#------------------------------------------------------------#"
FILE : Subdir.mk
-include Target.mk
TARGET_PROPERTIES+=alpha
TARGET_PROPERTIES+=beta
$(warning $(TARGET_PROPERTIES))
all:
#echo "Subdir.mk......[OK]"
PROBLEM:-
I want TARGET_PROPERTIES, to be updated from Subdir.mk and the use the results in Makefile.mk
following is my output
$ make -f Makefile.mk
make -C /cygdrive/c/make_pf -f Subdir.mk all
make[1]: Entering directory `/cygdrive/c/make_pf'
Subdir.mk:8: alpha beta
Subdir.mk......[OK]
make[1]: Leaving directory `/cygdrive/c/make_pf'
#------------------------------------------------------------#
Target build properties
#------------------------------------------------------------#
in Subdir.mk TARGET_PROPERTIE updates, fine until here.
Subdir.mk:8: alpha beta
in Makefile.mk after return from "Subdir.mk - all target" it resets to NULL.
Not sure what I am doing wrong
P.S. I am using cygwin environment.
Exported environment variables are copied to child processes, so changes there do not propagate back into the parent process.
Your best bet would probably to avoid recursive makefiles and instead include everything from the main Makefile.mk. Google for Recursive Make considered harmful for pointers how to do this.
Related
I want a pattern rule for a Makefile for turning several sources into a single object.
So instead of a filename like foo.c I have a folder name foo/.
Additionally, there's path of the directory stem src/bar/foo/ where not only the shared src/ needs to be ignored but also the variable bar/.
Directory Structure
I have several objects to create - let's call them this:
bin/lib1.so
bin/lib2.so
bin/lib3.so
The source directory has a structure like this with folders grouping the libs:
src/
foo/
lib1/
a.c
b.c
bar/
lib2/
d.c
e.c
lib3/
f.c
g.c
If the grouping of libs didn't exist it would be straightforward, but it does exist.
Makefile
The targets get built by make all which is given for this example explicitly (I actually use shell find as in this answer, because there's several of them, but for this example I keep it simple):
all: bin/lib1.so bin/lib2.so bin/lib3.so
Now I would like to clean up the Makefile by creating a pattern rule for making all of these targets, kind of like this:
bin/%.so: $$(wildcard src/*/%/*.c)
# testing the rule:
echo $< > $#
But this doesn't work.
I'm skipping the step of c->o for simplicity because the point is linking together several files.
There's this question which has a similar problem of subdirectories, but it's only about 1:1 mapping of files instead of n:1, and I couldn't get it to work for my problem.
Desired Result
To test the rule it should just show in each target file what sources went into it:
bin/lib1.so
src/foo/lib1/a.c
src/foo/lib1/b.c
bin/lib2.so
src/bar/lib2/d.c
src/bar/lib2/e.c
bin/lib3.so
src/bar/lib3/f.c
src/bar/lib3/g.c
Here is a working version that supports one or multiple C files as input:
bin/%.so: src/*/%/*.c
#echo "START"
#echo $^
#echo $#
#echo "END"
all: bin/lib1.so bin/lib2.so bin/lib3.so
Result:
$ make
START
src/foo/lib1/main.c
bin/lib1.so
END
START
src/bar/lib2/plip.c src/bar/lib2/plop.c
bin/lib2.so
END
START
src/bar/lib3/kilo.c
bin/lib3.so
END
I would like all my recipes to be executed from a specific directory, the directory where the Makefile is located.
This is the default behaviour when invoking make without options, but an user could always run :
(cd /somewhere; make -f /path/to/directory/Makefile)
To ensure that make working directory is the same as the directory where the Makefile is located, there are multiple solutions :
run make without options (default), from this specific directory (cd /path/to/directory; make)
use make -C /path/to/directory
cd to /path/to/directory for each recipe, like this :
MAKEFILE_DIR_LOCATION := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
a:
cd ${MAKEFILE_DIR_LOCATION} && do_something_from_makefile_folder
b:
cd ${MAKEFILE_DIR_LOCATION} && do_another_thing_from_makefile_folder
The problem is that the first two solutions requires actions from the user invoking the Makefile, while the last one clutters the Makefile.
Is there a prettier way to ensure that all recipes are executed from the directory where the Makefile is located?
Extra solution (does not work)
I also thought comparing the working directory ($(shell pwd)) to ${MAKEFILE_DIR_LOCATION}, and exit if it does not match (at least to warn the user that make is not correctly invoked), but I can't find how to do this. I tried :
MAKEFILE_DIR_LOCATION := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
WORKING_DIR := $(shell pwd)
ifneq (${MAKEFILE_DIR_LOCATION}, ${WORKING_DIR})
#error "Please run make from the directory of the Makefile, or use make -C"
endif
a:
do_something_from_makefile_folder
b:
do_another_thing_from_makefile_folder
But I got a missing separator error (line #error), or a recipe commences before first target if #error line is indented.
Answering the question you asked without commenting on whether it's a good idea or not, I'm not sure where you found this syntax:
#error "Please run make from the directory of the Makefile, or use make -C"
but it's definitely wrong. error is a make function, so you want this:
$(error Please run make from the directory of the Makefile, or use make -C)
A variant on your last attempt would re-invoke Make in the correct directory, with the same target:
ifneq (${MAKEFILE_DIR_LOCATION},${WORKING_DIR})
%:
$(MAKE) -C ${MAKEFILE_DIR_LOCATION} $#
.PHONY: %
else
## rest of Makefile rules
endif
When I tried my makefile, I got error saying that No such file or directory, but my directory is right there, what do I do wrong? Thanks.
my project structure :
dev |--- ev
|--- display
|--- install ( makefile is here, try to call makefiles in ev and display folder)
My makefile :
MODULES :=ev display
SRC_DIR :=$(addprefix ../, $(MODULES))
BUILD_DIR:=$(addsuffix /build, $(SRC_DIR))
x:=../ev ------> add temporarily just for test,
------> the same error if x:=$(HOME)/dev/ev
INSTALL_DIR:=EX Frameworks Add-ons
INSTALL_DIR:=$(addprefix $(HOME)/EX/, $(INSTALL_DIR))
vpath %.cpp %.java $(SRC_DIR)
.PHONY: all clean
checkdirs: $(INSTALL_DIR)
$(INSTALL_DIR):
#echo "INSTALL DIR"
#mkdir -p $#
define make-goal
$1:
#echo "start building each part"
cd $# && make -f Makefile_new.osx clean
cd $# && make -f Makefile_new.osx package
endef
clean:
#echo "clean up"
#echo "BUILD_DIR IS $(BUILD_DIR)"
#rm -rf $(BUILD_DIR)
all:
#echo "start build subdirectory"
#echo "SRC_DIR IS $(SRC_DIR)"
#echo "x is $(x)"
$(call make-goal, $(x))) ----> when it comes to here, I got error message
The error messages:
x is ../ev
../x:
make: ../ev:: No such file or directory.
I guess it is about relative path, because I call this makefile from Install folder, then $(x) can't be found from Install folder, but when I tried to make a folder named ev (Install/ev), I still got the same error.
I think it must be something basic I missed here, but what it is.
Thanks.
Update:
I am trying to build a project which includes several sub-projects. the structure is:
dev |---- ev
|---- edf
|----- dt
|------af
|------Install
Inside of Install, I have a makefile, which is at the top level. The makefile in Install folder will call makefiles in other folders to build different subjects,
Ideally, I want to build every sub projects without touching sources. My sources include c++ and java code.
It's not clear what you're trying to do. Also due to some indentation hiccups I can't be sure, but you appear to be defining a variable make-goal that contains a template for a make rule, then using it with $(call ...) inside the recipe for the all target. That cannot work: you cannot create a make rule inside the recipe for another make rule!
The reason this fails is that the $(call ...) is expanding to content which is added to the recipe of the all target, so instead of creating a new make rule it's treating the result as a shell script. The first line is $1:, and you passed in ../ev, so make is trying to run the command ../ev: just as the error shows you.
If you describe what you want to do at a higher level we can give you some ideas on how to do it.
ETA:
If you just want your all target to also build a subdirectory, there's no need for all this complex GNU make advanced capabilities. That stuff is only needed when you get to guru-level makefile creation. Simple "build a target after another target is finished" is the exact thing make was designed to do: nothing special is needed to do that.
For example:
.PHONY: all $(SRC_DIR)
all: $(SRC_DIR)
$(SRC_DIR):
#echo "start building $#"
cd $# && $(MAKE) -f Makefile_new.osx clean
cd $# && $(MAKE) -f Makefile_new.osx package
This is still a pretty non-standard setup but I think it will work the way you want. Remember you'll have to either move the all target up to be the first one in the makefile, or you'll have to run make all explicitly: make only builds the first target in the makefile unless you give it specific targets on the command line.
The question is about parallel making w/ GNU makefile.
Given a folder structure as below, the goal is to deliver a makefile that it supports make release/debug/clean in parallel.
project folder structure:
foo
+-foo1
+-foo2
+-foo3
The makefile may be sth like:
SUBDIR = foo1 foo2 foo3
.PHONY $(SUBDIR) release debug clean
release: $(SUBDIR)
$(SUBDIR):
$(MAKE) -C $# release
debug: $(SUBDIR)
#below is incorrect. $(SUBDIR) is overriden.
$(SUBDIR):
$(MAKE) -C $# debug
..
Sub directory list are set as phony targets for parallel making. but it lost the information of original target (release, debug, clean etc).
One method is to suffix the names for the directories and recover it in commands, but it is weird. another method might be to use variables, but not sure how to work it out.
The questions is:
How to write the rules for directories, that supports parallel making w/ different targets (release/debug/clean)?
Any hints are greatly appreciated.
Setting variables on the command line certainly works. You can also use MAKECMDGOALS (see the GNU make manual):
$(SUBDIR):
$(MAKE) -C $# $(MAKECMDGOALS)
I want to create a Makefile (in a parent dir) to call several other Makefiles (in sub dirs) such that I can build several binaries (one per project sub dir) by invoking just the one parent Makefile.
My research has been hampered by finding loads of stuff on recursive Makefiles, but I think this is where you are trying to build several directories Makefiles into a single binary?
Maybe what I want to do is better handled by a shell script perhaps invoking make in each sub directory in turn, but I thought a Makefile might be a more elegant solution?
any pointers gratefully received
PS using linux and the GNU tool chain
The for loop solution given in the first answer above actually shouldn't be used, as-is. In that method, if one of your sub-makes fails the build will not fail (as it should) but continue on with the other directories. Not only that, but the final result of the build will be whatever the exit code of the last subdirectory make was, so if that succeeded the build succeeds even if some other subdirectory failed. Not good!!
You could fix it by doing something like this:
all:
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $${dir} $# || exit $$?; \
done
However now you have the opposite problem: if you run "make -k" (continue even if there are errors) then this won't be obeyed in this situation. It'll still exit on failure.
An additional issue with both of the above methods is that they serialize the building of all subdirectories, so if you enable parallel builds (with make's -j option) that will only happen within a single subdirectory, instead of across all subdirectories.
Eregrith and sinsedrix have solutions that are closer to what you want, although FYI you should never, ever use "make" when you are invoking a recursive make invocation. As in johfel's example you should ALWAYS use $(MAKE).
Something like this is what you want:
SUBDIRS = subdir1 subdir1 subdir3 ...
all: $(addprefix all.,$(SUBDIRS))
all.%:
# $(MAKE) -C '$*' '$(basename $#)'
.PHONY: $(addprefix all.,$(SUBDIRS))
And of course you can add more stanzas like this for other targets such as "install" or whatever. There are even more fancy ways to handle building subdirectories with any generic target, but this requires a bit more detail.
If you want to support parallel builds you may need to declare dependencies at this level to avoid parallel builds of directories which depend on each other. For example in the above if you cannot build subdir3 until after both subdir1 and subdir2 are finished (but it's OK for subdir1 and subdir2 to build in parallel) then you can add something like this to your makefile:
all.subdir3 : all.subdir1 all.subdir2
You can call targets in subdirectory makefiles via
all:
$(MAKE) -C subdirectory1 $#
$(MAKE) -C subdirectory2 $#
...
or better
SUBDIRS=subd1 subd2 subd3
all:
#for dir in $(SUBDIRS); \
do \
$(MAKE) -C $${dir} $#; \
done
you should indeed use cmake to generate the Makefile automatically from a given CMakeLists.txt configuration file.
Here's a random link to get you started. Here you can find a simple sample project, including multiple subdirectories, executables, and a shared library.
Each makefile can have several target, it's still true with recursive makefiles, usually it's written:
all: target1 target2 target3
target1 :
make -C subdir
Then make all