Skip to content

Instantly share code, notes, and snippets.

@andreabedini
Created July 31, 2023 04:47
Show Gist options
  • Save andreabedini/a3b012345124854c2fe58380dfe3d4ae to your computer and use it in GitHub Desktop.
Save andreabedini/a3b012345124854c2fe58380dfe3d4ae to your computer and use it in GitHub Desktop.

Building a native shared library with cabal

$ cabal build
Resolving dependencies...
Build profile: -w ghc-9.4.5 -O1
In order, the following will be built (use -v for more details):
...
 - ngx-export-distribution-test-0.1.0.0 (flib:ngx-export-distribution-test) (first run)
Configuring foreign library 'ngx-export-distribution-test' for ngx-export-distribution-test-0.1.0.0..
Preprocessing foreign library 'ngx-export-distribution-test' for ngx-export-distribution-test-0.1.0.0..
Building foreign library 'ngx-export-distribution-test' for ngx-export-distribution-test-0.1.0.0..
[1 of 1] Compiling NgxDistributionTest ( NgxDistributionTest.hs, /home/andrea/Scratchpad/ngx-export-distribution-test/dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/ngx-export-distribution-test-tmp/NgxDistributionTest.dyn_o )
[2 of 2] Linking /home/andrea/Scratchpad/ngx-export-distribution-test/dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so
$ ldd dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so
        linux-vdso.so.1 (0x00007fff1a71a000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fe61f715000)
        libffi.so.8 => /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libffi.so.8 (0x00007fe61f400000)
        libHSngx-export-1.7.5-9a953ec123414a4c4c7cccd9fb2cb5dcc93a680d144b79274679e1da2625fd4b-ghc9.4.5.so => /home/andrea/.local/state/cabal/store/ghc-9.4.5/ngx-export-1.7.5-9a953ec123414a4c4c7cccd9fb2cb5dcc93a680d144b79274679e1da2625fd4b/lib/libHSngx-export-1.7.5-9a953ec123414a4c4c7cccd9fb2cb5dcc93a680d144b79274679e1da2625fd4b-ghc9.4.5.so (0x00007fe61f688000)
        libHSunix-2.7.3-ghc9.4.5.so => /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSunix-2.7.3-ghc9.4.5.so (0x00007fe61f31b000)
...
        libHSghc-prim-0.9.0-ghc9.4.5.so => /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSghc-prim-0.9.0-ghc9.4.5.so (0x00007fe61b200000)
        libHSrts-1.0.2-ghc9.4.5.so => /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSrts-1.0.2-ghc9.4.5.so (0x00007fe61cc66000)
        libgmp.so.10 => /lib64/libgmp.so.10 (0x00007fe61cbc2000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe61b003000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe61f82f000)
        librt.so.1 => /lib64/librt.so.1 (0x00007fe61d709000)
        libutil.so.1 => /lib64/libutil.so.1 (0x00007fe61d704000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fe61cbbd000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe61cbb8000)

There are many ways to collect all these libs together. The most straightforward I have found is using linuxdeploy:

$ wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
...
2023-07-31 12:42:31 (12.8 MB/s) - ‘linuxdeploy-x86_64.AppImage.1’ saved [13509824/13509824]
$ chmod +x linuxdeploy*.AppImage
$ ./linuxdeploy-x86_64.AppImage --appdir AppDir --library dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so


linuxdeploy version 1-alpha (git commit ID 17ca786), GitHub actions build 180 built on 2023-07-13 19:42:48 UTC

-- Creating basic AppDir structure --
Creating directory AppDir/usr/bin/
Creating directory AppDir/usr/lib/
Creating directory AppDir/usr/share/applications/
Creating directory AppDir/usr/share/icons/hicolor/
Creating directory AppDir/usr/share/icons/hicolor/16x16/apps/
Creating directory AppDir/usr/share/icons/hicolor/32x32/apps/
Creating directory AppDir/usr/share/icons/hicolor/64x64/apps/
Creating directory AppDir/usr/share/icons/hicolor/128x128/apps/
Creating directory AppDir/usr/share/icons/hicolor/256x256/apps/
Creating directory AppDir/usr/share/icons/hicolor/scalable/apps/

-- Deploying dependencies for existing files in AppDir --

-- Deploying shared libraries --
Deploying shared library dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so
Deploying dependencies for ELF file dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so
Skipping deployment of blacklisted library /lib64/libm.so.6
Deploying shared library /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libffi.so.8
Deploying shared library /home/andrea/.local/state/cabal/store/ghc-9.4.5/ngx-export-1.7.5-9a953ec123414a4c4c7cccd9fb2cb5dcc93a680d144b79274679e1da2625fd4b/lib/libHSngx-export-1.7.5-9a953ec123414a4c4c7cccd9fb2cb5dcc93a680d144b79274679e1da2625fd4b-ghc9.4.5.so
Deploying shared library /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSunix-2.7.3-ghc9.4.5.so
...
Deploying shared library /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSghc-bignum-1.3-ghc9.4.5.so
Deploying shared library /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSghc-prim-0.9.0-ghc9.4.5.so
Deploying shared library /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSrts-1.0.2-ghc9.4.5.so
Skipping deployment of blacklisted library /lib64/libgmp.so.10
Skipping deployment of blacklisted library /lib64/libc.so.6
Skipping deployment of blacklisted library /lib64/librt.so.1
Skipping deployment of blacklisted library /lib64/libutil.so.1
Skipping deployment of blacklisted library /lib64/libdl.so.2
Skipping deployment of blacklisted library /lib64/libpthread.so.0

-- Copying files into AppDir --
Copying file dist-newstyle/build/x86_64-linux/ghc-9.4.5/ngx-export-distribution-test-0.1.0.0/f/ngx-export-distribution-test/build/ngx-export-distribution-test/libngx-export-distribution-test.so to AppDir/usr/lib/libngx-export-distribution-test.so
Copying file /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSarray-0.5.4.0-ghc9.4.5.so to AppDir/usr/lib/libHSarray-0.5.4.0-ghc9.4.5.so
Copying file /home/andrea/.ghcup/ghc/9.4.5/lib64/ghc-9.4.5/lib/x86_64-linux-ghc-9.4.5/libHSbase-4.17.1.0-ghc9.4.5.so to AppDir/usr/lib/libHSbase-4.17.1.0-ghc9.4.5.so
...
Copying file /home/andrea/.local/state/cabal/store/ghc-9.4.5/witherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58/lib/libHSwitherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58-ghc9.4.5.so to AppDir/usr/lib/libHSwitherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58-ghc9.4.5.so
Calling strip on library AppDir/usr/lib/libHSOneTuple-0.4.1.1-e1611e67a77ed62be2ec0bb0e4f2f5591d45e517529330fc726f5ab10a4576cd-ghc9.4.5.so
Calling strip on library AppDir/usr/lib/libHSQuickCheck-2.14.3-d498a9537fc03bed8a6f9fff07960fa37e1ad191ecb3c9ee8bf7decc3bf6196c-ghc9.4.5.so
...
Calling strip on library AppDir/usr/lib/libHSwitherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58-ghc9.4.5.so
Calling strip on library AppDir/usr/lib/libffi.so.8
Calling strip on library AppDir/usr/lib/libngx-export-distribution-test.so
Setting rpath in ELF file AppDir/usr/lib/libHSOneTuple-0.4.1.1-e1611e67a77ed62be2ec0bb0e4f2f5591d45e517529330fc726f5ab10a4576cd-ghc9.4.5.so to $ORIGIN
Setting rpath in ELF file AppDir/usr/lib/libHSQuickCheck-2.14.3-d498a9537fc03bed8a6f9fff07960fa37e1ad191ecb3c9ee8bf7decc3bf6196c-ghc9.4.5.so to $ORIGIN
...
Setting rpath in ELF file AppDir/usr/lib/libHSwitherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58-ghc9.4.5.so to $ORIGIN
Setting rpath in ELF file AppDir/usr/lib/libffi.so.8 to $ORIGIN
Setting rpath in ELF file AppDir/usr/lib/libngx-export-distribution-test.so to $ORIGIN

-- Copying files into AppDir --

-- Deploying files into AppDir root directory --
WARNING: Could not find desktop file in AppDir, cannot create links for AppRun, desktop file and icon in AppDir root`
$ tree AppDir
AppDir
└── usr
    ├── bin
    ├── lib
    │   ├── libffi.so.8
    │   ├── libHSaeson-2.2.0.0-bed6bf412dba7797768750303d108edfa405e1c831248f59aa6b8acc2131912d-ghc9.4.5.so
    │   ├── libHSarray-0.5.4.0-ghc9.4.5.so
...
    │   ├── libHSvector-0.13.0.0-45717532419dd6453c543dc13f2ef915f0749d24bb0e507a450dae190d54b958-ghc9.4.5.so
    │   ├── libHSvector-stream-0.1.0.0-7089620515557d479f030f3001ed5d31f50b77755b47e76b47e9ded9cb711699-ghc9.4.5.so
    │   ├── libHSwitherable-0.4.2-bdbaee8f5aa3d3818a84a37d2284833ab827fdbfd2e62760615f0321db8ead58-ghc9.4.5.so
    │   └── libngx-export-distribution-test.so
    └── share
        ├── applications
        └── icons
            └── hicolor
                ├── 128x128
                │   └── apps
                ├── 16x16
                │   └── apps
                ├── 256x256
                │   └── apps
                ├── 32x32
                │   └── apps
                ├── 64x64
                │   └── apps
                └── scalable
                    └── apps

20 directories, 66 files
cabal-version: 3.0
name: ngx-export-distribution-test
version: 0.1.0.0
license: NONE
author: andrea@andreabedini.com
maintainer: Andrea Bedini
build-type: Simple
flag standalone
default: False
manual: True
common warnings
ghc-options: -Wall
foreign-library ngx-export-distribution-test
import: warnings
type: native-shared
if flag(standalone)
options: standalone
other-modules: NgxDistributionTest
build-depends: base ^>=4.17.1.0
, aeson
, bytestring
, ngx-export
default-language: Haskell2010
{-# LANGUAGE TemplateHaskell #-}
module NgxDistributionTest where
import NgxExport
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy.Char8 as C8L
import Data.Aeson
import Data.Maybe
incCnt :: ByteString -> C8L.ByteString
incCnt = C8L.pack . show . succ . fromMaybe (0 :: Int) . decodeStrict
ngxExportYY 'incCnt
@andreabedini
Copy link
Author

Note you can also build a shared library with RTS and all Haskell libraries statically linked into it.
There are some minor issues though:

  • cabal's user guide says it's not supported on Linux
  • GHC bindists come with non-relocatable boot packages, so you will need a suitably built GHC.
  • libffi linking it a bit weird

Working with a self-compiled GHC these days is not too hard though:

$ cat build.mk
GhcLibHcOpts += -fPIC
GhcRtsHcOpts += -fPIC
GhcRtsCcOpts += -fPIC
BuildFlavour = quick
$ ghcup compile ghc -v 9.4.5 -b 9.0 -o 9.4-fpic --config build.mk

PS1: it might also need -fexternal-dynamic-refs
PS2: Hadrian equivalent seems to be hadrian/build --docs=none --flavour=quick "*.*.ghc.*.opts += -fPIC -fexternal-dynamic-refs" "*.*.cc.*.opts += -fPIC but ghcup seems to have some issues with Hadrian.

@Kleidukos
Copy link

Kleidukos commented Nov 21, 2023

cabal's user guide says it's not supported on Linux

@andreabedini I think this should be more specific: This is not supported with glibc because glibc doesn't support static linking anymore. However with alpine this should probably be supported?

@andreabedini
Copy link
Author

@andreabedini I think this should be more specific: This is not supported with glibc because glibc doesn't support static linking anymore. However with alpine this should probably be supported?

Yes, this should be more specific. Let's see if we can make progress on haskell/cabal#9320

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment