Packaging a C++ package#
This tutorial will guide you though making a C++ package with rattler-build
.
Header-only library#
Here we will build a package for the header-only library xtensor
. The package
depends on cmake
and ninja
for building.
The main "trick" is to instruct CMake
to install the headers in the right
prefix, by using the CMAKE_INSTALL_PREFIX
setting. On Unix, conda
packages
follow the regular "Unix" prefix standard ($PREFIX/include
and $PREFIX/lib
etc.). On Windows, it also looks like a "Unix" prefix but it's nested in a
Library
folder ($PREFIX/Library/include
and $PREFIX/Library/lib
etc.). For
this reason, there are some handy variables (%LIBRARY_PREFIX%
and
%LIBRARY_BIN%
) that can be used in the CMake
command to install the headers
and libraries in the right place.
context:
version: "0.24.6"
package:
name: xtensor
version: ${{ version }}
source:
url: https://github.com/xtensor-stack/xtensor/archive/${{ version }}.tar.gz
sha256: f87259b51aabafdd1183947747edfff4cff75d55375334f2e81cee6dc68ef655
build:
number: 0
script:
- if: win
then: |
cmake -GNinja \
-D BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=%LIBRARY_PREFIX% \
%SRC_DIR%
ninja install
else: |
cmake ${CMAKE_ARGS} -GNinja -DBUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
$SRC_DIR
ninja install
requirements:
build:
- ${{ compiler('cxx') }}
- cmake
- ninja
host:
- xtl >=0.7,<0.8
run:
- xtl >=0.7,<0.8
run_constraints:
- xsimd >=8.0.3,<10
tests:
- package_contents:
include:
- xtensor/xarray.hpp
files:
- share/cmake/xtensor/xtensorConfig.cmake
- share/cmake/xtensor/xtensorConfigVersion.cmake
about:
homepage: https://github.com/xtensor-stack/xtensor
license: BSD-3-Clause
license_file: LICENSE
summary: The C++ tensor algebra library
description: Multi dimensional arrays with broadcasting and lazy computing
documentation: https://xtensor.readthedocs.io
repository: https://github.com/xtensor-stack/xtensor
extra:
recipe-maintainers:
- some-maintainer
A C++ application#
In this example we will build poppler
, a C++ application to manipulate PDF
files from the command line. The final package will install a few tools into the
bin/
folder.
context:
version: "24.01.0"
package:
name: poppler
version: ${{ version }}
source:
url: https://poppler.freedesktop.org/poppler-${{ version }}.tar.xz
sha256: c7def693a7a492830f49d497a80cc6b9c85cb57b15e9be2d2d615153b79cae08
build:
script: poppler-build.sh
requirements:
build:
- ${{ compiler('c') }} # (1)!
- ${{ compiler('cxx') }}
- pkg-config
- cmake
- ninja
host:
- cairo # (2)!
- fontconfig
- freetype
- glib
- libboost-headers
- libjpeg-turbo
- lcms2
- libiconv
- libpng
- libtiff
- openjpeg
- zlib
tests:
- script:
- pdfinfo -listenc # (3)!
- pdfunite --help
- pdftocairo --help
- We use the
compiler
function to get the compiler for C and C++. - These are all the dependencies that we link against
- The script test just executes some of the installed tools to check if they are working. You could run some more complex tests if you want.
We've defined an external build script in the recipe. This will be searched next
to the recipe by the file name given (or by the default name build.sh
or
build.bat
).
#! /bin/bash
extra_cmake_args=(
-GNinja
-DCMAKE_INSTALL_LIBDIR=lib
-DENABLE_UNSTABLE_API_ABI_HEADERS=ON
-DENABLE_GPGME=OFF
-DENABLE_LIBCURL=OFF
-DENABLE_LIBOPENJPEG=openjpeg2
-DENABLE_QT6=OFF
-DENABLE_QT5=OFF
-DENABLE_NSS3=OFF
)
mkdir build && cd build
cmake ${CMAKE_ARGS} "${extra_cmake_args[@]}" \
-DCMAKE_PREFIX_PATH=$PREFIX \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DTIFF_INCLUDE_DIR=$PREFIX/include \
$SRC_DIR
ninja
# The `install` command will take care of copying the files to the right place
ninja install
When you look at the output of the rattler-build
command you might see some
interesting information.
Our package will have some run
dependencies (even though we did not specify
any). These run-dependencies come from the "run-exports
" of the packages we
depend on in the host
section of the recipe. This is shown in the output of
rattler-build
along with "RE of [host: package]"
.
Basically, libcurl
declares "if you depend on me in the host section, then you
should also depend on me during runtime with the following version ranges". This
is important to make linking to shared libraries work correctly.
Run dependencies:
╭───────────────────────┬──────────────────────────────────────────────╮
│ Name ┆ Spec │
╞═══════════════════════╪══════════════════════════════════════════════╡
│ libcurl ┆ >=8.5.0,<9.0a0 (RE of [host: libcurl]) │
│ fontconfig ┆ >=2.14.2,<3.0a0 (RE of [host: fontconfig]) │
│ fonts-conda-ecosystem ┆ (RE of [host: fontconfig]) │
│ lcms2 ┆ >=2.16,<3.0a0 (RE of [host: lcms2]) │
│ gettext ┆ >=0.21.1,<1.0a0 (RE of [host: gettext]) │
│ freetype ┆ >=2.12.1,<3.0a0 (RE of [host: freetype]) │
│ openjpeg ┆ >=2.5.0,<3.0a0 (RE of [host: openjpeg]) │
│ libiconv ┆ >=1.17,<2.0a0 (RE of [host: libiconv]) │
│ cairo ┆ >=1.18.0,<2.0a0 (RE of [host: cairo]) │
│ libpng ┆ >=1.6.42,<1.7.0a0 (RE of [host: libpng]) │
│ libzlib ┆ >=1.2.13,<1.3.0a0 (RE of [host: zlib]) │
│ libtiff ┆ >=4.6.0,<4.7.0a0 (RE of [host: libtiff]) │
│ libjpeg-turbo ┆ >=3.0.0,<4.0a0 (RE of [host: libjpeg-turbo]) │
│ libglib ┆ >=2.78.3,<3.0a0 (RE of [host: glib]) │
│ libcxx ┆ >=16 (RE of [build: clangxx_osx-arm64]) │
╰───────────────────────┴──────────────────────────────────────────────╯
We can also observe some "linking" information in the output, for example on macOS:
[lib/libpoppler-glib.8.26.0.dylib] links against:
├─ @rpath/libgio-2.0.0.dylib
├─ @rpath/libgobject-2.0.0.dylib
├─ /usr/lib/libSystem.B.dylib
├─ @rpath/libglib-2.0.0.dylib
├─ @rpath/libpoppler.133.dylib
├─ @rpath/libfreetype.6.dylib
├─ @rpath/libc++.1.dylib
├─ @rpath/libpoppler-glib.8.dylib
└─ @rpath/libcairo.2.dylib
rattler-build
performs these checks to make sure that:
- All shared libraries that are linked against are present in the run dependencies. If you link against a library that is not explicitly mentioned in your recipe, you will get an "overlinking" warning.
- You don't require any packages in host that you are not linking against. this is the case, you will get an "overdepending" warning.