Compiling an app to work on both Ubuntu 16 and 18

When I compile a Crystal app in ubuntu 16.04 it “binds” to, but when installed on a ubuntu 18.04 machine it won’t start and instead report:

error while loading shared libraries: cannot open shared object file: No such file or directory

as ubuntu 18.04 only comes with libevent-2.1.

Is there a way around this or do we need to compile one version of the app per OS version?

Another way would be to install the missing library on the target machine.

Not sure if that is “allowed” by the package manager.
Don’t know if that helps, but you can show the needed libs and where they are found with “ldd”

for example:

 mavu   master  ~  repo  sx10control  ldd sx10control (0x00007fff5d9cd000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735d4b0000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735d41f000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735d137000) => /lib/x86_64-linux-gnu/ (0x00007f735cf19000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735ccfb000) => /lib/x86_64-linux-gnu/ (0x00007f735cc87000) => /lib/x86_64-linux-gnu/ (0x00007f735cb02000) => /lib/x86_64-linux-gnu/ (0x00007f735cae1000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735c88b000) => /lib/x86_64-linux-gnu/ (0x00007f735c881000) => /lib/x86_64-linux-gnu/ (0x00007f735c87c000) => /lib/x86_64-linux-gnu/ (0x00007f735c862000) => /lib/x86_64-linux-gnu/ (0x00007f735c69f000)
	/lib64/ (0x00007f735d9e5000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735c3c4000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735c1f5000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735a805000) => /lib/x86_64-linux-gnu/ (0x00007f735a5df000) => /usr/lib/x86_64-linux-gnu/ (0x00007f735a45a000)

With Linux that’s generally how it is: an application is expected to be compiled specifically for the system.
Alternatively, you can ship all the libraries (usually except libc) with the application.

1 Like

I’d recommend you to compile statically your app. It can be done in any Alpine Linux system. If you have Docker installed, you can look at

Yes, that’s what I’ve ended up doing, but with Vagrant. Noticed though that Alpine 3.7 have conflicts between libressl and openssl, so Alpine 3.6 was required for me to compile Crystal applications.


Vagrant.configure("2") do |config|
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"

  config.vm.define "alpine" do |node| = "alpine/alpine64"
    node.vm.box_version = "3.6.0"
    node.vm.provision "shell", inline: <<~SHELL
      apk update
      apk upgrade
      apk add crystal shards libc-dev libxml2-dev openssl-dev readline-dev gmp-dev yaml-dev

  config.vm.define "ubuntu" do |node| = "ubuntu/bionic64"
    node.vm.provision "shell", inline: <<~SHELL
      apt-key adv --keyserver --recv-keys 09617FD37CC06B54
      echo "deb crystal main" > /etc/apt/sources.list.d/crystal.list
      apt-get update
      apt-get install -y crystal help2man lintian

#!/bin/bash -eu
vagrant resume alpine || vagrant up alpine
vagrant ssh alpine -c "cd /vagrant; sudo shards build --release --production --static"
vagrant suspend alpine
vagrant resume ubuntu || vagrant up ubuntu
vagrant ssh ubuntu -c "cd /vagrant; build/deb $revision"
vagrant ssh ubuntu -c "cd /vagrant; build/tar $revision"
vagrant suspend ubuntu

where build/deb is a shell script that makes a deb package, but from the static executable built in Alpine.

1 Like

Neat @carlhoerberg! Take also care of using crystal and shards from the edge repo of Alpine to have the latest versions.

echo '@edge' >>/etc/apk/repositories
apk add --update crystal@edge shards@edge