Makefile autocompletion for paths (e.g. for defconfig) - makefile

I have a project with a menuconfig configuration for which this I use several *_defconfig files as default configurations. These defconfig files are grouped for each project:
/
- projects
- projectA
- configs
- 32bit_defconfig
- 64bit_defconfig
- foo_defconfig
- projectB
- configs
- 32bit_defconfig
- 64bit_defconfig
- bar_defconfig
Now I would like to have a makefile, where I get the autocompletion for these defconfigs:
$ make projects/pr<TAB>
projects/projectA
projects/projectB
I thought about writing a Makefile like this:
projects/%/configs/%_defconfig: FORCE
echo $#
Currently the only thing which is working is this rule, where I have no autocompletion for the path:
# e.g. 'make projects/88000-000/configs/32bit_defconfig'
%_defconfig: FORCE
$(MAKE) -f tools/make/menuconfig.mk $#
PS: Autocompletion works for regular make targets.

You can use wildcards for this reason:
DEFCONFIGS=$(wildcard projects/*/configs/*_defconfig)
test: FORCE
echo $(DEFCONFIG)
$(DEFCONFIGS): FORCE
$(MAKE) -f tools/make/menuconfig.mk $#
First use the test-target to check whether your wildcard is working, then you can use autocompletion:
$ make <TAB>
all default install_toolchain
buildroot-menuconfig FORCE menuconfig
clean install projects/
$ make projects/<TAB>
92107-110/ BananaPro/
$

Related

Multiple rules for one target

I have large project and it's compiled on-demand on several different machines with different OS'es.
One of targets has foo.res in it's dependencies. This resource file can be compiled using either one of 2 different rules:
First rule requires text file foo.txt to be present. This rule also requires some of the non-cross platform software to be installed in the system. This rule can not be used in-field by the our engineers, as it won't run under old MacOS.
Second rule uses pre-compiled resource file foo.res in resources directory and simply copies it to build/. Obviously, this is unwanted workaround, but i have no other choice.
I've tried to describe 2 rules in one Makefile, but i've got such error:
Makefile:78: warning: overriding recipe for target 'build/foo.res'
Makefile:75: warning: ignoring old recipe for target 'build/foo.res'
Currently I use Makefile with one of the rules commented-out:
.PHONY: compile
build/app.bin: some_files... build/foo.res
(Here is compiler call)
build/:
-mkdir build/
.PHONY: clear
clear:
-rm -rf ./build
... Lots of stuff here ...
# build/foo.res: res/foo.res | build/.
# cp res/foo.res build/foo.res
build/foo.res: res/foo.txt | build/.
some_app -o build/foo.res res/foo.txt
I deploy pre-compiled res/foo.res to some machines and then I swap commented rules, so regular cp is used. This works fine, until some changes are introduced to Makefile in some of commits. Then it blocks fast-forward update in git.
How can I configure make to fire only one of the rules, based on matched dependencies?
You can't do this with explicit rules. An explicit rule tells make THIS is how you build this target. You can create two different pattern rules that can build the same target. A pattern rule says this is one way you can build that target.
So, change your makefile to:
build/%.res: res/%.res | build/.
cp $< $#
build/%.res: res/%.txt | build/.
some_app -o $# $<

Make: why do I get error saying "no such file or directory"

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.

How to handle different targets for same directories in parallel making

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)

start other makefile within makefile

Since i am not so experienced with the building process / makefiles on linux i ran in follow problem:
the Setup:
i have an makefile A, which needs some enviroment variables set before running, this is done by running . ./set_A_vars.sh (set_A_vars.sh contains many export lines) before running make -f A
now i need to make project A within a makefile B.
i tried the following setup for makefile B:
all: debug release
A_debug:
. ./set_A_vars.sh && make -f A DEBUG=1
A_release:
. ./set_A_vars.sh && make -f A DEBUG=0
debug: A_debug some_B_stuff_debug
release: A_release some_B_stuff_debug
however i get lots of errors, which sound like the enviroment variables in set_A_vars.sh have not been set for make -f A ... in B.
How can i call makefile A from makefile B with the enviroment variables in set_A_vars.sh set in makefile B ??
Any help appreciated.
Your makefile looks good with these provisos:
When you call make from a makefile, please use the macro invocation ${MAKE} rather than plain make. (This ensures parallel make works, and also means it still works even if your make has another name (GNUmake say).)
If your targets do not correspond to actual files, then mark them with .PHONY (see below).
Does some_B_stuff_debug require A to be built first? Then you must tell make this.
some_B_stuff_debug: A_debug
some_B_stuff_debug: A_release
This is clearly wrong. One way is to enforce the ordering via the shell.
Try something like this:
.PHONY: debug
debug:
. ./set_A_vars.sh && ${MAKE} -f A DEBUG=1
${MAKE} some_B_stuff_debug
.PHONY: release
release:
. ./set_A_vars.sh && ${MAKE} -f A DEBUG=0
${MAKE} some_B_stuff_debug
.PHONY: some_B_stuff_debug
∶
Your makefiles should work. I suggest you try the following:
Try running set_A_vars.sh from the command line.
Verify that the variables you wanted set are set.
make -f MakefileA, to verify that MakefileA really does work nicely with these variables set.
Try a rule in MakefileB that will test one of the variables, say FOO:
test_var:
#echo FOO is $(FOO)
This should work if you have just run set_vars.sh. If it doesn't, then there are a couple of things that could be wrong...
Now clear the variables (including FOO) and try this rule in MakefileB:
set_vars_and_test_them:
./set_A_vars.sh && echo FOO is $(FOO)
Now put it together:
A_debug:
./set_A_vars.sh && make -f MakefileA DEBUG=1
(I recommend against calling a makefile "A".)

Override target in makefile to add more commands?

At work we use a common makefile that other makefiles include (via the include statement) and it has a generic "clean" target that kills some common files. I want to add on to that target in my new makefile so I can delete some specific files, but if I add a clean target in my makefile, it just overrides the old one.
I know I can just make a new target with a new name and have it call clean, and then do other stuff, but for sake of consistency I'd like to be able to just call make clean and have it do everything.
Is that possible?
I've seen this done at several shops. The most common approach is to use double-colon rules, assuming you're using something like GNU make. In your common makefile you would have something like this:
clean::
# standard cleanup, like remove all .o's:
rm -f *.o
Note that there are two colons following clean, not just one!
In your other makefile you just declare clean again, as a double-colon rule:
clean::
# custom cleanup, like remove my special generated files:
rm -f *.h.gen
When you invoke make clean, GNU make will automagically run both of these "branches" of the clean rule:
% make clean
rm -f *.o
rm -f *.h.gen
It's simple to set up and it composes quite neatly I think. Note that specifically because it is a double-colon rule, you don't get the "overriding commands" errors you normally get when you define two rules for the same target. That's sort of the point of double-colon rules.
You can write your own clean and make it a preq of the common clean.
clean: myclean
myclean:
rm whatever
Yours will run first. If for some reason you want the common clean to run first then the solution will be more complicated.
EDIT:
Here is the best solution I can see which runs the common rule before the local one:
include Makefile.common
clean:
$(MAKE) -f Makefile.common $#
rm whatever additional things
The include directive is necessary because the local makefile relies on the common one for things other than clean. The local clean rule overrides the common clean rule, but invokes the common clean rule before doing the additional work. (This overriding will cause some warnings, which is a nuisance; I don't know a good way to silence them.)
Use implicit rules:
existing-target: my-extention
my-extention:
echo running command 1
echo running command 2
Very simple make tutorial to ramp up.
When using :: you can run into issues since make complains when you mix single colon : and double colon :: rules:
a:
echo a
a::
echo aa
will result in:
. . .
*** target file `a' has both : and :: entries. Stop.
It seems like the common makefile's rule should be called something like common-clean. Then each main makefile would declare their clean rule as
clean: common-clean
and you're set.
If that isn't an option, you could take a look at double colon rules, but those introduce a whole other set of issues to consider.
Adding another possible solution I've seen for posterity... I know the OP was wary about changing the common makefile, but something like this works and involves minimal changes.
local makefile 1:
CLEAN=MyExe1 MyExe2
....
include /my/common/makefile
local makefile 2:
CLEAN=MyExe3 MyExe4
....
include /my/common/makefile
common makefile:
clean:
rm -f *.dep *.o *.a $(CLEAN)
Basically the idea is to define some variable (in this case CLEAN) in each local makefile with all the specific items you want to delete. Then the common makefile runs rm -f on all the common file types to delete, plus whatever was specifically flagged for deletion in each local makefile via the CLEAN variable. If there's nothing specific to delete, simply omit the variable declaration or leave it empty (CLEAN=)
So now if we run make clean for local makefile 1, it executes
rm -f *.dep *.o *.a MyExe1 MyExe2
And if we run make clean for local makefile 2, it executes
rm -f *.dep *.o *.a MyExe3 MyExe4
I've found a better solution:
.PHONY: my-extra-clean
clean: my-extra-clean
my-extra-clean:
rm <whatever-you-want>
include Makefile.common
The key line is clean: my-extra-clean. Ie, you can add dependencies in separate stanzas in different makefiles to add behaviour. my-extra-clean is run as a dependency of the root clean target.
For ours, we define a variable, EXTRAFILESTOCLEAN, then when the clean rule runs, it has a step to remove anything specified in the EXTRAFILESTOCLEAN variable
clean:
rm -f *.o
ifdef $(EXTRAFILESTOCLEAN)
rm -f $(EXTRAFILESTOCLEAN)
endif
That can cause unexpected problems if you set that variable to weird values, but you could guard against those by adding prefixes or other tests.
It's in the docs: https://www.gnu.org/software/make/manual/html_node/Overriding-Makefiles.html
So instead of include Makefile you use a wildcard target and forward it to the base Makefile:
# -include base.Makefile <--- not this
%:
#$(MAKE) -f base.Makefile $#

Resources