I'm writing a program in Crystal, that I intend to compile and move to other systems for execution. Ideally, it should have no dependencies, as the target systems will be fresh installations of linux.
Sadly, I can't get around the libc dependency, so I will presumably have to compile the executable on a system possessing the lowest version of libc I wish to target. I figure it should be forward-compatible.
I'm having difficulty with libssl, however. Default installations of Debian Wheezy don't seem to come with libssl, so I get this error when running my executable:
error while loading shared libraries: libssl.so.1.0.0:
cannot open shared object file: No such file or directory
I assume this dependency exists because I require "http/client"
in my source. However, I make no ssl-related calls, as I only use it to connect to unsecured websites.
I apparently also have a dependency on libevent-2.0.so.5
. Presumably all Crystal programs do. Who knows how many other dependencies Crystal has?
My executables have to run on a freshly-installed linux system. So, how can I produce a Crystal executable with no dependencies? Other than libc, I suppose.
In Linux, you can list the shared libraries that an executable needs using the ldd
command. In OSX, otool -L
could be used for the same purpose.
Normally, the linker will use shared libraries while building the executable if it can find them. So, what you need to do, is force the linker to use static libraries instead. (In the future we might add a flag to the compiler to force this choice)
You should find some of these static libraries in /opt/crystal/embedded/lib. We use these to generate a portable Crystal compiler.
In order to use these libraries you can run:
$ LIBRARY_PATH=/opt/crystal/embedded/lib crystal build my_app.cr
That should prefer libraries available in that directory before considering others installed in the standard locations.
Unfortunately, OpenSSL is not distributed with Crystal, so you must either copy or build a static version of libssl
and libcrypto
. It's a common library anyway, available in any Linux distribution.
Regarding libc
, that's more tricky. We compile the Crystal binary for releases using old CentOS and Debian distributions to make it compatible with many more libc versions.
The Crystal docs mention that the --static
compiler flag currently only works on Alpine Linux (and recommends using an Alpine Linux Docker container).
If you are not into Docker but happen to have Vagrant on your machine, you can use my Alpine box (relativkreativ/alpine) instead of going through the hassle of building your own.
In either case, static linking works on Alpine.
Just run the following steps:
/etc/apk/repositories
apk update
the get the latest package listapk add crystal shards
apk add libc-dev
(a meta-package which does just that)Once this is done, you can compile your Crystal project with crystal build src/FILE.cr -o bin/FILE --release --static
.
Now having a Crystal binary with no dependencies allows you to easily distribute your project as RPM, for example (which is how I found this question in the first place).
I also summarised this in an article on my website.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With