Can reuse makefile multiple times within single execution? - makefile

Suppose I have:
# ./Makefile
CLUSTER=dev
include Makefile.cluster.mk
CLUSTER=local
include Makefile.cluster.mk
And in:
# ./Makefile.cluster.mk
${CLUSTER}.cmd:
cmd ${CLUSTER}
So now I can call:
make dev.cmd
make local.cmd
Great! Except the variable is evaluated too late. Running:
$ make local.cmd # cmd local
$ make dev.cmd # Also cmd local !
Make sense: according to: https://www.gnu.org/software/make/manual/html_node/Reading-Makefiles.html
rule steps are deferred evaluation (vs. immediate/on file load).
immediate : immediate ; deferred
deferred
Is there a better/other way to compose a set of make commands without maintaining multiple copies of the same file?

There are lots of ways to do it, even beyond the options above; you could use static pattern rules:
CLUSTERS := dev local
$(CLUSTERS:%=%.cmd) : %.cmd :
cmd $*
If you really want to have stuff in a separate makefile you can use target-specific variables; change your Makefile.cluster.mk to do this:
# ./Makefile.cluster.mk
${CLUSTER}.cmd: CLUSTER := $(CLUSTER)
${CLUSTER}.cmd:
cmd ${CLUSTER}

Is there a better/other way to compose a set of make commands without maintaining multiple copies of the same file?
Often it's pattern rules. In the case of your particular example, you might do
Makefile
%.cmd:
cmd '$*'
However, that particular version will enable any make foo.cmd, which might not be what you want.
Sometimes it's to make better use of the tools available to you. For example,
Makefile.cluster.mk
${CLUSTER}.cmd:
arg='$#'; cmd "$${arg%.cmd}"
That extracts the wanted cluster name from the name of the target.
Occasionally it is $(eval).
(See the manual for an example.)
And from time to time, it's "don't do that." For example,
Makefile
CLUSTERS = dev local
CMDS = $(patsubst %,%.cmd,$(CLUSTERS))
$(CMDS):
arg='$#'; cmd "$${arg%.cmd}"
That defines only dev.cmd and local.cmd targets, and avoids duplicating the recipe.

Related

Where should I start to debug when Make throws a particular error

My knowledge of Make is small. I have been told that everything you put after make (that does not contain "-") is a target.
Well a building process I have is failing.
First there is a line
make path/to/configuration_file
configuration_file is not a target. It is a autogenerated configuration file buried inside the directory structure ("path/to") that is of the form
#
# Boot Configuration
#
#
# DRAM Component
#
CONFIG_DRAM_TYPE_LPDDR4=y
# CONFIG_DRAM_TYPE_DDR4 is not set
CONFIG_DDR_SIZE=0x80000000
#
# Boot Device
#
# CONFIG_ENABLE_EMMC_BOOT is not set
# CONFIG_ENABLE_NAND_BOOT is not set
CONFIG_ENABLE_SPINAND_BOOT=y
# CONFIG_ENABLE_SPINOR_BOOT is not set
CONFIG_EMMC_ACCESS_8BIT=y
# CONFIG_EMMC_ACCESS_4BIT is not set
# CONFIG_EMMC_ACCESS_1BIT is not set
so I cannot understand how this is a target. For reference, when I run make there is a Makefile but this Makefile does not reference this file.
Still this line is going well.
The path where it fails says
make diags
and I have verified there is no "diags" target.
I will print here the error file that can give us more info of what is happening
GEN cortex_a/output/Makefile
Init diag test "orc_scheduler" ...
remoteconfig: Failed to generate configure in cortex_a/soc/visio/tests/orc_scheduler!
Makefile:11 recipe for target 'orc_scheduler-init' failed
make[10]: *** [orc_scheduler-init] Error 25
At least what I would like to know is how to interpret this error message. I don't know what the "11" or the "10" or the "25" refers to.
make is fundamentally a tool for automatically running commands in the right order so you don't have to type them in yourself. So all the commands make runs are commands that you could just type into your shell prompt. And all the errors that those commands generate are the same ones that you would see if you typed the command yourself. So, looking at make to try to understand those errors is looking in the wrong place: you have to look at the documentation for whatever command was invoked.
A "target" is just a file that make knows how to build. The fact that when you typed make <somefile> is didn't give you an error that it doesn't know how to build <somefile>, means that <somefile> is a target as far as your makefiles are concerned.
The error message Makefile:11: simply refers to the filename Makefile, line 11, which is where the command that make ran, that failed, can be found. But this likely won't help you solve the problem of why the command failed (unless the problem is you invoked it with the wrong arguments and you need to adjust the makefile to specify different arguments).
The command that failed generated the message:
remoteconfig: Failed to generate configure in cortex_a/soc/visio/tests/orc_scheduler!
I don't know what that means, but it's not related to make. You'll need to find out what this remoteconfig command is, what it does, and why it failed. It's unfortunate that it doesn't show any better error message as to why it failed to "generate configure", but again there's nothing make can do about that.
If you want to learn more about make you can look at the GNU make manual (note, GNU make is only one implementation of make; there are others and they are fundamentally the same but different in details).

Conditional inclusion of patch file in recipe script

I have recipe file and my SRC_URI section looks something as follows:
SRC_URI += "file://file1.patch \
file://file2.patch \
file://file4.patch \
"
I want to include a file5.patch under the SRC_URI only if a certain environment variable is set. Is there a way to insert a if condition with the SRC_URI that looks something like this:
SRC_URI += "file://file1.patch \
file://file2.patch \
file://file4.patch \
**if $ENVIRONMENT_VARIABLE:
file://file5.patch**
"
Is there any other way I can achieve the same thing?
Well, the short answer is: yes, you can do this, but it's messy and there's probably a Better Way(TM). So let's answer the question first. If you really want to change the behavior of a recipe using an environment variable, the first challenge is to set the environment variable, and then let bitbake know that your new environment variable is safe and allowable. When you source the oe-init-build-env script to setup your project or subsequently to setup your new shell to continue working on the project, it sets an env variable called BB_ENV_EXTRAWHITE. You must include your new env variable in this list like this:
$ export MYENV_VAR=file5.patch
$ export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE MYENV_VAR"
Once this is done, then bitbake won't scrub the environment of your new environment variable.
In your recipe, use a python snippet to conditionally add your patch as follows:
SRC_URI += "${#os.getenv('MYENV_VAR', '')}"
As you can see, it's a bit messy. Of course, you could get a little more complex and test the value of the variable in your recipe, instead of putting the name of the patch file in your environment variable, but this example was the simplest way to demonstrate the concept.
Perhaps a better way is to use an override, and not rely on environment variables. If you are building a bsp with multiple variants, you could use your bsp name as the override, something like this.
SRC_URI_append_mybsp = "file://file5.patch"
This is a much cleaner way to accomplish the same thing. Of course, I'm speculating about your use case. The yocto project reference manual explains overrides. One more suggestion, join #yocto or the yocto project mailing list and you will have access to many smart people to help you.
Hope this helps. ;)
The proper way to accomplish this would be as follows,
1. local.conf
# comment the following line to remove file5.patch
ENV_VAR = "1"
NOTE: Don't forget to include the double quotes, otherwise Yocto will throw error.
2. recipe.bbappend
SRC_URI += "${#bb.utils.contains('ENV_VAR', '1', 'file://file5.patch', '', d)}"
Instead of local.conf you're free to use any .conf file. It's taken from Yocto mailing list

Get autocompletion list in bash variable

I'm working with a big software project with many build targets. When typing make <tab> <tab> it shows over 1000 possible make targets.
What I want is a bash script that filters those targets by certain rules. Therefore I would like to have this list of make targets in a bash variable.
make_targets=$(???)
[do something with make_targets]
make $make_targets
It would be best if I wouldn't have to change anything with my project.
How can I get such a List?
#yuyichao created a function to get autocomplete output:
comp() {
COMP_LINE="$*"
COMP_WORDS=("$#")
COMP_CWORD=${#COMP_WORDS[#]}
((COMP_CWORD--))
COMP_POINT=${#COMP_LINE}
COMP_WORDBREAKS='"'"'><=;|&(:"
# Don't really thing any real autocompletion script will rely on
# the following 2 vars, but on principle they could ~~~ LOL.
COMP_TYPE=9
COMP_KEY=9
_command_offset 0
echo ${COMPREPLY[#]}
}
Just run comp make '' to get the results, and you can manipulate that. Example:
$ comp make ''
test foo clean
You would need to overwrite / modify the completion function for make. On Ubuntu it is located at:
/usr/share/bash-completion/completions/make
(Other distributions may store the file at /etc/bash_completion.d/make)
If you don't want to change the completion behavior for the whole system, you might write a small wrapper script like build-project, which calls make. Then write a completion function for that mapper which is derived from make's one.

startup script in freebsd is not running

I have been trying to run a shell script at boot time of freebsd. I have read all simmilar questions in stackoverflow and tried. But nothing is worked. This is the sample code that i tried is dummy.
#!/bin/sh
. /etc/rc.subr
name="dummy"
start_cmd="${name}_start"
stop_cmd=":"
dummy_start()
{
echo "Nothing started."
}
load_rc_config $name
run_rc_command "$1"
Saved with name of dummy.
Permissions are -r-xr-xr-x.
in rc.conf file made dummy_enable="YES".
The problem is, when i rebooted my system to test, dummy file is not there. So script is not executing. what else need to do run my dummy script.
SRC:http://www.freebsd.org/doc/en/articles/rc-scripting/article.html#rc-flags
You need to add rcvar="dummy_enable" to your script. At least for FreeBSD 9.1.
Call your script with parameter rcvar to get the enabled status:
# /etc/rc.d/dummy rcvar
# dummy
#
dummy_enable="YES"
# (default: "")
And finally start it with parameter start - this won't start the service/script unless dummy_enable is set in /etc/rc.conf (or /etc/rc.conf.local, or /etc/defaults/rc.conf)
# /etc/rc.d/dummy start
Nothing started.
One possible explanation is that rcorder(8) says:
Within each file, a block containing a series of "REQUIRE", "PROVIDE",
"BEFORE" and "KEYWORD" lines must appear.
Though elsewhere I recall that if a file doesn't have "REQUIRE", "PROVIDE" or "BEFORE", then it will be arbitrarily placed in the dependency ordering. And, it could be that the arbitrary placement differs between the first run up to $early_late_divider and in the second run of those after $early_late_divider.
OTOH, is this a stock FreeBSD, or some variant? I recall reading that FreeNAS saves its configuration somewhere else and recreates its system files on every boot. And, quite possibly that /etc is actually on a ramdisk.
Also, /usr/local/etc/rc.d doesn't come into existence until the first port installing an rc file is installed.

Why does make lose variable settings when called recursively?

I barely know enough makefile stuff to hack away at other people's makefiles, and sometimes not even that much. My current employer has a fairly sophisticated make environment, and I added a couple targets to the makefile, mostly to self-document all the switches I needed. (There might be a better way to do this...if there is, please let me know!!)
Anyway, the first target works as expected. The second target is identical to the first, except that the BENCH assignment has a "2" at the end. Otherwise, its the same exact call. At some point during execution, the BENCH variable gets used to create a directory. The first target creates the directory as expected. The second target creates the directory using the default BENCH name instead of the one passed to it. Somehow it lost the variable setting at the command line, even though almost identical syntax worked for the first target.
Why does it lose my variable settings when it calls itself? Is there some make subtlety that I'm missing? Is this even a valid thing to do?
comp_gate_oct04_ff:
make clean all BENCH=GATE_OCT04_FF SIMULATOR=NC SIM_64BIT=1 CORNER=FF NETLIST=oct04 | tee all_gate_oct04_ff.log
#tail all_gate_oct04_ff.log | mail -s "Compile for GATE_OCT04_FF is complete" $(SMS_ADDR) $(USER)
comp_gate_oct04_ff2:
make clean all BENCH=GATE_OCT04_FF2 SIMULATOR=NC SIM_64BIT=1 CORNER=FF NETLIST=oct04 | tee all_gate_oct04_ff2.log
#tail all_gate_oct04_ff2.log | mail -s "Compile for GATE_OCT04_FF2 is complete" $(SMS_ADDR) $(USER)
I can't see why you're getting this error, and I can't reproduce it. Try something simpler:
comp_gate_oct04_ff:
make foo BENCH=GATE_OCT04_FF
comp_gate_oct04_ff2:
make foo BENCH=GATE_OCT04_FF2
foo:
#echo BENCH is $(BENCH)
Tell us how this behaves and we'll go from there.
EDIT:
All right, we've cut the problem in half. Now try this:
comp_gate_oct04_ff:
make clean
make all BENCH=GATE_OCT04_FF SIMULATOR=NC SIM_64BIT=1 CORNER=FF NETLIST=oct04
comp_gate_oct04_ff2:
make clean
make all BENCH=GATE_OCT04_FF2 SIMULATOR=NC SIM_64BIT=1 CORNER=FF NETLIST=oct04

Resources