Note that this is a related to Statically Link
So we started a greenfield project at work using OCaml/Reason (we are mainly a Scala based team) and we have successfully deployed however we noticed an issue that we need some help in.
The issue comes across making executable that can run without any runtime C dependencies, we need this due to our CDP build system. Since OCaml produces native bytecode, you basically have to do static linking for the platform. To be clear, the libraries which contain C dependencies which we are trying to static link are ocaml-ssl (https://github.com/savonet/ocaml-ssl) which binds to the openssh library and also libev which is used by conf-libev
.
There is a guide on how to do this here http://rgrinberg.com/posts/static-binaries-tutorial/ however the main issue is that global static linking (i.e. using (flags (-ccopt -static))
) doesn’t work on MacOS (note that MacOS perfectly supports static linking specific dependency, just not every dependency in your project). This leaves to solutions for us. Most of our developers use machines that have MacOS for local development, however in production we deploy docker containers which run linux.
- The ideal (or perfect) solution is to only statically link the
libev
andopenssh
library on every platform. Unfortunately I haven’t managed to figure out how to do this using-ccopt
flags. These flags are directly passed intold
however with a lot of searching I haven’t actually managed to figure out how to only statically linkopenssl
/libev
(I know there is a-l
flag that can be passed intold
to do this, but I didn’t manage to get it to work in an agnostic way. Furthermore it has the known issue that it will always pick up the dynamic.dynlib
/.so
libraries over the static.a
files, so you need a manual prepossessing step to deal with this. - The less ideal solution is to allow you to build your project with an optional flag (i.e. something like
--static-linux
) so that by default it uses dynamic libraries but in our build systems on linux we can just build with--static-linux
). The issue is I haven’t managed to figure this out withesy
/dune
(esy
just usesdune
under the hood). Firstly someone on discord recommended me to use theenv
stanza to conditionally add the(flags (-ccopt -static))
flags and then use--profile
indune
however the issue with this is thatesy
uses the-p
(i.e. package flag) to build dune projects which can’t be mixed with--profile
. I also had issues just getting theenv
command to work when running dune directly, i.e. if you have a trivial dune file as shown
(library
(name lib)
(public_name hello-ocaml)
(libraries lambda-term lwt lwt_ssl))
Where would you put the env
stanza, i.e. would you put it here
(env
(static-linux (flags (:standard -ccopt -static))))
(library
(name lib)
(public_name hello-ocaml)
(libraries lambda-term lwt lwt_ssl))
Or here
(library
(name lib)
(env
(static-linux (flags (:standard -ccopt -static))))
(public_name hello-ocaml)
(libraries lambda-term lwt lwt_ssl))
Note that in this case I still have the issue that I cant do something like dune build --profile=static-linux -p hello
because the flags don’t mix.
Anyone have any recommendation on what to do here?