Cabal foreign libraries
In this age of the stack
domination, not everyone remembers the role of Cabal
and cabal-install`. And still cabal and cabal-install do progress and introduce new features, that may benefit entire ecosystem. And it’s quite unfortunate that some of the changes remain unnoticed.
The big list of changes in Cabal-2.0 can be found here. In this post I’d like to look into one single change: Foreign libraries support.
TLDR: you can find all documentation in the cabal user-guide, which is a very good resource to read anyway.
Let’s look into the problem solved by this feature. Sometimes we need to use Haskell in projects written in other language. This can be done either by making an Haskell executable and using some RPC to communicate between different components or by making a shared object. For a long time cabal did not support shared objects definition. Common solution for that problem was to create an executable
section in cabal file, add ghc-options
-shared
and then play games with -fPIC
support. That solution was doable but painfull and required knowledge of low level details.
And finally in cabal-2.0 a support for that usecase was introduced. Now we have a new stanza, foreign-library
which means that Cabal
will build a standalone library to be used with foreign languages.
Inside foreign-library
block we can define type
of the library:
native-static
for static library (.a
);native-shared
for the dynamic library (.so
).
Currently only native-shared
are supported.
If you are using windows you should remember to add options: standlone
stanza. With this option libHSrts
will not be required. You should not set this option otherwise.
A simple example:
foreign.cabal
:
foreign-library mylib
type: native-shared
lib-version-info: 6:3:2
build-depends: base >=4.9 && <4.10
hs-source-dirs: src
other-modules Lib
default-language: Haskell2010
If you have foreign exported modules, then you should also provide:
library
build-depends: base >= 4.9 && <4.10
hs-source-dirs: src
other-modules: Lib
install-includes: Lib_stub.h
default-language: Haskell2010
We need Lib_stub.h
so header file will be installed in the system. See #5299. This workaround helps with the problem but still you will not be able to call cabal sdist
because it will try to copy autogenerated file that does not exist in filesystem.
src/Lib.hs
:
module Lib (fac) where
foreign export ccall fac :: Int -> Int
fac :: Int -> Int
fac n = product [1..n]
After cabal install
you’ll get:
~/.cabal/
~//cabal/libmylib.so -> libmylib.so.4.2.3
~/.cabal/libmylib.so.4 -> libmylib.so.4.2.3
~/.cabal/libmylib.so.4.2.3
~/.cabal/lib/x86_64-linux-ghc-8.0.2/foreign-0.1.0.0-22cwmsmBVpIHoSDwDYFUR6/include/Lib_stub.h
Enjoy!
Update: problem with sdist
can be worked around by using a buildinfo trick
- create
foreign.buildinfo
file with the following contents:install-includes: Lib_stub.h
- add section to cabal:
extra-tmp-files: foreign.buildinfo
- remove
install-includes
stanza - now sdist works.
Enjoy again!
comments powered by Disqus