I use execute_process to run a shell script,
set(CMAKE_C_FLAGS ...) # here ... means many options
execute_process(
COMMAND ./my_script.sh)
In my_script.sh I want to use the value of CMAKE_C_FLAGS and how to do it?
When echo ${CMAKE_C_FLAGS} in script, I get nothing.
CMake variables are not environment variables.
You can set an environment variable like so:
set(CMAKE_C_FLAGS ...)
set(ENV{CMAKE_C_FLAGS} "${CMAKE_C_FLAGS}")
execute_process(COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/my_script.sh")
Note that this lasts only for the duration of the CMake configure step. This means it will work with execute_process, but not add_custom_command.
Also note that calling a shell script from CMake is a code smell (hinders portability, is weird and probably unnecessary).
Related
I have a parameterised function in mytestprogram.cmake written like below:
function(get_output_from_input output input)
set(${output} "test" PARENT_SCOPE)
endfunction()
Question:
How do I call the cmake method get_output_from_input from a shell script?
I learnt that there is -P <source.cmake> flag, that puts CMake into script processing mode and we can execute arbitrary CMake code with it using something like below.
execute_process(COMMAND ${CMAKE_PROGRAM} -P yourscript.cmake)
So, in this case I believe the way to call get_output_from_input from a shell script would be something like below?
input="some_input"
output=""
execute_process(get_output_from_input(output, input) ${CMAKE_PROGRAM} -P mytestprogram.cmake)
echo $output
But above trick does not work. Is the way I am running execute_process correct?
Trying to figure out whats wrong, it seems echo $CMAKE_PROGRAM returns empty? Could that be the reason? What am I missing here to call get_output_from_input?
Environment:
cmake version 3.18.2
macOS Catalina
cmake -P executes an entire script, not a single function defined in a CMake file, so need to add an additional script file that you can then execute via cmake -P. Arguments to a script executed via cmake -P need to be passed as CMake variables, e.g. cmake -DINPUT=some_input -P myscript.cmake .
Since you need the output of the CMake script in an bash variable, the CMake script "mytestscript.cmake" would look something like this:
# make `get_output_from_input` available in current script
# assuming the script file is located next to `mytestprogram.cmake`
include(${CMAKE_CURRENT_LIST_DIR}/mytestprogram.cmake)
get_output_from_input(RESULT "${INPUT}")
message("${RESULT}")
and the shell script contains
#!/bin/bash
input="some_input"
# assumes `mytestscript.cmake` is located in the current working directory
output=$(cmake -DINPUT="${input}" -P mytestscript.cmake 2>&1)
# Below statement should print the value of output.
echo $output
Regarding execute_process: That is meant to be used if you need to execute another process from within a CMake script, not to execute a CMake script from a shell process. Depending on what you plan to do with the output of the CMake script you could possibly use execute_process instead of additional bash.
What I think you're asking for—setting a Bash variable directly from CMake's script mode—is impossible. The script mode (-P) just lets you run CMake code without a project / build directory. And execute_process is a CMake command, not a shell command, so calling it from sh/bash is bound to fail.
The CMake function you wrote is wrong, too. All it does is write to a local variable which is never read and immediately gets destroyed. You probably wanted set(VAR "VALUE" PARENT_SCOPE). The return() is pointless and should be removed.
If you explained a bit more about what you were trying to do, maybe this question would be answerable.
Here's a basic demonstration of CMake's script mode:
# ./script.cmake
# Input variable: file
# Output: md5sum of file
cmake_minimum_required(VERSION 3.19)
file(MD5 "${file}" hash)
message("${hash}")
Running this from the terminal (equiv. a shell script):
$ ls
my_file.txt script.cmake
$ cat my_file.txt
Hello, world!
$ cmake -Dfile=my_file.txt -P script.cmake
746308829575e17c3331bbcb00c0898b
I didn't find anything about that, and i am trying to wrote this rule in my Makefile.
setenv:
#echo "export DYLD_LIBRARY_PATH=."
#echo "export DYLD_INSERT_LIBRARIES=$(NAME).so"
#echo "export DYLD_FORCE_FLAT_NAMESPACE=1"
#echo "# Run eval $$(make setenv)"
So by running eval $(make setenv) in my terminal, the environment variable will be set.
But it's starting an infinite loop.
I've also try with:
\$(make setenv)
but nothing work ... What is the correct syntax for this ?
EDIT:
\$$(make setenv) Did the trick !
If you're setting environment variables for other recipes, note that:
Using $(shell export ...) won't work: $(shell ...) always spawns a new shell, so anything that is exported into it won't be available outside of that particular invocation;
Using export shell commands in a recipe will only work if .ONESHELL is used (not recommended), because each recipe line runs in a different shell.
The typical way to export environment variables to sub-makes and sub-shells is to use export as a Makefile directive, like this:
export DYLD_LIBRARY_PATH=.
export DYLD_INSERT_LIBRARIES=$(NAME).so
export DYLD_FORCE_FLAT_NAMESPACE=1
Outside any recipe.
What does CC=/path/to/afl/afl-gcc ./configure do? (see. AFL's Readme)
Is it telling GCC to look into that directory for files?
(Maybe something like a path-variable, because of the =-character?)
Strange thing also: there is no configure-exe. in that directory.
When you write
A=B C
The shell runs the command C with the environment variable A set to B.
The CC environment variable is commonly used to tell configure scripts where a C compiler is located.
This is a combination of two actions:
Set the environment variable CC to /path/to/afl/afl-gcc
Execute ./configure (with that environment variable)
If both actions are on one line, the environent variable is only passed to this command and is not stored in the environment of the current shell.
The CC can be used to tell the configure script which c comiler to use.
Is there a way to detect whether a variable has been set from the environment vs. on the command line?
I would like to distinguish between someone invoking make with make LIB=mylib vs. make and $LIB being defined.
Yes. You can use the origin function to determine where a variable was defined.
ifneq (,$(findstring environment,$(origin LIB)))
# LIB was defined by the environment
else
# LIB was defined some other way
endif
With non-Gnu make, you could run the export command and grep for the variable in question. This works only in rules and only as long as the variable is not set as a one-shot (like in LIB=foo make).
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.