Skip to content

Commit ab84597

Browse files
committed
fix: source bundled libs from Ubuntu 22.04 to keep manylinux_2_35 baseline
The previous commit pulled libxml2 and libicu74 from Ubuntu 24.04, but those .so files require GLIBC 2.38, which is newer than the manylinux_2_35 baseline (Ubuntu 22.04 / Debian 12) the wheel ships under. CI's Linux x86_64-gnu wheel test failed on the ubuntu-22.04 runner with: postgres: libm.so.6: version `GLIBC_2.38' not found (required by libxml2.so.2) Root-cause realization: the bundled postgres binary itself does NOT have libicu in DT_NEEDED. It only links against libxml2.so.2; libxml2 is what pulls libicu in transitively. So the ICU major version we ship just needs to match whatever ICU the bundled libxml2 was built against - it does not have to match the original SONAME `.so.74` from Ubuntu 24.04. Switch to Ubuntu 22.04 sources: - libxml2 2.9.13+dfsg-1ubuntu0.11 (.so.2 SONAME, transitively wants .so.70) - libicu70 70.1-2ubuntu1 (icudata + icui18n + icuuc) These libs require at most GLIBC 2.34, comfortably below our 2.35 wheel baseline, and are still ABI-compatible everywhere we care about (22.04, 24.04, 25.10, 26.04). They sit alongside whatever libicu the host has installed - on 24.04 the system libicu74 is unused; on 25.10 the system libicu76 is unused; in both cases the bundled postgres resolves through our libxml2 -> our libicu70. Verified locally: - Vanilla ubuntu:22.04 (glibc 2.35, no libxml2/libicu installed): pg0 start + psql + stop works. - ubuntu:24.04 + ubuntu:25.10: docker-tests/test_ubuntu_amd64.sh passes. - python:3.11-slim debian: docker-tests/test_debian_amd64.sh passes. - missing-libs detection still works. Comments in build.rs and main.rs updated to reflect the new sourcing rationale; README's Ubuntu 25.10 row updated from "ICU 74" to "libicu70".
1 parent 6924725 commit ab84597

4 files changed

Lines changed: 58 additions & 36 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ The table below reflects what we actually exercise via the docker tests in `dock
498498
| Debian 13 (trixie) | x86_64, aarch64 | ✅ Expected to work | Same glibc / libxml2 ABI as bookworm |
499499
| Ubuntu 22.04 (Jammy) | x86_64, aarch64 | ✅ Expected to work | glibc 2.35 baseline; matches release CI build host |
500500
| Ubuntu 24.04 (Noble) | x86_64 | ✅ Tested | `docker-tests/test_ubuntu_amd64.sh` |
501-
| Ubuntu 25.10 (Plucky) | x86_64 | ✅ Tested | `docker-tests/test_ubuntu_amd64.sh` - works thanks to bundled libxml2.so.2 / ICU 74 |
501+
| Ubuntu 25.10 (Plucky) | x86_64 | ✅ Tested | `docker-tests/test_ubuntu_amd64.sh` - works thanks to bundled libxml2.so.2 + libicu70 |
502502
| Ubuntu 26.04 (next LTS) | x86_64, aarch64 | ✅ Expected to work | Inherits libxml2 2.14 / ICU 76 from 25.10 |
503503
| Alpine 3.20 | x86_64, aarch64 | ✅ Tested | `docker-tests/test_alpine_*.sh` (python:3.12-alpine3.20). Uses musl + system ICU 74 |
504504
| Alpine 3.21 | x86_64, aarch64 | ✅ Expected to work | Same ICU 74 line as 3.20 (untested but ABI-compatible) |

‎build.rs‎

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -179,18 +179,24 @@ fn download_file(url: &str, dest: &PathBuf) -> io::Result<()> {
179179
Ok(())
180180
}
181181

182-
/// Bundle libxml2.so.2 and the ICU 74 .so files alongside PostgreSQL.
182+
/// Bundle libxml2.so.2 and its transitive ICU dependency alongside PostgreSQL.
183183
///
184-
/// The theseus-rs PostgreSQL builds dynamic-link against libxml2.so.2 and
185-
/// libicu*.so.74. Both have been replaced upstream:
184+
/// The theseus-rs PostgreSQL build links against libxml2.so.2 (DT_NEEDED);
185+
/// libxml2 then pulls ICU in transitively. Both have been replaced upstream:
186186
/// - libxml2 2.14 (Ubuntu 25.10+) bumped the SONAME to .so.16; there is no
187187
/// .so.2 compat package.
188-
/// - ICU has moved to 76 in 25.10+ and 80+ on rolling distros.
188+
/// - ICU has moved to .so.74 in 24.04, .so.76 in 25.10+, and continues to
189+
/// drift forward.
189190
///
190-
/// We download the matching .so files from Ubuntu 24.04's archive at build
191-
/// time, repack them into a single tar.gz, and embed that into the pg0 binary.
192-
/// At runtime, main.rs extracts them next to the bundled postgres binary and
193-
/// adds that directory to LD_LIBRARY_PATH.
191+
/// We download libxml2 + the matching libicu .deb files from Ubuntu 22.04's
192+
/// archive at build time, repack them into a single tar.gz, and embed that
193+
/// into the pg0 binary. Ubuntu 22.04 is chosen because its libs require at
194+
/// most GLIBC 2.34, keeping us inside the manylinux_2_35 wheel baseline -
195+
/// Ubuntu 24.04's libs would require GLIBC 2.38 and break users on 22.04 /
196+
/// Debian 12.
197+
///
198+
/// At runtime, main.rs extracts the libs next to the bundled postgres binary
199+
/// and prepends that directory to LD_LIBRARY_PATH.
194200
///
195201
/// Only Linux GNU targets get a non-empty bundle. Other targets get an empty
196202
/// bundle file so the include_bytes! macro in main.rs has something to point
@@ -223,21 +229,25 @@ fn bundle_runtime_libs(versions: &HashMap<String, String>, out_dir: &PathBuf) {
223229
.get(&format!("LIBXML2_DEB_SHA256_{}", arch))
224230
.expect("missing LIBXML2_DEB_SHA256")
225231
.clone(),
226-
wanted: vec!["libxml2.so.2.9.14".to_string()],
232+
// Ubuntu 22.04 ships libxml2.so.2 -> libxml2.so.2.9.13.
233+
wanted: vec!["libxml2.so.2.9.13".to_string()],
227234
},
228235
DebSpec {
229236
url: versions
230-
.get(&format!("LIBICU74_DEB_URL_{}", arch))
231-
.expect("missing LIBICU74_DEB_URL")
237+
.get(&format!("LIBICU_DEB_URL_{}", arch))
238+
.expect("missing LIBICU_DEB_URL")
232239
.clone(),
233240
sha256: versions
234-
.get(&format!("LIBICU74_DEB_SHA256_{}", arch))
235-
.expect("missing LIBICU74_DEB_SHA256")
241+
.get(&format!("LIBICU_DEB_SHA256_{}", arch))
242+
.expect("missing LIBICU_DEB_SHA256")
236243
.clone(),
244+
// Ubuntu 22.04 ships libicu70.1 (matching the .so.70 SONAME).
245+
// libxml2.so.2 only directly needs libicuuc, but libicuuc itself
246+
// pulls in libicudata; libicui18n is included for completeness.
237247
wanted: vec![
238-
"libicudata.so.74.2".to_string(),
239-
"libicui18n.so.74.2".to_string(),
240-
"libicuuc.so.74.2".to_string(),
248+
"libicudata.so.70.1".to_string(),
249+
"libicui18n.so.70.1".to_string(),
250+
"libicuuc.so.70.1".to_string(),
241251
],
242252
},
243253
];

‎src/main.rs‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ static POSTGRESQL_BUNDLE: &[u8] = include_bytes!(env!("POSTGRESQL_BUNDLE_PATH"))
1717
/// The embedded pgvector bundle
1818
static PGVECTOR_BUNDLE: &[u8] = include_bytes!(env!("PGVECTOR_BUNDLE_PATH"));
1919

20-
/// Extra runtime libraries (libxml2.so.2, libicu*.so.74) that the bundled
21-
/// PostgreSQL binary dynamic-links against. Empty on platforms where the host
22-
/// reliably provides them (macOS, Windows, Alpine/musl). See build.rs.
20+
/// Extra runtime libraries (libxml2.so.2 + the libicu major it transitively
21+
/// loads) that the bundled PostgreSQL binary dynamic-links against. Empty on
22+
/// platforms where the host reliably provides them (macOS, Windows,
23+
/// Alpine/musl). See build.rs.
2324
static RUNTIME_LIBS_BUNDLE: &[u8] = include_bytes!(env!("RUNTIME_LIBS_BUNDLE_PATH"));
2425

2526
#[derive(Error, Debug)]
@@ -585,8 +586,8 @@ fn ensure_runtime_libs(version_dir: &Path) -> Result<(), CliError> {
585586
}
586587

587588
/// Given a fully-versioned shared-library filename like
588-
/// `libxml2.so.2.9.14` or `libicudata.so.74.2`, return the SONAME the dynamic
589-
/// linker actually resolves: `libxml2.so.2`, `libicudata.so.74`. Returns None
589+
/// `libxml2.so.2.9.13` or `libicudata.so.70.1`, return the SONAME the dynamic
590+
/// linker actually resolves: `libxml2.so.2`, `libicudata.so.70`. Returns None
590591
/// for filenames we don't recognise (so we don't accidentally create bogus
591592
/// symlinks).
592593
fn soname_for(filename: &str) -> Option<String> {

‎versions.env‎

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,28 @@ PGVECTOR_COMPILED_TAG=v0.18.237
44
PGVECTOR_COMPILED_REPO=nicoloboschi/pgvector_compiled
55

66
# Runtime libraries bundled with the Linux GNU binaries.
7-
# The theseus-rs PostgreSQL builds are linked against libxml2.so.2 and ICU 74,
8-
# both of which are missing or replaced on Ubuntu 25.10+ (libxml2 2.14 bumped
9-
# the SONAME to .so.16; libicu jumped to 76). We bundle the matching .so files
10-
# from the Ubuntu 24.04 archive so pg0 stays self-contained on newer distros.
11-
LIBXML2_DEB_VERSION=2.9.14+dfsg-1.3ubuntu3.7
12-
LIBXML2_DEB_URL_AMD64=http://archive.ubuntu.com/ubuntu/pool/main/libx/libxml2/libxml2_2.9.14+dfsg-1.3ubuntu3.7_amd64.deb
13-
LIBXML2_DEB_SHA256_AMD64=74ab8be7aa487e5cc7d9d228212f538ff96658afcb080335c02fe0f3e384ff7c
14-
LIBXML2_DEB_URL_ARM64=http://ports.ubuntu.com/pool/main/libx/libxml2/libxml2_2.9.14+dfsg-1.3ubuntu3.7_arm64.deb
15-
LIBXML2_DEB_SHA256_ARM64=2bc507d1bee2676f714a6feee61866cdf38790aac8da83d640ccea418394675a
16-
LIBICU74_DEB_VERSION=74.2-1ubuntu3.1
17-
LIBICU74_DEB_URL_AMD64=http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu74_74.2-1ubuntu3.1_amd64.deb
18-
LIBICU74_DEB_SHA256_AMD64=c9a70989678660eed9a1e904c74fa043da8bec8e2036856fc16e31ced79b04f8
19-
LIBICU74_DEB_URL_ARM64=http://ports.ubuntu.com/pool/main/i/icu/libicu74_74.2-1ubuntu3.1_arm64.deb
20-
LIBICU74_DEB_SHA256_ARM64=48f93acf50dcf237a8d58ce366730a28438ce52d3f06d7a2a88b51261dd791f7
7+
#
8+
# The theseus-rs PostgreSQL build does NOT directly link against ICU. It
9+
# links against libxml2.so.2 (DT_NEEDED), and libxml2 in turn pulls in ICU
10+
# transitively. So we bundle a libxml2.so.2 + the matching libicu it was
11+
# built against, all sourced from the same Ubuntu archive.
12+
#
13+
# We deliberately use Ubuntu 22.04 (Jammy) packages because:
14+
# 1. Their glibc symbol requirements top out at GLIBC 2.34, comfortably
15+
# below our manylinux_2_35 wheel baseline. Using Ubuntu 24.04 packages
16+
# would require GLIBC 2.38, breaking users on Ubuntu 22.04 / Debian 12.
17+
# 2. Ubuntu 22.04's libxml2.so.2 transitively wants libicu*.so.70, so we
18+
# bundle that ICU major rather than the .so.74 ICU 24.04 ships.
19+
# This works on every supported distro: 22.04 has the same SONAMEs natively;
20+
# 24.04+ keeps libxml2.so.2 around but in a newer ICU lineage; 25.10+ has
21+
# neither, but the bundled libxml2.so.2 + libicu70 fills both gaps.
22+
LIBXML2_DEB_VERSION=2.9.13+dfsg-1ubuntu0.11
23+
LIBXML2_DEB_URL_AMD64=http://archive.ubuntu.com/ubuntu/pool/main/libx/libxml2/libxml2_2.9.13+dfsg-1ubuntu0.11_amd64.deb
24+
LIBXML2_DEB_SHA256_AMD64=74eb1df2112ec3cd5a961b737d68c9a96c6de2f115a124ede81af5292b5d23e7
25+
LIBXML2_DEB_URL_ARM64=http://ports.ubuntu.com/pool/main/libx/libxml2/libxml2_2.9.13+dfsg-1ubuntu0.11_arm64.deb
26+
LIBXML2_DEB_SHA256_ARM64=313e94b051c3e3974dea06c4576dc2b42f04cf7aba6c9dbb2f14135c218c7be7
27+
LIBICU_DEB_VERSION=70.1-2ubuntu1
28+
LIBICU_DEB_URL_AMD64=http://archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu70_70.1-2ubuntu1_amd64.deb
29+
LIBICU_DEB_SHA256_AMD64=223c1e6cebf2a6748637303227d8b84337c14a2d30eacbc46a68d02557dcff3e
30+
LIBICU_DEB_URL_ARM64=http://ports.ubuntu.com/pool/main/i/icu/libicu70_70.1-2ubuntu1_arm64.deb
31+
LIBICU_DEB_SHA256_ARM64=a06f86489e364f555a0655f476e6b2693760aff9d8dec0011daf9b17957da3c5

0 commit comments

Comments
 (0)