How to specify LD_LIBRARY_PATH via add_custom_command? - linux

I am trying to add ld_library_path via cmake.
What I have done so far is
add_custom_command(TARGET ${target}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${target}> ${PROJECT_BINARY_DIR}/bin
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND $<TARGET_FILE:${target}>
################ ENV Set here ####################
-E env "LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}:${PROJECT_SOURCE_DIR}/boost_linux/lib"
COMMENT "Running Tests Now .. " VERBATIM
)
But I am still getting linking error during runtime. Does any one know how to properly link lib path.
In bash it would be like
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/path/to/lib

It's not clear what exactly you're trying to achieve and how it is related to a linking error. But the way you run commands with custom environment variables is the following:
add_custom_command(
...
COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=..."
actual command line that you need to execute
)
So, -E env works such that it executes whatever is passed after env variable specification.
Note, however, that you cannot use multiple COMMAND arguments and set env in the first one while using it in the following COMMANDs - it won't work. Or, at least, it is generator-dependent. With Make backend this is translated into multiple calls to shell - so it sets the env but the rest of commands are executed separately and don't see it. Ninja generator translates multiple COMMANDs into something like cmd1 && cmd2 && ... so it works there, AFAIK.

Related

Dockerfile set ENV based on npm package version [duplicate]

Is it possible to set a docker ENV variable to the result of a command?
Like:
ENV MY_VAR whoami
i want MY_VAR to get the value "root" or whatever whoami returns
As an addition to DarkSideF answer.
You should be aware that each line/command in Dockerfile is ran in another container.
You can do something like this:
RUN export bleah=$(hostname -f);echo $bleah;
This is run in a single container.
At this time, a command result can be used with RUN export, but cannot be assigned to an ENV variable.
Known issue: https://github.com/docker/docker/issues/29110
I had same issue and found way to set environment variable as result of function by using RUN command in dockerfile.
For example i need to set SECRET_KEY_BASE for Rails app just once without changing as would when i run:
docker run -e SECRET_KEY_BASE="$(openssl rand -hex 64)"
Instead it i write to Dockerfile string like:
RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'
and my env variable available from root, even after bash login.
or may be
RUN /bin/bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" > /etc/profile.d/docker_init.sh'
then it variable available in CMD and ENTRYPOINT commands
Docker cache it as layer and change only if you change some strings before it.
You also can try different ways to set environment variable.
This answer is a response to #DarkSideF,
The method he is proposing is the following, in Dockerfile :
RUN bash -l -c 'echo export SECRET_KEY_BASE="$(openssl rand -hex 64)" >> /etc/bash.bashrc'
( adding an export in the /etc/bash.bashrc)
It is good but the environment variable will only be available for the process /bin/bash, and if you try to run your docker application for example a Node.js application, /etc/bash.bashrc will completely be ignored and your application won't have a single clue what SECRET_KEY_BASE is when trying to access process.env.SECRET_KEY_BASE.
That is the reason why ENV keyword is what everyone is trying to use with a dynamic command because every time you run your container or use an exec command, Docker will check ENV and pipe every value in the process currently run (similar to -e).
One solution is to use a wrapper (credit to #duglin in this github issue).
Have a wrapper file (e.g. envwrapper) in your project root containing :
#!/bin/bash
export SECRET_KEY_BASE="$(openssl rand -hex 64)"
export ANOTHER_ENV "hello world"
$*
and then in your Dockerfile :
...
COPY . .
RUN mv envwrapper /bin/.
RUN chmod 755 /bin/envwrapper
CMD envwrapper myapp
If you run commands using sh as it seems to be the default in docker.
You can do something like this:
RUN echo "export VAR=`command`" >> /envfile
RUN . /envfile; echo $VAR
This way, you build a env file by redirecting output to the env file of your choice. It's more explicit than having to define profiles and so on.
Then as the file will be available to other layers, it will be possible to source it and use the variables being exported. The way you create the env file isn't important.
Then when you're done you could remove the file to make it unavailable to the running container.
The . is how the env file is loaded.
As an addition to #DarkSideF's answer, if you want to reuse the result of a previous command in your Dockerfile during in the build process, you can use the following workaround:
run a command, store the result in a file
use command substitution to get the previous result from that file into another command
For example :
RUN echo "bla" > ./result
RUN echo $(cat ./result)
For something cleaner, you can use also the following gist which provides a small CLI called envstore.py :
RUN envstore.py set MY_VAR bla
RUN echo $(envstore.py get MY_VAR)
Or you can use python-dotenv library which has a similar CLI.
Not sure if this is what you were looking for, but in order to inject ENV vars or ARGS into your .Dockerfile build this pattern works.
in your my_build.sh:
echo getting version of osbase image to build from
OSBASE=$(grep "osbase_version" .version | sed 's/^.*: //')
echo building docker
docker build -f \
--build-arg ARTIFACT_TAG=$OSBASE \
PATH_TO_MY.Dockerfile \
-t my_artifact_home_url/bucketname:$TAG .
for getting an ARG in your .Dockerfile the snippet might look like this:
FROM scratch
ARG ARTIFACT_TAG
FROM my_artifact_home_url/bucketname:${ARTIFACT_TAG}
alternatively for getting an ENV in your .Dockerfile the snippet might look like this:
FROM someimage:latest
ARG ARTIFACT_TAG
ENV ARTIFACT_TAG=${ARTIFACT_TAG}
the idea is you run the shell script and that calls the .Dockerfile with the args passed in as options on the build.

Makefile running export env having issue

I've created a Makefile to export a kubeconfig from fixed path like:
myproj
- .kube //folder
config //file which contain the config
- Makefile. //same level as .kube folder
Now when I'm running from the terminal the following it works, I mean if I run kubectl get ns I got results which means that it configure successfully!
export KUBECONFIG=/Users/i33333/projects/app-test/v-app/.kube/config
I've created a makefile target like following
kube-cfg:
export KUBECONFIG=$(PWD)/.kube/config
When execute the target I see in the terminal
export KUBECONFIG=/Users/i33333/projects/app-test/v-app/.kube/config
which exactly the same as doing that manually but when when I run kubectl get ns
I got error:
error: no configuration has been provided, try setting KUBERNETES_MASTER environment variable
I dont understand why it dosent work when I run it from makefile and works when I run it from the terminal manually ? any idea
I try to change and use also the $(CURRDIR) which doesnt help
update
I've tried like suggested which doesnt works
KUBECONFIG=$(PWD)/.kube/config
kube-cfg:
export $(KUBECONFIG)
update2
If I do it like this
KUBECONFIG := $(PWD)/kube/config.yaml
tgt1:
#export KUBECONFIG=$(KUBECONFIG) && kubectl get ns
I was able to see the ns when running the makefile tgt1: but
if now I want to run it from the terminal kubectl get ns I get the same error `error: no configuration has been provided, try setting KUBERNETES_MASTER environment variable, I want to configure it from the makefile
The problem is that makefile recipe creates new environment, which is destroyed after finishing recipe.
If you want to use kubernetes tools after calling make, more appropriate tool in your scenario is using source command. It applies in your current environment all changes made in script passed as parameter:
$ source setupenv.sh
$ kubectl get ns # should be no problem
$ make someting # even using kubectl inside make shouldn't be a problem
However if you want to use kubectl in make scripts, then create something like:
recipe :
source setupenv.sh && kubectl get ns
# or
recipe2 :
export KUBECONFIG=$(PWD)/.kube/config && kubectl get ns
UPDATE:
I thought config file is a script. So you should prepare shell script setting up environment, for example setupenv.sh:
#!/bin/bash
export KUBECONFIG=$(PWD)/.kube/config
When you run make the recipe is executed in a shell that is forked from make process. Also-recipes spanning multiple, each line (unless chained over newline escape) also gets its own shell child process. This effectively means, whatever happens (shell variable assignments or exports) in any of these shells, has no impact on the make itself or other recipe lines.
You could define for instance a make variable (as you have done in the update) and then you can set that in an environment for any command (somecmd) you are trying to run, e.g.:
some_target:
export KUBECONFIG=$(KUBECONFIG); somecmd
or:
some_target:
KUBECONFIG=$(KUBECONFIG) somecmd
In that case KUBECONFIG refers to a make variable, like the one you've defined above:
KUBECONFIG := $(PWD)/.kube/config
I.e. like this:
KUBECONFIG := $(PWD)/.kube/config
all: tgt1 tgt2
tgt1:
#export KUBECONFIG=$(KUBECONFIG); echo "KUBECONFIG is $${KUBECONFIG}"
tgt2:
#KUBECONFIG=$(KUBECONFIG) sh -c 'echo KUBECONFIG is $${KUBECONFIG}'
Yielding:
$ make
KUBECONFIG is /tmp/.kube/config
KUBECONFIG is /tmp/.kube/config
So, if you're after something that does persists also after the make is done, you need to write it out. E.g. a wrapper, such such as:
KUBECONFIG := $(PWD)/kube/config.yaml
.PHONY: call
# run callme.sh being the first prerequisite.
call: callme.sh
./$<
# creates and sets exec bit on rule target here being callme.sh
callme.sh:
#echo -e '#!/bin/bash\nKUBECONFIG=$(KUBECONFIG) kubectl get ns' > $#
chmod +x $#
This make you can run make and target call calls the wrapper... and you're also left with a wrapper callme.sh you can run after make is done.

source env variables files inside Makefile

so from my local machine I am able to do this:
. env_vars.env
and it works fine:
cat env_vars.env
#!/bin/bash
export abce=def
but when I try to reflect same in makefile it returns nothing:
SHELL=/bin/bash
print-env-vars:
. env_vars.env
echo ${abce}
I also tried with source env_vars.env inside makefile but output is still the same. Wondering how can I source variables inside the makefile.
Each line of a make recipe is executed by a separate shell, so even if you source the file, the shell that sources it exits before the next line is evaluated. It's equivalent to running the following from your shell:
bash -c '. env_vars.env'
bash -c 'echo ${abce}'
Put both commands on the same line (or use \ to split a single logical line across multiple physical lines) so that both are executed in the same shell. The semicolon is necessary so that the shell doesn't see . env_vars.env echo ${abce}
as the single command to run.
print-env-vars:
. env_vars.env; \
echo $${abce}
(The double dollar sign ensures that you actually pass a parameter expansion to the shell, rather than make trying to expand a make variable.)

Getting bash script to update parent shell's Environment

I am attempting to write a bash command line tool that is usable immediately after installation, i.e. in the same shell as its installation script was called. Lets say install-script.sh (designed for Ubuntu) looks like:
# Get the script's absolute path:
pushd `dirname $0` > /dev/null
SCRIPTPATH=`pwd`
popd > /dev/null
# Add lines to bash.bashrc to export the environment variable:
echo "SCRIPT_HOME=${SCRIPTPATH}" >> /etc/bash.bashrc
echo "export SCRIPT_HOME" >> /etc/bash.bashrc
# Create a new command:
cp ${SCRIPTPATH}/newcomm /usr/bin
chmod a+x /usr/bin/newcomm
The idea is that the new command newcomm uses the SCRIPT_HOME environment variable to reference the main script - which is also in SCRIPTPATH:
exec "${SCRIPT_HOME}/main-script.sh"
Now, the updated bash.bashrc hasn't been loaded into the parent shell yet. Worse, I cannot source it from within the script - which is running in a child shell. Using export to change SCRIPT_HOME in the parent shell would at best be duct-taping the issue, but even this is impossible. Also note that the installation script needs to be run using sudo so it cannot be called from the parent shell using source.
It should be possible since package managers like apt do it. Is there a robust way to patch up my approach? How is this usually done, and is there a good guide to writing bash installers?
You can't. Neither can apt.
A package manager will instead just write required data/variables to a file, which are read either by the program itself, by a patch to the program, or by a wrapper.
Good examples can be found in /etc/default/*. These are files with variable definitions, and some even helpfully describe where they're sourced from:
$ cat /etc/default/ssh
# Default settings for openssh-server. This file is sourced by /bin/sh from
# /etc/init.d/ssh.
# Options to pass to sshd
SSHD_OPTS=
You'll notice that none of the options are set in your current shell after installing a package, since programs get them straight from the files in one way or another.
The only way to modify the current shell is to source a script. That's unavoidable, so start there. Write a script that is sourced. That script will in turn call your current script.
Your current script will need to communicate with the sourced one to tell it what to change. A common way is to echo variable assignments that can be directly executed by the caller. For instance:
printf 'export SCRIPT_HOME=%q\n' "$SCRIPTPATH"
Using printf with %q ensures any special characters will be escaped properly.
Then have the sourced script eval the inner script.
eval "$(sudo install-script.sh)"
If you want to hide the sourceing of the top script you could hide it behind an alias or shell function.

using setenv in makefile

I am trying to use setenv variable in my makefile but when I execute my make file it gives setenv: command not found.
How can I use it?
Actually I wanted to run a shell script which sets multiple environment variables.
Since the list is very huge I dont have an option except to use the scripts. I cant set them manually like
abcd:= /xx/yy/zz
Please suggest.
P.S. the same command
setenv xxx yyy works very well in shell
it just fails when I use in makefile directly or makefile with a script having this command.
'
Why do not you use export command ?
Running the script to set the environment variable will not work as the shell run a separate process & will not reflect in your current shell. You will need to source the shell script. You can use source or . based on your shell. Following is a sample for your reference where setvar.sh sets a variable & print.sh prints it; in the Makefile (mkfile) setvar.sh is being sourced using .
$ cat setvar.sh
export TEST=ABC
$ cat print.sh
echo $TEST
$ cat mkfile
test:
. ./setvar.sh && ./print.sh
.SILENT:test
$ make -f mkfile
ABC
You can also include I guess for example,
$ cat mkfile2
include setvar.sh
test:
./print.sh
.SILENT:test
$ make -f mkfile2
ABC
Hope this helps!
Look at
make -e
and Communicating Variables to a Sub-make
I think setenv is not a builtin to the sh shell. If you are using GNU Make that is the default shell used. In your situation you probably want to use a different shell, like bash. You do this by setting the SHELL variable in the makefile to what you want like:
SHELL := /usr/bin/bash
For more information checkout this section of the GNU Make manual. It details the different behavior of the SHELL variable and how it is, or isn't inherited from the shell make is invoked from on different platforms.
EDIT: I agree with the implication of the other posters that you are probably not setting enviroment variables the way you think you should be and would not be using the setenv command at. I am just responding to your original question. To learn about variables in make files checkout these other sections in the GNU Make manual.
export MY_VAR := "/package/your_path"

Resources