From 5a0db95814b208d26f74797130ebf2a86aba8624 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 1 Jun 2026 15:52:38 +0000 Subject: [PATCH 1/5] ci: enable linux_amd64_musl extension build Remove linux_amd64_musl from exclude_archs now that vortex builds for x86_64-unknown-linux-musl in its own CI. Signed-off-by: Joe Isaacs --- .github/workflows/MainDistributionPipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MainDistributionPipeline.yml b/.github/workflows/MainDistributionPipeline.yml index 158ad6a..c94d9db 100644 --- a/.github/workflows/MainDistributionPipeline.yml +++ b/.github/workflows/MainDistributionPipeline.yml @@ -19,5 +19,5 @@ jobs: ci_tools_version: v1.5.3 duckdb_version: v1.5.3 extension_name: vortex - exclude_archs: "wasm_mvp;wasm_eh;wasm_threads;windows_amd64_rtools;windows_amd64_mingw;windows_amd64;linux_amd64_musl" + exclude_archs: "wasm_mvp;wasm_eh;wasm_threads;windows_amd64_rtools;windows_amd64_mingw;windows_amd64" extra_toolchains: "rust" From a6b8cb3e6446b123bf5912396cb9e6c9a6bb42f3 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 1 Jun 2026 20:06:32 +0100 Subject: [PATCH 2/5] ci: actually opt in linux_amd64_musl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit linux_amd64_musl is marked opt_in in extension-ci-tools' distribution_matrix.json, so dropping it from exclude_archs alone does not build it — the matrix generator skips opt_in archs unless they are also listed in opt_in_archs. Add the opt_in_archs input so the musl extension build is actually generated and runs in CI. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Isaacs --- .github/workflows/MainDistributionPipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/MainDistributionPipeline.yml b/.github/workflows/MainDistributionPipeline.yml index c94d9db..dc4d065 100644 --- a/.github/workflows/MainDistributionPipeline.yml +++ b/.github/workflows/MainDistributionPipeline.yml @@ -20,4 +20,7 @@ jobs: duckdb_version: v1.5.3 extension_name: vortex exclude_archs: "wasm_mvp;wasm_eh;wasm_threads;windows_amd64_rtools;windows_amd64_mingw;windows_amd64" + # linux_amd64_musl is opt_in in extension-ci-tools' distribution_matrix.json, + # so removing it from exclude_archs is not enough — it must also be opted in here. + opt_in_archs: "linux_amd64_musl" extra_toolchains: "rust" From 619ff912f31290279ddb9f6009436479bbb72e67 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Mon, 1 Jun 2026 19:40:02 +0000 Subject: [PATCH 3/5] ci: build vortex crate PIC with dynamic CRT on musl The linux_amd64_musl extension build links the vortex-duckdb staticlib into the loadable extension shared object. Rust's x86_64-unknown-linux-musl target defaults to a static CRT and non-PIC codegen, which fails at link time with relocation R_X86_64_32 against a shared object. Pass -Ctarget-feature=-crt-static and -Crelocation-model=pic for the crate, scoped to musl via the loader path so glibc/macOS builds are unaffected. Signed-off-by: Joe Isaacs --- CMakeLists.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2206b0..013c543 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,21 @@ corrosion_set_env_vars( "DUCKDB_VERSION=${DUCKDB_VERSION}" ) +# On musl (Alpine) the vortex crate is built as a staticlib and folded into the +# loadable extension, which is a shared object. Rust's x86_64-unknown-linux-musl +# target defaults to a static CRT and non-PIC codegen, so the archive fails to +# link into a shared object (relocation R_X86_64_32 ... can not be used when +# making a shared object). Build it position-independent against a dynamic CRT. +# Scoped to musl via the loader path so glibc/macOS builds are unaffected. +if(EXISTS "/lib/ld-musl-x86_64.so.1") + message(STATUS "musl libc detected: building vortex crate as PIC with dynamic CRT") + corrosion_add_target_rustflags( + ${VORTEX_RUST_TARGET_NAME} + "-Ctarget-feature=-crt-static" + "-Crelocation-model=pic" + ) +endif() + include_directories(src/include vortex/vortex-duckdb/include) set(EXTENSION_NAME ${TARGET_NAME}_extension) From e750b937ea1aadd319303e609ea112d5b471e1d8 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Tue, 2 Jun 2026 10:24:21 +0100 Subject: [PATCH 4/5] ci: let musl host build scripts dlopen libclang The linux_amd64_musl build fails in custom-labels' build script: Unable to find libclang: "... could not be opened: Dynamic loading not supported" custom-labels (a mandatory dep of vortex-duckdb/vortex-io) runs bindgen, which dlopen()s libclang. In the Alpine/musl image the host is musl and Rust defaults crt-static=on, so the build-script executable is static and cannot dlopen. The prior -crt-static RUSTFLAGS (added via corrosion) only affects the target artifacts under --target, not host build scripts. Add a .cargo/config.toml disabling crt-static for the musl triple. Under --target, host build scripts read [target.].rustflags from config (via target-applies-to-host), so this makes them dynamically linked and able to dlopen libclang. Only consulted for musl builds; glibc/macOS/ Windows are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Isaacs --- .cargo/config.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..fcbc5ce --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,23 @@ +# Host build-script linkage for the linux_amd64_musl extension build. +# +# In the Alpine/musl CI image the *host* is x86_64-unknown-linux-musl, so build +# scripts are compiled for that triple. Rust defaults `crt-static = on` for musl, +# producing a statically linked build-script executable. The `custom-labels` +# crate (a mandatory dependency of vortex-duckdb / vortex-io) runs `bindgen` in +# its build script, and bindgen `dlopen()`s libclang at runtime — which is +# impossible from a fully static binary: +# +# Unable to find libclang: "... libclang.so ... could not be opened: +# Dynamic loading not supported" +# +# Disabling crt-static for the musl triple makes host build scripts dynamically +# linked, so they can dlopen libclang and the musl build proceeds. +# +# Note: corrosion already passes the equivalent flag (plus -Crelocation-model=pic) +# to the extension *target* via RUSTFLAGS (see CMakeLists.txt). Under `--target`, +# env RUSTFLAGS only affects the final target artifacts, not host build scripts; +# this `[target.]` table — applied to host build scripts via +# target-applies-to-host (default true) — is what covers them. Only consulted +# when building for the musl triple, so glibc/macOS/Windows builds are unaffected. +[target.x86_64-unknown-linux-musl] +rustflags = ["-C", "target-feature=-crt-static"] From 32680ae893d28403306a0c743d93c812a2fdbb2f Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Tue, 2 Jun 2026 10:55:46 +0100 Subject: [PATCH 5/5] ci: move musl rustflags to cargo config so host build scripts get them The previous attempt set -crt-static/-relocation-model=pic via corrosion's RUSTFLAGS env. That has two problems on the musl build: - under --target, env RUSTFLAGS only applies to the target artifacts, so the host build scripts (compiled for the musl host triple) stayed statically linked. custom-labels' build script runs bindgen, which dlopen()s libclang, and a static binary cannot dlopen -> "Dynamic loading not supported". - when RUSTFLAGS env is set, cargo ignores [target.*].rustflags from config. Move the flags into .cargo/config.toml [target.x86_64-unknown-linux-musl] and drop the corrosion RUSTFLAGS. With no env RUSTFLAGS, the config table applies to both the target crate (fixing the relocation/PIC error) and host build scripts (target-applies-to-host), making the latter dynamically linked so bindgen can dlopen libclang. Scoped to the musl triple; other platforms unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Joe Isaacs --- .cargo/config.toml | 42 +++++++++++++++++++++++------------------- CMakeLists.txt | 20 ++++++-------------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index fcbc5ce..afa0225 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,23 +1,27 @@ -# Host build-script linkage for the linux_amd64_musl extension build. +# Build flags for the linux_amd64_musl extension build. These MUST live in cargo +# config (not corrosion's RUSTFLAGS env), for two reasons: # -# In the Alpine/musl CI image the *host* is x86_64-unknown-linux-musl, so build -# scripts are compiled for that triple. Rust defaults `crt-static = on` for musl, -# producing a statically linked build-script executable. The `custom-labels` -# crate (a mandatory dependency of vortex-duckdb / vortex-io) runs `bindgen` in -# its build script, and bindgen `dlopen()`s libclang at runtime — which is -# impossible from a fully static binary: +# 1. Host build scripts. In the Alpine/musl image the host is +# x86_64-unknown-linux-musl, so build scripts compile for that triple. Rust +# defaults `crt-static = on` for musl, producing a *static* build-script +# binary. The `custom-labels` crate (a mandatory dep of vortex-duckdb / +# vortex-io) runs bindgen in its build script, and bindgen dlopen()s +# libclang — impossible from a static binary: +# Unable to find libclang: "... libclang.so ... could not be opened: +# Dynamic loading not supported" +# Under `--target`, env RUSTFLAGS only affects the target artifacts, not host +# build scripts. A `[target.]` config table, by contrast, also +# applies to host build scripts of that triple (target-applies-to-host, +# default true) — so disabling crt-static here makes them dynamically linked +# and able to dlopen libclang. # -# Unable to find libclang: "... libclang.so ... could not be opened: -# Dynamic loading not supported" +# 2. Relocation. The vortex crate is built as a staticlib folded into the +# loadable extension shared object; musl's default non-PIC codegen fails with +# "relocation R_X86_64_32 ... cannot be used when making a shared object". +# -Crelocation-model=pic fixes that for the target crate. # -# Disabling crt-static for the musl triple makes host build scripts dynamically -# linked, so they can dlopen libclang and the musl build proceeds. -# -# Note: corrosion already passes the equivalent flag (plus -Crelocation-model=pic) -# to the extension *target* via RUSTFLAGS (see CMakeLists.txt). Under `--target`, -# env RUSTFLAGS only affects the final target artifacts, not host build scripts; -# this `[target.]` table — applied to host build scripts via -# target-applies-to-host (default true) — is what covers them. Only consulted -# when building for the musl triple, so glibc/macOS/Windows builds are unaffected. +# Setting RUSTFLAGS env (as corrosion does) would make cargo IGNORE this table, +# so the flags are kept here instead. Only consulted when building for the musl +# triple, so glibc/macOS/Windows builds are unaffected. [target.x86_64-unknown-linux-musl] -rustflags = ["-C", "target-feature=-crt-static"] +rustflags = ["-C", "target-feature=-crt-static", "-C", "relocation-model=pic"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 013c543..4558401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,20 +80,12 @@ corrosion_set_env_vars( "DUCKDB_VERSION=${DUCKDB_VERSION}" ) -# On musl (Alpine) the vortex crate is built as a staticlib and folded into the -# loadable extension, which is a shared object. Rust's x86_64-unknown-linux-musl -# target defaults to a static CRT and non-PIC codegen, so the archive fails to -# link into a shared object (relocation R_X86_64_32 ... can not be used when -# making a shared object). Build it position-independent against a dynamic CRT. -# Scoped to musl via the loader path so glibc/macOS builds are unaffected. -if(EXISTS "/lib/ld-musl-x86_64.so.1") - message(STATUS "musl libc detected: building vortex crate as PIC with dynamic CRT") - corrosion_add_target_rustflags( - ${VORTEX_RUST_TARGET_NAME} - "-Ctarget-feature=-crt-static" - "-Crelocation-model=pic" - ) -endif() +# NOTE: musl (Alpine) build flags live in .cargo/config.toml under +# [target.x86_64-unknown-linux-musl], NOT here. They must be applied via cargo +# config rather than corrosion's RUSTFLAGS env, because (a) under --target, env +# RUSTFLAGS only reaches the target artifacts, not the *host* build scripts, and +# the custom-labels build script needs a dynamic CRT to dlopen libclang; and +# (b) setting RUSTFLAGS env makes cargo ignore the [target] config entirely. include_directories(src/include vortex/vortex-duckdb/include)