Bundling C/C++ projects in Cabal package made easy.
(The code doesn't need to be in C or C++, it just has to expose a C ABI)
Add a custom setup stanza to your Cabal file:
custom-setup
setup-depends:
base
, Cabal
, cabal-bundle-clibReplace your default Setup.hs with the following code:
import Development.CabalBundleCLib (mainWithCLib)
import Development.CabalBundleCLib.CMake (simpleCMakeBuilder)
main :: IO ()
main = mainWithCLib
"cpp_proj" -- C project root directory, relative to package root directory
["mycpplib"] -- C library names
["."] -- Direct parent dirs for built libraries, relative to build root dir.
simpleCMakeBuilder -- The builderFor now, we only provide one builder: simpleCMakeBuilder. This builder
basically calls cmake --build, and doesn't take care of cmake install.
NOTE External native libraries, such as stdc++, still need to be listed
in extra-libraries as normal.
The library is extensible. You can write your own builder if your C project
doesn't use CMake, or has some complex build process. The provided
simpleCMakeBuilder is a good example to get started.
Furthermore, there are several example packages provided.
example-appAn application that bundles C code.example-libA library that bundled C Code.example-lib-consumerAn application that depends onexample-lib, but has no knowledge of the C code used inexample-lib
This library is tested against:
- Cabal and cabal-install 2.4.1.0, using v2 build
- stack 1.9.1 with
lts-13.0 - cmake 3.13.2
Traditionally, there are two ways to organize a project that contains both Haskell and C code
- List the C files in
c-sourcesof Cabal file, and let cabal build them - Build and install the C project manually (or use external package managers,
such as
apt), then list the relative installation path inextra-lib-dirs
However, neither way is perfect. With the first method, we are forced to let
Cabal build the C code, and you may want to use CMake, for example. And if you
are trying to bundle a third-party C library with its own build system, this
approach won't work. With the second method, the build process of the C project
is not managed by Cabal. You have to make sure the libraries are properly
installed on the system. What's worse, an application developer have to take
care of any C libraries used by the Haskell libraries he/she use, even
transitive dependencies. For example, to use the library hmatrix, whether
directly or indirectly, you will have to install libblas liblapack, etc.
So, we want an approach to bundle a C project inside a Cabal package. The package developer can edit the C code at any time, and cabal should detect the changes and trigger incremental build. Just as if he/she is editing Haskell code. If the package is a library, then for consumers of the package, they do not need to know there exists some C code in that library.
There is a blog providing some basic ideas of this approach. It makes the C
code transparent to library users. However, using the exact code posted in that
blog, the development process is not satisfactory. It builds the C code in
configure stage due to some 'limitations' of Cabal, which means cabal v2-build will not trigger an incremental build of the C code. Based on that blog,
I improved the implementation to satisfy the requirements stated above.