I keep seeing
eval $(opam env)
e.g. when I try to install coq:
# brew install opam # for mac
# for ubuntu
conda install -c conda-forge opam
opam init
# if doing local env?
# eval $(opam env)
# - install coq
# local install
#opam switch create . 4.12.1
#eval $(opam env)
#opam repo add coq-released https://coq.inria.fr/opam/released
#opam install coq
# If you want a single global (wrt conda) coq installation (for say your laptop):
opam switch create 4.12.1
opam switch 4.12.1
opam repo add coq-released https://coq.inria.fr/opam/released
opam install coq
but I never know what it does (nor no one I talk to knows) and when I google it this comes up instead: What is the use of eval `opam config env`?
cross posted: https://discuss.ocaml.org/t/what-does-eval-opam-env-do-does-it-activate-a-opam-environment/9990
Note that
eval `opam config env`
might be very similar. In the sense that I think the dashes ''
are also command substitution as in $(...)
but not sure. Which might make What is the use of eval `opam config env`? very related (though I don't know the difference for sure)
tldr: it activates your opam context according to your current switch -- similar to how a python virtual env is activated in python but for opam.
What eval $(opam env)
does is command substitute $(opam env)
i.e. run opam env
in a subshell (that's what $( )
does) return the string it outputted and then give it to eval
to evaluate as bash code. Command substitution is usually done to next the output of commands in bash. In python eval
would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume it's bash (is my guess).
What does opam env
does? It returns the current bash env variables for the current swithc (i.e. siwth approximately euqal to opam environment). So therefore, doing:
eval $(opam env)
does this:
$(cmd)
does. It's command substitution. Usually used to nest commands.$(opam env)
) is given to eval
. opam env
returns a string of env variables needed to "activate: the current opam env (similar to how you activate virtual envs in python).eval
evaluates the string it receives from the command substitution i.e. it parses the string as a bash command and runs it.For compeleteness see the output of opam env
:
(iit_synthesis) brandomiranda~ ❯ opam env
OPAM_SWITCH_PREFIX='/Users/brandomiranda/.opam/4.12.1'; export OPAM_SWITCH_PREFIX;
CAML_LD_LIBRARY_PATH='/Users/brandomiranda/.opam/4.12.1/lib/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml'; export CAML_LD_LIBRARY_PATH;
OCAML_TOPLEVEL_PATH='/Users/brandomiranda/.opam/4.12.1/lib/toplevel'; export OCAML_TOPLEVEL_PATH;
PATH='/Users/brandomiranda/.opam/4.12.1/bin:/Users/brandomiranda/miniconda/envs/iit_synthesis/bin:/Users/brandomiranda/miniconda/condabin:/usr/local/bin:/Users/brandomiranda/.opam/4.12.1/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin'; export PATH;
Please note : The back ticks shown around
opam env
aftereval
are essential. They change the order of application, which is very important. The back ticks tells the system to first evaluateopam env
(which returns a string of commands) and theneval
executes those commands in the string. Executing them doesn’t return anything, but it initializes the Opam environment behind the scenes. ref: https://ocaml.org/docs/up-and-running
also see:
From the man page for opam env:
This is most usefully used as eval $(opam env) to have further shell commands be evaluated in the proper opam context.
see: https://opam.ocaml.org/doc/man/opam-env.html
Slightly more details:
Finally, to get all the pieces together, what is the difference between command substitution (e.g. $( ) or
) and evaluating an expression (e.g. eval string or eval $(cmd) ) (in bash mainly). Ref: https://unix.stackexchange.com/a/23116/55620. My understanding is that $( ) runs a command in a subshells and outputs the string so that it's string is an input to another command e.g. eval. So to my understanding you can think of $(cmd) as replacing that expression and pasting the string of it back to to the command line for another commadn e.g. eval. While eval will take in the string and evaluate the expression in it instead. So what eval $(cmd) does is first evaluate $(cmd) replace it with the output string of running cmd in a subshell and then feeding it to eval -- where eval will pretend that input is code and evaluate it, parse and run it. So $(...) is usually done to nest command inside other commands.
The only puzzling thing to me is why $(cmd) without a cmd2 (eg eval) in the front interprets the strings of $(cmd) as bash commands to run instead of just evaluting e.g. (iit_synthesis) brandomiranda~ ❯ $(echo v=1) zsh: command not found: v=1
but
(iit_synthesis) brandomiranda~ ❯ v=1 (iit_synthesis) brandomiranda~ ❯ echo $v 1
does evaluate my string v=1 and then run it.
Thus what eval $(opam env) does is command substitute $(opam env) i.e. run opam env in a subshell return the string it outputted and then given to eval to evaluate as bash code. In python eval would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume its bash (is my guess)
toolchain = In software, a toolchain is a set of programming tools that is used to perform a complex software development task or to create a software product, which is typically another computer program or a set of related programs. https://www.google.com/search?q=toolchain&oq=toolchain&aqs=chrome..69i57j0i512l9.209j0j7&sourceid=chrome&ie=UTF-8
(iit_synthesis) brandomiranda~ ❯ opam env
OPAM_SWITCH_PREFIX='/Users/brandomiranda/.opam/4.12.1'; export OPAM_SWITCH_PREFIX;
CAML_LD_LIBRARY_PATH='/Users/brandomiranda/.opam/4.12.1/lib/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml/stublibs:/Users/brandomiranda/.opam/4.12.1/lib/ocaml'; export CAML_LD_LIBRARY_PATH;
OCAML_TOPLEVEL_PATH='/Users/brandomiranda/.opam/4.12.1/lib/toplevel'; export OCAML_TOPLEVEL_PATH;
PATH='/Users/brandomiranda/.opam/4.12.1/bin:/Users/brandomiranda/miniconda/envs/iit_synthesis/bin:/Users/brandomiranda/miniconda/condabin:/usr/local/bin:/Users/brandomiranda/.opam/4.12.1/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin'; export PATH;
so opam env
outputs a bunch of paths that are needed for the toolchain to work...perhaps here toolchain == opam? Based on What is the use of eval `opam config env` or eval $(opam env) and their difference? (question for eval opam config env
) I am inferring that what it means is that these are the bash env variables needed to "activate the ocaml/opam environment". Concluded that because opam env
outputs a bunch of env variables.
So running opam env
by itself only prints the output to the terminal the output of the command opam env
.
$ usually refers that the identifier is a variable. e.g. $x is the variable x while x in the terminal is literally the string x (or command x if it exists).
$(command) or command
is command substitution. So doing $(command) runs the output (e.g. the script that would have been printed to the terminal after running command) of command. I assume it's called command substitution because we substitute command with the output of it and try to run it. e.g. it says: In computing, command substitution is a facility that allows a command to be run and its output to be pasted back on the command line as arguments to another command in the wikipedia article so yes. https://en.wikipedia.org/wiki/Command_substitution
opam env = opam-env - Prints appropriate shell variable assignments to stdout. Returns the bindings for the environment variables set in the current switch, e.g. PATH, in a format intended to be evaluated by a shell. https://opam.ocaml.org/doc/man/opam-env.html note that same opam man page says This is most usefully used as eval $(opam env) to have further shell commands be evaluated in the proper opam context.
Finally, to get all the pieces together, what is the difference between command substitution (e.g. $( ) or
) and evaluating an expression (e.g. eval string or eval $(cmd) ) (in bash mainly). Ref: https://unix.stackexchange.com/a/23116/55620. My understanding is that $( ) runs a command in a subshells and outputs the string so that it's string is an input to another command e.g. eval. So to my understanding you can think of $(cmd) as replacing that expression and pasting the string of it back to to the command line for another commadn e.g. eval. While eval will take in the string and evaluate the expression in it instead. So what eval $(cmd) does is first evaluate $(cmd) replace it with the output string of running cmd in a subshell and then feeding it to eval -- where eval will pretend that input is code and evaluate it, parse and run it. So $(...) is usually done to nest command inside other commands.
The only puzzling thing to me is why $(cmd) without a cmd2 (eg eval) in the front interprets the strings of $(cmd) as bash commands to run instead of just evaluting e.g. (iit_synthesis) brandomiranda~ ❯ $(echo v=1) zsh: command not found: v=1
but
(iit_synthesis) brandomiranda~ ❯ v=1 (iit_synthesis) brandomiranda~ ❯ echo $v 1
does evaluate my string v=1 and then run it.
Thus what eval $(opam env) does is command substitute $(opam env) i.e. run opam env in a subshell return the string it outputted and then given to eval to evaluate as bash code. In python eval would interpret the input string to it as literal python code to evaluate, parse, run here similarly it would do the same but assume its bash (is my guess)
Eval vs $( ) details:
Playground 1
(iit_synthesis) brandomiranda~ ❯ clear
(iit_synthesis) brandomiranda~ ❯ $(echo v=1)
zsh: command not found: v=1
(iit_synthesis) brandomiranda~ ❯ v=1
(iit_synthesis) brandomiranda~ ❯ echo $v
1
Playground 2
(iit_synthesis) brandomiranda~ ❯ echo vv=2
vv=2
(iit_synthesis) brandomiranda~ ❯ $(echo vv=2)
zsh: command not found: vv=2
(iit_synthesis) brandomiranda~ ❯ eval $(echo vv=2)
(iit_synthesis) brandomiranda~ ❯ echo $vv
2