= Consuming librnp in downstream projects This document describes how to use `librnp` — the RNP OpenPGP library — as a dependency of your own project: via CMake `find_package`, via pkg-config, via a package manager, or by embedding the sources. The public C API is declared in `include/rnp/rnp.h`, which is installed as `/include/rnp/rnp.h` together with `rnp_err.h`, `rnp_export.h` and `rnp_ver.h`. See link:c-usage.adoc[C API usage] for an introduction. == Choosing a crypto backend librnp is built against one crypto backend, selected at build time with `-DCRYPTO_BACKEND=`: * `botan` (default) — Botan 2.14 or later; use `botan3` to require Botan 3.x. Supports all features. * `openssl` — OpenSSL 1.1.1 or later. Some features are unsupported with this backend: SM2, Twofish, crypto-refresh (v6) support and PQC. The backend choice is recorded in the installed CMake and pkg-config files, so consumers automatically get the matching dependency (Botan or OpenSSL). == Shared vs static By default (`-DBUILD_SHARED_LIBS=ON`, the common case for packaged installations) librnp is installed as a shared library and linking `rnp::librnp` (CMake) or `-lrnp` (pkg-config/manual) is all a consumer needs. With `-DBUILD_SHARED_LIBS=OFF` a static `librnp.a` is installed, and consumers must also link the transitive dependencies (the crypto backend, zlib, bzip2 and sexpp). With CMake this happens automatically — see below. A static librnp built with the bundled sexpp sources installs `libsexpp.a` next to it and exports it as `rnp::sexpp`, so no separate sexpp installation is needed (unless rnp was built with `-DSYSTEM_LIBSEXPP=ON`, in which case the sexpp package is required at consume time). Note that librnp is written in C++. When linking the *static* library from a C project, the C++ runtime must be linked as well: with CMake enable the CXX language in your project, with manual flags link via the C++ compiler driver or add the C++ standard library explicitly (`-lc++` or `-lstdc++`). == CMake find_package The installed CMake package (`/lib/cmake/rnp/rnp-config.cmake`) resolves all transitive dependencies via `find_dependency()` and provides the imported target `rnp::librnp`: [source,cmake] -- cmake_minimum_required(VERSION 3.18) # CXX is only needed to link a static librnp (see above) project(example C CXX) find_package(rnp REQUIRED) add_executable(example main.c) target_link_libraries(example PRIVATE rnp::librnp) -- If rnp or its dependencies are installed in non-standard prefixes, list them in `CMAKE_PREFIX_PATH`: [source,console] -- cmake -B build -DCMAKE_PREFIX_PATH="/opt/rnp;/opt/botan" -- == pkg-config A pkg-config file is installed as `/lib/pkgconfig/librnp.pc`: [source,console] -- export PKG_CONFIG_PATH=/opt/rnp/lib/pkgconfig cc $(pkg-config --cflags librnp) main.c $(pkg-config --libs librnp) -o example -- For a static librnp, use `--static` to also get the private dependencies and link with the C++ driver: [source,console] -- cc $(pkg-config --cflags librnp) -c main.c c++ main.o $(pkg-config --libs --static librnp) -o example -- == vcpkg A vcpkg port for rnp is being prepared. Until it lands, install rnp from source and consume it via `find_package(rnp)` or pkg-config as described above — with vcpkg's CMake toolchain, adding the rnp installation prefix to `CMAKE_PREFIX_PATH` is enough for `find_package(rnp)` to work. == Prebuilt static libraries (release assets) Each librnp GitHub release ships per-target static-library tarballs alongside the source tarball. Each tarball bundles `librnp.a` plus a curated static build of every transitive dependency (sexpp, Botan or OpenSSL, zlib, bzip2), so downstream consumers can link against librnp without compiling the C++ + Botan stack from source and without any system package dependencies. This is intended for build systems that cannot reach a system package manager — Cargo `--features vendored`, embedded cross-compile targets, Windows app vendors, and CI pipelines that pin a specific librnp version. For conventional Linux distro consumers, the system packages described above remain the recommended path. === Asset naming Each tarball follows the convention: ---- rnp-v--.tar.gz rnp-v--.sha256 ---- For example: ---- rnp-v0.18.1-x86_64-unknown-linux-gnu-botan.tar.gz rnp-v0.18.1-aarch64-apple-darwin-openssl.tar.gz ---- === Available targets [cols="2,1,1,2", options="header"] |=== | Target triple | Backend(s) | CI runner | Notes | `x86_64-unknown-linux-gnu` | botan, openssl | `ubuntu-latest` | glibc; broadest Linux compatibility | `aarch64-unknown-linux-gnu` | botan, openssl | `ubuntu-24.04-arm` | glibc ARM64 | `x86_64-unknown-linux-musl` | botan, openssl | `ubuntu-latest` (alpine container) | static libc; Alpine / Docker | `aarch64-unknown-linux-musl`| botan, openssl | `ubuntu-24.04-arm` (alpine container) | static libc ARM64 | `aarch64-apple-darwin` | botan, openssl | `macos-14` | Apple Silicon; `MACOSX_DEPLOYMENT_TARGET=12.0` | `x86_64-pc-windows-msvc` | openssl | `windows-latest` | MSVC 2022, `/MT` static runtime, via vcpkg |=== 11 tarballs per release. Windows + botan is not currently shipped: vcpkg's botan port for the x64-windows-static triplet declares the C FFI symbols with `__declspec(dllimport)`, so the MSVC linker emits unresolved `__imp_botan_*` externals when rnp links statically. Fixing it needs an upstream vcpkg port change or a from-source Botan build on Windows; tracked as follow-up. === Tarball layout ---- include/ rnp/ public FFI headers (rnp.h, rnp_err.h, rnp_export.h, rnp_ver.h) botan-3/ (botan backend) or openssl/ (openssl backend) bzlib.h zlib.h lib/ librnp.a libsexpp.a libbotan-3.a (botan backend) or libcrypto.a + libssl.a (openssl backend) libz.a libbz2.a cmake/rnp/ CMake config (find_package(rnp)) pkgconfig/ pkg-config files MANIFEST.txt human-readable summary, dependency versions, link flags ---- NOTE: sexpp's headers are not included in the tarball. They are not needed by C API consumers (the public rnp FFI is pure C). C++ consumers that use rnp's internal C++ API additionally need sexpp's headers from a separate sexpp installation. === Consuming a prebuilt tarball Extract the tarball anywhere on disk and point your build system at the `include/` and `lib/` directories. CMake: [source,cmake] -- cmake_minimum_required(VERSION 3.18) project(example C CXX) # Unpack the tarball to /opt/rnp-prebuilt, then: set(rnp_PREBUILT_DIR /opt/rnp-prebuilt CACHE PATH "Path to rnp prebuilt bundle") list(APPEND CMAKE_PREFIX_PATH "${rnp_PREBUILT_DIR}") find_package(rnp REQUIRED) add_executable(example main.c) target_link_libraries(example PRIVATE rnp::librnp) -- Or with raw compiler flags (see `MANIFEST.txt` inside the tarball for the exact list, since it depends on backend and target): [source,console] ---- tar xzf rnp-v0.18.1-aarch64-apple-darwin-botan.tar.gz cc -I rnp-v0.18.1-aarch64-apple-darwin-botan/include \ -L rnp-v0.18.1-aarch64-apple-darwin-botan/lib \ main.c -o example \ -lrnp -lsexpp -lbotan-3 -lz -lbz2 \ -lc++ -framework Security -framework CoreFoundation ---- === Verifying integrity Each tarball ships with a `.sha256` sidecar: [source,console] ---- sha256sum -c rnp-v0.18.1-x86_64-unknown-linux-gnu-botan.sha256 ---- When the project's release signing key is configured in CI (via the `RNP_RELEASE_GPG_KEY` and `RNP_RELEASE_GPG_PASSPHRASE` repository secrets), each tarball also ships with a `.asc` detached signature. Verify with the project's published signing key fingerprint: [source,console] ---- gpg --verify rnp-v0.18.1-x86_64-unknown-linux-gnu-botan.tar.gz.asc \ rnp-v0.18.1-x86_64-unknown-linux-gnu-botan.tar.gz ---- Tarballs without a sidecar `.asc` were published before signing was configured; rely on the `.sha256` instead. === Reproducibility The tarball contents are reproducible to the extent the underlying compilers and libc allow: * `SOURCE_DATE_EPOCH=0` is exported for every dependency build, so tools that embed build timestamps (gzip header, libtool archives, Python bytecode) produce identical output across runs on the same platform. * The gzip wrapper header is normalized via `GZIP=-n`. Two known sources of non-reproducibility remain: * `.a` archive members retain their per-object mtime, which `ar` embeds in the archive index. GNU `ar -D` (deterministic mode) would fix this; wiring it through CMake across every dep is follow-up. * Compiled object files embed the absolute build path in some debug info sections. `-ffile-prefix-map=$WORK=.` would fix this; same follow-up scope. Cross-platform reproducibility (Linux build == macOS build) is not achievable since the binary contents differ by definition. === How the tarballs are built The build is driven by two scripts: * `ci/build_prebuilt.sh` — Linux glibc, Linux musl, macOS. Downloads pinned versions of each dependency (zlib, bzip2, Botan or OpenSSL), builds them as static libraries into a temporary prefix, builds librnp against that prefix, and stages the resulting headers and archives into the tarball layout shown above. * `ci/build_prebuilt.ps1` — Windows MSVC. Uses vcpkg's `x64-windows-static` triplet to install the dependency stack, then builds librnp against it via CMake. The matrix itself lives in `.github/workflows/prebuilt.yml`, a reusable workflow with three triggers: * `pull_request` — runs on PRs touching `ci/build_prebuilt.*` or the workflow itself, so changes to the static-build machinery get end-to-end validation before merge. Uploads the resulting tarballs as workflow artifacts (downloadable from the PR checks page under the `prebuilt--` artifact name) instead of attaching to a release. * `workflow_call` — invoked by `release.yml` after the source tarball is published. Attaches the resulting tarballs to the release. * `workflow_dispatch` — manual run against an existing release tag, for re-building prebuilts for an older release without re-pushing the tag. The Botan module set (Linux/macOS) is in `ci/botan3-pqc-modules`. == Embedding the sources rnp can also be built as part of your own CMake project with `add_subdirectory`: [source,cmake] -- add_subdirectory(rnp) target_link_libraries(example PRIVATE librnp) -- sexpp (a required dependency) can be provided in two ways: * bundled: clone rnp with `--recurse-submodules` or run `git submodule update --init` — the `src/libsexpp` submodule is then built together with librnp and nothing else is needed; * system-wide: configure rnp with `-DSYSTEM_LIBSEXPP=ON` to use an installed sexpp (0.8.7 or later). The sexpp CMake package (target `sexpp::sexpp`, available since sexpp 0.9.1) is preferred, with a pkg-config fallback for older installations. == Smoke test The script `ci/tests/downstream-consumer.sh` builds and installs rnp (shared and static) and compiles a minimal consumer program against each installation in all three ways described above (CMake `find_package`, pkg-config and raw compiler flags). It can be used to verify a local installation end to end.