Compiling an app to work on both Ubuntu 16 and 18


#1

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

error while loading shared libraries: libevent-2.0.so.5: 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?


#2

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
	linux-vdso.so.1 (0x00007fff5d9cd000)
	libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f735d4b0000)
	libssl.so.1.1 => /usr/lib/x86_64-linux-gnu/libssl.so.1.1 (0x00007f735d41f000)
	libcrypto.so.1.1 => /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 (0x00007f735d137000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f735cf19000)
	libyaml-0.so.2 => /usr/lib/x86_64-linux-gnu/libyaml-0.so.2 (0x00007f735ccfb000)
	libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f735cc87000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f735cb02000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f735cae1000)
	libevent-2.1.so.6 => /usr/lib/x86_64-linux-gnu/libevent-2.1.so.6 (0x00007f735c88b000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f735c881000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f735c87c000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f735c862000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f735c69f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f735d9e5000)
	libicui18n.so.63 => /usr/lib/x86_64-linux-gnu/libicui18n.so.63 (0x00007f735c3c4000)
	libicuuc.so.63 => /usr/lib/x86_64-linux-gnu/libicuuc.so.63 (0x00007f735c1f5000)
	libicudata.so.63 => /usr/lib/x86_64-linux-gnu/libicudata.so.63 (0x00007f735a805000)
	liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f735a5df000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f735a45a000)

#3

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.


#4

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 https://hub.docker.com/r/jrei/crystal-alpine


#5

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.

Vagrantfile:

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

  config.vm.define "alpine" do |node|
    node.vm.box = "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
    SHELL
  end

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

build.sh:

#!/bin/bash -eu
revision=$1
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.


#6

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

echo '@edge http://dl-cdn.alpinelinux.org/alpine/edge/community' >>/etc/apk/repositories
apk add --update crystal@edge shards@edge