Is there a way to get the complete command line used to invoke make?
I invoked my make using --print-data-base and I cannot find any make variable that contains the string --print-data-base nor its shorthand -p.
I did find, in the print database, the line
-*-command-variables-*- := MAKEFILES=C:/Users/mureadr/Desktop/A/ImpTarget.mk
but nothing that shows the complete command-line used to invoke make.
I don't think it's possible to print the original command line, but you can peek at each part of it with the following variables
$(error $(MAKE) $(MAKEFLAGS) $(MAKEOVERRIDES) $(MAKECMDGOALS))
Related
Beginner in bash and makefiles here. I have a course where we need to create a makefile where each rule calls one of the already compiled programs. All of the compiled programs take a command line argument. As the arguments can be quite large and mostly consists of the same character in a row (for example AAAAAAA) I made a script that uses python to print the argument. Example:
#!/bin/bash
python -c 'print "A"*1000 + "Q"*200'
I am wondering how to create the rule in the makefile so that the output of the above script will be passed as the command line argument. Essentially like this:
test:
./schoolprogram ./myprogram.sh
So when make test is executed then ./schoolprogram should be run with the argument 1000 A's followed by 200 Q's and not the literal string "./myprogram.sh".
I don't know why you have a script that does nothing but invoke python; why not just run python directly?
In any event, this isn't really a makefile question it's mostly a shell question. When writing makefile recipes, the best way is to get the command you want to run working at your shell prompt, then take that same command (with one small tweak) and put it into your makefile.
In the shell, you can use either $(...) or backticks (an older style) to run a command and replace it with the output of that command. So you can run this:
$ ./schoolprogram $(./myprogram.sh)
or more easily:
$ ./schoolprogram $(python -c 'print "A"*1000 + "Q"*200')
Now when you take a command and put it into a makefile recipe, the thing you have to remember is that the $ character is special to make, so if you want a $ to be passed to your command you have to escape it by doubling it, $$. So you'd write:
test:
./schoolprogram $$(./myprogram.sh)
or equivalently:
test:
./schoolprogram $$(python -c 'print "A"*1000 + "Q"*200')
I am trying to learn Make syntax, I have instructed it to compile a file and it does this correctly, when I tell it to execute a shell command to create a file using touch it does not do this, it returns no error to indicate anything is wrong.
Commands
HelloWorld: HelloWorld.c
gcc -o HelloWorld HelloWorld.c
FILES="$(shell touch > file1.txt)"
As pointed out already your syntax is wrong. But beyond that your shell function is never even executed.
Why not? Because in your makefile, you define a variable which contains the shell variable invocation but then you never use the variable anywhere. Since you don't use it, the variable is never expanded. Since the variable is never expanded, the function in it is never invoked.
If you want the variable to be expanded you either need to make it a simple variable (using :=) so that the right-hand side is expanded when the variable is assigned, or you have to use the function in a context where it's expanded immediately; the other answer has an example of using that (outside of any variable assignment)
Here's an example of using a simple variable:
HelloWorld: HelloWorld.c
gcc -o HelloWorld HelloWorld.c
FILES := $(shell touch file1.txt)
(note you don't need quotes when setting makefile variables, unlike shell variables).
As for the manual, it's written to be a user guide: that is you're supposed to read it starting at the beginning, rather than a reference manual where you jump around. In particular you won't get anywhere writing makefiles until you read carefully and fully understand the initial two chapter "Introduction to Makefiles" and "Writing Makefiles". For fluency you need to understand the section How make Reads a Makefile.
I think you want:
$(shell touch file1.txt)
(Notice the lack of a > redirect in there). Also touch does not output anything to stdout, therefore FILES would be blank no matter what, so the assignment is useless.
If you're going to do things like this be aware that the $(shell ...) commands (in the global scope) are executed at parse time, before any of the recipes are run.
------------ EDIT -------------
In regards to your question about creating a blank file:
all:
$(info output $(shell echo "hello world"))
$(shell touch file1.txt)
should produce your file:
> ls file1.txt; make; ls file1.txt
file1.txt
output hello world
make-3.81: Nothing to be done for `all'.
file1.txt
I found many answers here and elsewhere on the topic, but none that worked. Please help me out here.
I need to set some environment variables, which is partly done in some scripts, called from a master script, partly directly. Here is a minimal Makefile that shows the unwanted behaviour:
FC := ifort
SHELL := /bin/bash
some_target: load_ifort
$(FC) file.f
load_ifort:
source /usr/local2/bin/ifort-compilervars.sh ia32
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic
if I call make, I get an "ifort: command not found" error. If I execute the two comamnds by hand on the command line before calling make, ifort is found and everything is good.
What am I missing???
Each line in a recipe gets executed in a separate subshell. So you create one shell which sources the .sh file, then exits and forgets everything, then another shell which starts with a clean slate.
The straightforward solution in your case would be to collect all these commands in a single variable. I have factored out the LM_LICENSE_FILE assignment because that can be done in Make directly, but you could include that in the FC variable as well.
LM_LICENSE_FILE := /usr/local2/misc/intel2013/flexlm/server.lic
export LM_LICENSE_FILE
FC := source /usr/local2/bin/ifort-compilervars.sh ia32; \
ifort
some_target:
$(FC) file.f
If the shell commands can be straightforwardly run by Make as well, you could include them, or perhaps translate the sh file into Make commands by a simple script.
Another option would be to create a simple wrapper in your PATH; maybe call it fc:
#!/bin/sh
. /usr/local2/bin/ifort-compilervars.sh ia32
ifort "$#"
then just use fc where you currently have $(FC). (If the ifort-compilervars.sh file contains Bash constructs, in spite of the name, you should change the shebang to #!/bin/bash.)
As a rule, only one-liner shell commands "work". From the comment about "bash", it seems likely you are using GNU make. In your example, the word "source" is not found in the GNU make manual's index. (If you found this in a working example, it would be helpful to start from that). There are two types of variables of interest:
makefile variables, which live in the make program
environment variables, which are "exported"
The latter would include $PATH, which is used to find programs. For updating that, you do need shell commands. But (lacking some special provision in the make program), exported variables from a shell script are not passed up into the make program and made available for the next line of the makefile.
You could reorganize the makefile to provide a rule which combines the source command and other initialization into a shell command which then recurs (carrying those variables along) into a subprocess which would then do the compiles. Something like
build:
sh -c "source /usr/local2/bin/ifort-compilervars.sh ia32; \
export LM_LICENSE_FILE=/usr/local2/misc/intel2013/flexlm/server.lic; \
$(MAKE) some_target"
some_target: load_ifort
$(FC) file.f
The Makefile is written as the followings:
all:
iceking='$#';
echo $$iceking;
However the output is as the followings:
[root#localhost test]# make
iceking='all';
echo $iceking;
The string 'all' doesn't output. Why?
New sub-shell for each line of the recipe.
From GNU make manual:
When it is time to execute recipes to update a target, they are
executed by invoking a new sub-shell for each line of the recipe...
Set of shell commands, that called by your makefile is equivalent to:
bash -c iceking='all';
bash -c echo $iceking;
The variable iceking is not accessible from the environment of the second invocation of bash. That's why you receive empty output.
.ONESHELL (only since GNU make 3.82)
One way to fix it, is use .ONESHELL special target. From GNU make manual:
If the .ONESHELL special target appears anywhere in the makefile then
all recipe lines for each target will be provided to a single
invocation of the shell.
But there is one problem with .ONESHELL, this feature was added only since version 3.82 of GNU make.
One line recipes.
Another way to fix it, is write recipes in one line, since all commands in the line will be passed to a single invocation of the shell.
all:
iceking='$#'; echo $$iceking;
So, to compile my executable, I need to have the library locations set up correctly. The problem is, the setup comes from a bunch of scripts that do the env variable exporting, and what needs to be set up may change (beyond my control) so I need to use those scripts instead of copying their functionality. To compile in regular command line, I need to do something like:
setup library1
setup library2
source some_other_setup_script.bash
g++ blah.c
# setup is a executable on my system that run some scripts
How would I write a makefile that accomplishes that? As far as I tried, the env variable exporting does not carry over (i.e. "export VAR=remember; echo $VAR" won't work)
You can also add environment variables properly with the machinery of GNU make, like so:
export TEST:="Something Good!"
test:
echo $$TEST
This (I think) has different semantics from:
TEST2:="Something not quite so useful?"
test2:
echo ${TEST2}
Which (again, I think) does the substitution within make before passing along to the shell. Note that the export command doesn't work within a target block, just unindented as an immediately executed command.
If variable exporting is not working the way it does on your command line, that suggests that Make is choosing a shell different from the one you're using, with different syntax for handling variables (export VAR=remember; echo $VAR works fine for me). Make uses /bin/sh by default, but you can override this with the SHELL variable, which Make does not import from the environment. I suggest setting SHELL (in the Makefile) to whatever you're using in your environment and trying the export VAR=remember experiment again.
Ultimately you will need to define the variable and execute the compiler in a shell list or even a script, rather than in separate make commands. There are a couple of refinements you could add, however. You could tell make about the script:
maintarget: script.sh blah.c
source script.sh; g++ blah.c
script.sh:
setup include script here
Another thing would be to just execute all that stuff in the same shell
maintarget: blah.c
run this; run that; run the other thing; g++ blah.c
I believe all make versions will run a ; list in the same shell, but you can always force a subshell with (list) or by calling specifically a shell script as a compiler command wrapper.
Don't forget to have the appropriate targets depend on your scripts themselves. BTW, some make versions (pmake aka bsd make) can execute a command when defining a make variable, and all versions of make then exports those. But I don't think gmake can do that.
You could write another shell script that executes all those commands, then prints out variable assignments that make can use. Run the script, pipe its output to a file, then include that file from your Makefile. For example:
Makefile:
all:
echo $(FOO)
test.mk: test.sh
./$< > $#
include test.mk
test.sh
echo "FOO=1"
Running "make" in the directory containing this Makefile produces:
make: Entering directory `/home/luser/build/mktest'
Makefile:7: test.mk: No such file or directory
./test.sh > test.mk
make: Leaving directory `/home/luser/build/mktest'
make: Entering directory `/home/luser/build/mktest'
echo 1
1
make: Leaving directory `/home/luser/build/mktest'
make creates test.mk by running the shell script, then includes it. test.mk contains the output of test.sh, and is parsed as a Makefile. See http://www.gnu.org/software/make/manual/make.html#Include for more details.
We use a variant of this in Mozilla's client.mk to let you define options in a "mozconfig" file:
http://mxr.mozilla.org/mozilla-central/source/client.mk#138
Restatement: How do I get a shell variable into a make file?
Something like:
MYVAR := $(shell echo $(MYVAR)) <any_makefile_additions_here>
So, this defines MYVAR inside a MAKEFILE when an environment variable named MYVAR is also set.
It might be of interest, that, in order to override an option that is already defined in a makefile, make supports (I am referring to GNU Make 3.82, but other version probably too) the option -e.
Example:
Makefile:
CC=gcc
...
Run make:
CC=gcc-4.7
make -e
will use gcc-4.7 instead of gcc.