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
| path | what happens | cost |
|---|
| prebuilt (default) | download duckdb-shared-libs-<os>-<arch>.tar.gz from the DuckDB release matching the pinned version, unpack it into a private prefix | seconds, no compiler |
| source (fallback) | git clone the pinned tag + CMake Release build, then harvest the shared object | 5-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
| sub | meaning |
|---|
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
- 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. - 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. - Unpack -
tar xzf into the version prefix, then normalise names
(libduckdb.dll -> duckdb.dll, headers into include/). - 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
- 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). - Configure - CMake out-of-tree,
Release, shell/unittests/benchmarks
off, PIC on. Ninja is preferred, Makefiles are the fallback. - Compile -
<cores> parallel jobs (capped to keep memory sane). - 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. - 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.
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
| variable | effect |
|---|
ALIEN_LIBDUCKDB_VERSION | target a different upstream tag (e.g. 1.4.1) |
ALIEN_LIBDUCKDB_ROOT | override the root that holds prebuilt/, src/, build/, <version>/ |
ALIEN_LIBDUCKDB_PREFIX | override the install prefix entirely |
ALIEN_LIBDUCKDB_PREBUILT | 0 disables the prebuilt path (always compile) |
ALIEN_LIBDUCKDB_PREBUILT_ONLY | 1 forbids the source fallback: fail instead of compiling |
ALIEN_LIBDUCKDB_SRC | use an existing DuckDB checkout instead of cloning |
ALIEN_LIBDUCKDB_JOBS | parallel compile jobs (default: CPU cores) |
ALIEN_LIBDUCKDB_CC / _CXX | force a specific compiler |
ALIEN_LIBDUCKDB_KEEP_SOURCE | keep 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.