From d4a472c72943396b347436aee5ec73f61c7455e3 Mon Sep 17 00:00:00 2001
From: David Li
Date: Wed, 12 Aug 2026 14:43:53 +0900
Subject: [PATCH 1/4] feat: check for unexpected dependencies on Linux
Assisted-by: GPT-5.6 Sol
---
adbc_drivers_dev/make_checks.py | 79 +++++++++++++++++++++++++++++++++
adbc_drivers_dev/make_config.py | 5 +++
tests/test_make_checks.py | 53 ++++++++++++++++++++++
3 files changed, 137 insertions(+)
diff --git a/adbc_drivers_dev/make_checks.py b/adbc_drivers_dev/make_checks.py
index 96d0b14..7c3495b 100644
--- a/adbc_drivers_dev/make_checks.py
+++ b/adbc_drivers_dev/make_checks.py
@@ -22,6 +22,18 @@
from .make_config import MakeConfig, MakeEnv
+_LINUX_RUNTIME_DEPENDENCIES = {
+ "linux-vdso.so.1",
+ "libgcc_s.so.1",
+ "libm.so.6",
+ "libpthread.so.0",
+ "libc.so.6",
+}
+_LINUX_LOADERS = {
+ "amd64": "/lib64/ld-linux-x86-64.so.2",
+ "arm64": "/lib/ld-linux-aarch64.so.1",
+}
+
def _read_linux_symbols(binary: Path) -> list[str]:
return (
@@ -33,6 +45,10 @@ def _read_linux_symbols(binary: Path) -> list[str]:
)
+def _read_linux_dependencies(binary: Path) -> list[str]:
+ return subprocess.check_output(["ldd", str(binary)], text=True).splitlines()
+
+
def _read_macos_symbols(binary: Path) -> list[str]:
return (
subprocess.check_output(["nm", "-gU", str(binary)], text=True)
@@ -83,6 +99,61 @@ def _read_linux_symbols_in_docker(
)
+def _read_linux_dependencies_in_docker(
+ make_env: MakeEnv, make_config: MakeConfig, binary: Path
+) -> list[str]:
+ rel_binary = binary.resolve().relative_to(make_env.repo_root.resolve())
+ env = {
+ **os.environ,
+ "SOURCE_ROOT": str(make_env.repo_root),
+ "DOCKER_DEFAULT_PLATFORM": (
+ f"{make_env.target_platform}/{make_env.target_architecture}"
+ ),
+ "MANYLINUX": make_config.manylinux,
+ }
+ return subprocess.check_output(
+ [
+ "docker",
+ "compose",
+ "run",
+ "--rm",
+ "manylinux",
+ "ldd",
+ f"/source/{rel_binary.as_posix()}",
+ ],
+ cwd=Path(__file__).parent,
+ env=env,
+ text=True,
+ ).splitlines()
+
+
+def _extract_linux_dependencies(output: list[str]) -> set[str]:
+ dependencies = set()
+ for raw_line in output:
+ line = raw_line.strip()
+ if not line:
+ continue
+ parts = line.split()
+ dependencies.add(parts[0])
+ return dependencies
+
+
+def check_linux_runtime_dependencies(
+ output: list[str], binary: Path, architecture: str, additional: list[str]
+) -> None:
+ dependencies = _extract_linux_dependencies(output)
+ allowed = _LINUX_RUNTIME_DEPENDENCIES | set(additional)
+ try:
+ allowed.add(_LINUX_LOADERS[architecture])
+ except KeyError as err:
+ raise ValueError(f"Unsupported Linux architecture: {architecture}") from err
+
+ unexpected = {name for name in dependencies if name not in allowed}
+ if unexpected:
+ details = ", ".join(sorted(unexpected))
+ raise RuntimeError(f"{binary} has unexpected runtime dependencies: {details}")
+
+
def _extract_exported_linux_symbols(symbols: list[str]) -> list[str]:
exported_symbols = []
for symbol in symbols:
@@ -178,8 +249,10 @@ def check_linux_libc_requirement(symbols: list[str], manylinux: str) -> None:
def _check_linux(make_env: MakeEnv, make_config: MakeConfig, binary: Path) -> None:
if make_env.host_platform == "linux":
symbols = _read_linux_symbols(binary)
+ dependencies = _read_linux_dependencies(binary)
elif make_env.use_docker:
symbols = _read_linux_symbols_in_docker(make_env, make_config, binary)
+ dependencies = _read_linux_dependencies_in_docker(make_env, make_config, binary)
else:
raise RuntimeError(
"Cannot run Linux compatibility checks on non-Linux host without Docker"
@@ -188,6 +261,12 @@ def _check_linux(make_env: MakeEnv, make_config: MakeConfig, binary: Path) -> No
check_required_symbols(exported_symbols, binary, make_config.driver)
check_disallowed_symbols(exported_symbols, binary, make_config.driver)
check_linux_libc_requirement(symbols, make_config.manylinux)
+ check_linux_runtime_dependencies(
+ dependencies,
+ binary,
+ make_env.target_architecture,
+ make_config.additional_runtime_dependencies.get("linux", []),
+ )
def _check_macos_deployment_target(binary: Path) -> None:
diff --git a/adbc_drivers_dev/make_config.py b/adbc_drivers_dev/make_config.py
index 122a64a..56102dc 100644
--- a/adbc_drivers_dev/make_config.py
+++ b/adbc_drivers_dev/make_config.py
@@ -350,6 +350,11 @@ class MakeConfig(BaseModel):
alias="additional-volumes",
description="Additional Docker volume mounts, in HOST:CONTAINER format",
)
+ additional_runtime_dependencies: dict[typing.Literal["linux"], list[str]] = Field(
+ default_factory=dict,
+ alias="additional-runtime-dependencies",
+ description="Additional runtime dependencies allowed by platform",
+ )
def build_plan(self, config: MakeEnv) -> MakePlan:
env_vars = default_build_env(config)
diff --git a/tests/test_make_checks.py b/tests/test_make_checks.py
index e79803d..86d369f 100644
--- a/tests/test_make_checks.py
+++ b/tests/test_make_checks.py
@@ -83,6 +83,59 @@ def test_extract_exported_linux_symbols() -> None:
assert exported_symbols == ["AdbcDriverInit", "AdbcDriverDriverInit"]
+def test_extract_linux_dependencies() -> None:
+ dependencies = make_checks._extract_linux_dependencies(
+ [
+ "\tlinux-vdso.so.1 (0x00007fff)",
+ "\tlibm.so.6 => /lib64/libm.so.6 (0x00007fff)",
+ "\tlibmissing.so.1 => not found",
+ "\t/lib64/ld-linux-x86-64.so.2 (0x00007fff)",
+ ]
+ )
+ assert dependencies == {
+ "linux-vdso.so.1",
+ "libm.so.6",
+ "libmissing.so.1",
+ "/lib64/ld-linux-x86-64.so.2",
+ }
+
+
+def test_check_linux_runtime_dependencies() -> None:
+ output = [
+ "linux-vdso.so.1 (0x00007fff)",
+ "libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fff)",
+ "libm.so.6 => /lib64/libm.so.6 (0x00007fff)",
+ "libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fff)",
+ "libc.so.6 => /lib64/libc.so.6 (0x00007fff)",
+ "/lib64/ld-linux-x86-64.so.2 (0x00007fff)",
+ ]
+ make_checks.check_linux_runtime_dependencies(output, Path("driver.so"), "amd64", [])
+
+ output.append("libfoobar.so => /opt/libfoobar.so (0x00007fff)")
+ make_checks.check_linux_runtime_dependencies(
+ output, Path("driver.so"), "amd64", ["libfoobar.so"]
+ )
+ make_checks.check_linux_runtime_dependencies(
+ ["/lib/ld-linux-aarch64.so.1 (0x00007fff)"],
+ Path("driver.so"),
+ "arm64",
+ [],
+ )
+
+ with pytest.raises(RuntimeError, match="libfoobar.so"):
+ make_checks.check_linux_runtime_dependencies(
+ output, Path("driver.so"), "amd64", []
+ )
+
+ with pytest.raises(RuntimeError, match="libmissing.so.1"):
+ make_checks.check_linux_runtime_dependencies(
+ ["libmissing.so.1 => not found"],
+ Path("driver.so"),
+ "amd64",
+ [],
+ )
+
+
def test_extract_exported_macos_symbols() -> None:
symbols = [
"000000 T _AdbcDriverMultiwordnameInit",
From 4d5ee90b9821269eb35a81bbb175493ae8e28391 Mon Sep 17 00:00:00 2001
From: David Li
Date: Thu, 13 Aug 2026 09:45:22 +0900
Subject: [PATCH 2/4] add more libraries
---
adbc_drivers_dev/make_checks.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/adbc_drivers_dev/make_checks.py b/adbc_drivers_dev/make_checks.py
index 7c3495b..64a4703 100644
--- a/adbc_drivers_dev/make_checks.py
+++ b/adbc_drivers_dev/make_checks.py
@@ -23,11 +23,12 @@
from .make_config import MakeConfig, MakeEnv
_LINUX_RUNTIME_DEPENDENCIES = {
- "linux-vdso.so.1",
+ "libc.so.6",
"libgcc_s.so.1",
"libm.so.6",
"libpthread.so.0",
- "libc.so.6",
+ "libresolv.so.2",
+ "linux-vdso.so.1",
}
_LINUX_LOADERS = {
"amd64": "/lib64/ld-linux-x86-64.so.2",
From 94217dc7d4202419b10104a5766887d922940582 Mon Sep 17 00:00:00 2001
From: David Li
Date: Thu, 13 Aug 2026 09:50:14 +0900
Subject: [PATCH 3/4] add libdl
---
adbc_drivers_dev/make_checks.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/adbc_drivers_dev/make_checks.py b/adbc_drivers_dev/make_checks.py
index 64a4703..75f768a 100644
--- a/adbc_drivers_dev/make_checks.py
+++ b/adbc_drivers_dev/make_checks.py
@@ -24,6 +24,7 @@
_LINUX_RUNTIME_DEPENDENCIES = {
"libc.so.6",
+ "libdl.so.2",
"libgcc_s.so.1",
"libm.so.6",
"libpthread.so.0",
From 400b3c724e1c2bbc8aaf36f0666cac2e196521ea Mon Sep 17 00:00:00 2001
From: David Li
Date: Thu, 13 Aug 2026 10:03:56 +0900
Subject: [PATCH 4/4] add librt
---
adbc_drivers_dev/make_checks.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/adbc_drivers_dev/make_checks.py b/adbc_drivers_dev/make_checks.py
index 75f768a..c6d81c3 100644
--- a/adbc_drivers_dev/make_checks.py
+++ b/adbc_drivers_dev/make_checks.py
@@ -29,6 +29,7 @@
"libm.so.6",
"libpthread.so.0",
"libresolv.so.2",
+ "librt.so.1",
"linux-vdso.so.1",
}
_LINUX_LOADERS = {