Awesome
duckdb-extension-template-zig
A Zig & Nix toolkit template for building extensions against multiple versions of DuckDB using Zig, C or C++.
Usage
> nix develop -c $SHELL
> duckdb -unsigned
D LOAD 'zig-out/lib/quack.duckdb_extension';
D FROM duckdb_extensions();
┌──────────────────┬─────────┬───────────┬──────────────┬────────────────────────────────────────────────────────────────────────────────────┬───────────────────┐
│ extension_name │ loaded │ installed │ install_path │ description │ aliases │
│ varchar │ boolean │ boolean │ varchar │ varchar │ varchar[] │
├──────────────────┼─────────┼───────────┼──────────────┼────────────────────────────────────────────────────────────────────────────────────┼───────────────────┤
│ arrow │ false │ false │ │ A zero-copy data integration between Apache Arrow and DuckDB │ [] │
...
│ quack │ true │ │ │ │ [] │
...
│ visualizer │ true │ │ │ Creates an HTML-based visualization of the query plan │ [] │
├──────────────────┴─────────┴───────────┴──────────────┴────────────────────────────────────────────────────────────────────────────────────┴───────────────────┤
│ 24 rows 6 columns │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D FROM duckdb_extensions();
> WHERE function_name ILIKE '%quack%';
┌───────────────┬─────────────┬───────────────┬───────────────┬─────────────┬─────────────┬───┬─────────┬──────────────────┬──────────────────┬──────────┬──────────────┬─────────┐
│ database_name │ schema_name │ function_name │ function_type │ description │ return_type │ … │ varargs │ macro_definition │ has_side_effects │ internal │ function_oid │ example │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │ │ varchar │ varchar │ boolean │ boolean │ int64 │ varchar │
├───────────────┼─────────────┼───────────────┼───────────────┼─────────────┼─────────────┼───┼─────────┼──────────────────┼──────────────────┼──────────┼──────────────┼─────────┤
│ system │ main │ quack │ scalar │ │ VARCHAR │ … │ │ │ false │ true │ 1473 │ │
├───────────────┴─────────────┴───────────────┴───────────────┴─────────────┴─────────────┴───┴─────────┴──────────────────┴──────────────────┴──────────┴──────────────┴─────────┤
│ 1 rows 14 columns (12 shown) │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
D SELECT quack('howdy');
┌────────────────┐
│ quack('howdy') │
│ varchar │
├────────────────┤
│ Quack howdy 🐥 │
└────────────────┘
How it Works
DuckDB is a fast in-process analytical database written in C++ that can be extended by creating and loading a dynamically linked library using the extension API. Typically extensions are written in C++ using the officially supported extension template.
But you're one of the cool kids and want to write your extension in Zig! Fortunately the Zig build system ships with a Zig, C & C++ compiler.
1. Create a project directory initialized with the multi flake template
The Nix environment generated by the flake.nix
template
provides a self contained Linux & MacOS development toolchain:
- Clang (16.0.6)
- libcxx headers (16.0.6)
- Zig
master
(0.12.0-dev.3247+26e895e3d) - Multiple
duckdb
CLI &libduckdb
versions linked to the same versions oflibc
&libcxx
as the Zig compiler (v0.10.0, v0.9.2 & main)
> mkdir myextension && cd myextension
> nix flake init -t github:rupurt/duckdb-extension-template-zig#multi
> nix develop -c $SHELL
2. Implement 2 extension loader functions
When a DuckDB extension is loaded via LOAD 'myextension.duckdb_extension';
it requires 2 symbols
to be defined (myextension_version
& myextension_init
). The value returned from *_init
must
match the version of DuckDB loading the extension.
We create a simple header file to expose these 2 symbols in our built extension.
3. Create a C++ bridge that calls DuckDB::ExtensionUtil
The extension utils helper plugs into DuckDB internals such as:
- scalar functions
- table functions
- custom catalogs
- much more...
The example in this repository registers a simple scalar function called quack
4. Configure the Zig build system and compile the extension
The Zig build system is configured in build.zig.
- We'll need to add a shared library exposing
the DuckDB extension hooks defined in
root.zig
. - Add the include path for the C header file exposing these hooks.
- Don't forget the C++ bridge
- By convention DuckDB extensions use the file suffix
.duckdb_extension
. Zig writes the dynamic library using the formatlibmyextension.[so|dylib|dll]
. Add a custom install step to use the DuckDB naming convention for the extension filename.
Limitations
Currently this template can only build extensions using versions of duckdb
provided by the duckdb-nix
flake. The derivation built by the flake includes header files for duckdb
third_party
dependencies.
I have opened a Github issue to include those libraries
in the nixpkgs
derivation.
Development
This repository assumes you have Nix installed
> nix develop -c $SHELL
> nix develop .#v0-10-0 -c $SHELL
> nix develop .#v0-9-2 -c $SHELL
> nix develop .#main -c $SHELL
> make
Run the Zig test suite
> make test
Delete artifacts from previous builds
> make clean
Build extension binary with Zig
> make build
Run duckdb
cli allowing -unsigned
extensions
> make run
License
duckdb-extension-template-zig
is released under the MIT license