Alien::Libduckdb

Install and locate libduckdb (the DuckDB C library) for Raku NativeCall: prebuilt archive first, cmake source build as fallback

Alien::Libduckdb

Installs the DuckDB C library (libduckdb) and tells Raku where the result lives, so that a NativeCall binding can just depend on it instead of hunting for a pre-built binary.

Consumed by DB::DuckDB as its depends entry (pinned to an exact version there, because the C API is not ABI-stable across DuckDB majors).

Two install paths

pathwhat happenscost
prebuilt (default)download duckdb-shared-libs-<os>-<arch>.tar.gz from the DuckDB release matching the pinned version, unpack it into a private prefixseconds, no compiler
source (fallback)git clone the pinned tag + CMake Release build, then harvest the shared object5-20 minutes, needs cmake/ninja/g++

The prebuilt path is tried first. It is abandoned - with a printed reason - whenever the asset is missing for the platform, the download fails, or the library does not actually load here (missing MSVC runtime, glibc/musl mismatch, wrong CPU architecture). build-libduckdb then falls through to the source build, so a bare zef install never leaves you without a library.

The fallback exists because the release assets are not portable enough for a distribution that has to work everywhere:

  • Linux tarballs ship libduckdb.so with no RUNPATH, so a binding either needs LD_LIBRARY_PATH or a system-wide install;

  • Windows MinGW builds emit libduckdb.dll, MSVC builds emit duckdb.dll, and both need the import library next to them for downstream linking;

  • the headers must match the shared object exactly - mismatched duckdb.h is the classic source of silent memory corruption in NativeCall bindings.

Both paths land in the same private prefix with the same normalised layout, so consumers cannot tell them apart; source-kind() reports which one was used if you care.

Install

zef install Alien-Libduckdb

A few seconds when a prebuilt archive exists for your platform, a few minutes when it does not. The result is cached per upstream version; reinstalling the module does not rebuild unless the version changed.

To install the module but put the library in place later:

zef install Alien-Libduckdb --/build   # or ZEF_NO_BUILD=1

and then, whenever you want the library:

use Alien::Libduckdb;
ensure-installed();     # idempotent, prebuilt first, source if needed

Force a compile even when a prebuilt archive is available:

ALIEN_LIBDUCKDB_PREBUILT=0 zef install Alien-Libduckdb

Usage

use Alien::Libduckdb;

say duckdb-version();          # 2.0.0 - upstream version we build
say prefix();                  # .../Alien-Libduckdb/2.0.0
say installed();               # True once the build succeeded
say shared-lib().absolute;     # .../bin/duckdb.dll  or  .../lib/libduckdb.so

# what a NativeCall binding should do
sub duckdb_library_version(--> Str) is native(Alien::Libduckdb::lib()) {*}

lib() returns the absolute path when the library exists and falls back to the bare name (duckdb) so the OS loader can still find a system install.

Exported API

submeaning
duckdb-version()upstream DuckDB version this module installs
prefix()private install prefix (per version)
lib-dir()directory holding the shared library
include-dir()directory holding duckdb.h, duckdb_v2.h, ...
shared-lib()absolute path of the shared library, or an undefined IO::Path
lib()value to pass to is native(...)
installed()is an install matching version and platform present?
source-kind()'prebuilt', 'source', or 'unknown' for an untagged older install
prebuilt-asset() / prebuilt-url()the release archive this platform maps to
config()Hash with all of the above
cflags() / ldflags()flags for building against this prefix
ensure-installed(:force, :source-only)install on demand: prebuilt first, source if needed
install-prebuilt(:force)prebuilt archive only; fails instead of compiling
build-from-source(:force, :clean, :jobs)always compile from the pinned tag

How it works

build-libduckdb runs the two paths in order and never leaves a half-written prefix behind (a failed attempt is wiped before the next one starts).

Prebuilt path

  1. Resolve - map OS/arch to duckdb-shared-libs-<os>-<arch>.tar.gz in the v<version> GitHub release; an asset that does not exist for this platform ends the path immediately.

  2. Fetch - curl -fL (wget as fallback) into <root>/prebuilt/<version>, with the HTTP status checked so a 404 is an error, not an HTML file on disk.

  3. Unpack - tar xzf into the version prefix, then normalise names (libduckdb.dll -> duckdb.dll, headers into include/).

  4. Verify - load it and call duckdb_library_version(); only then write the .alientag marker. A library that fails to load (no VC++ runtime, glibc/musl mismatch) falls through to the source path.

Source path

  1. Fetch - git clone --depth 1 --branch v<version> from the DuckDB repo (falls back to the release tarball when git is unavailable). Submodules are initialised when the tag still has .gitmodules (1.x).

  2. Configure - CMake out-of-tree, Release, shell/unittests/benchmarks off, PIC on. Ninja is preferred, Makefiles are the fallback.

  3. Compile - <cores> parallel jobs (capped to keep memory sane).

  4. Harvest - copy the shared object into <prefix>/bin (Windows) or <prefix>/lib (POSIX), normalising libduckdb.dll -> duckdb.dll so consumers always load one canonical name; copy the headers and, on Windows, the import library.

  5. Verify - same smoke test as above, then the .alientag marker with version/platform/kind. installed() compares the marker against the current request, so a library installed for another DuckDB version or platform is never silently reused.

The source tree is deleted after a successful build (about 400 MB). Set ALIEN_LIBDUCKDB_KEEP_SOURCE=1 to keep it, and the next build becomes a near-instant incremental rebuild.

Platform notes

Linux / WSL

  • Prebuilt path needs only curl (or wget) and tar.

  • Source path additionally needs cmake, ninja (or make), g++ (GCC 11+ works, Clang too) and git.

  • The prebuilt libduckdb.so is built against a glibc baseline; on Alpine or any musl system it fails the load test and the source path takes over.

  • The library is installed to ~/.local/share/Alien-Libduckdb/<version>/lib, honouring XDG_DATA_HOME.

  • ldflags() adds -Wl,-rpath,<lib-dir> so binaries linked against the prefix do not need LD_LIBRARY_PATH.

Windows

  • Prebuilt path needs only curl (or wget) and tar; the archive is an MSVC build, so it needs the VC++ runtime and falls back when that is absent.

  • Source path needs CMake, Ninja, and a compiler. Both toolchains work:

    • MinGW-w64 (e.g. D:\llvm-mingw-...\bin\gcc.exe) - emits libduckdb.dll, which this module renames to duckdb.dll on install;

    • MSVC - emits duckdb.dll and duckdb.lib, both installed.

  • Default prefix: %LOCALAPPDATA%\Alien-Libduckdb\<version>.

  • Path is looked up case-insensitively on Windows (%*ENV<PATH> is not always populated by Rakudo there), so cmake/ninja from PATH are found even when the environment block uses mixed case.

macOS

The layout follows ~/Library/Application Support and ldflags() omits -rpath specifics beyond the standard flag; untested but no code path is Windows- or Linux-only.

Environment variables

variableeffect
ALIEN_LIBDUCKDB_VERSIONtarget a different upstream tag (e.g. 1.4.1)
ALIEN_LIBDUCKDB_ROOToverride the root that holds prebuilt/, src/, build/, <version>/
ALIEN_LIBDUCKDB_PREFIXoverride the install prefix entirely
ALIEN_LIBDUCKDB_PREBUILT0 disables the prebuilt path (always compile)
ALIEN_LIBDUCKDB_PREBUILT_ONLY1 forbids the source fallback: fail instead of compiling
ALIEN_LIBDUCKDB_SRCuse an existing DuckDB checkout instead of cloning
ALIEN_LIBDUCKDB_JOBSparallel compile jobs (default: CPU cores)
ALIEN_LIBDUCKDB_CC / _CXXforce a specific compiler
ALIEN_LIBDUCKDB_KEEP_SOURCEkeep the source tree after building

Layout

<root>/                     %LOCALAPPDATA%\Alien-Libduckdb  or  ~/.local/share/Alien-Libduckdb
ā”œā”€ā”€ prebuilt/duckdb-<ver>/  downloaded archive + staging area
ā”œā”€ā”€ src/duckdb-<version>/   source checkout (removed after success)
ā”œā”€ā”€ build/duckdb-<version>/ CMake build tree
└── <version>/              install prefix
    ā”œā”€ā”€ bin/                duckdb.dll          (Windows)
    ā”œā”€ā”€ lib/                libduckdb.so        (POSIX) + import libs
    ā”œā”€ā”€ include/            duckdb.h, duckdb_v2.h, ...
    ā”œā”€ā”€ logs/               download/clone/configure/build logs of the last attempt
    └── .alientag           marker: version, platform, kind, build id

License

Artistic-2.0. DuckDB itself is MIT-licensed.

Alien::Libduckdb v1.1.0

Install and locate libduckdb (the DuckDB C library) for Raku NativeCall: prebuilt archive first, cmake source build as fallback

Authors

  • skyter10086

License

Artistic-2.0

Dependencies

Test Dependencies

Provides

  • Alien::Libduckdb
  • Alien::Libduckdb::Builder
  • Alien::Libduckdb::Spec

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.