{"record":{"id":"08a18ba01766431c","repo":"headroomlabs-ai/headroom","slug":"neither-objdump-nor-llvm-objdump-is-on-path-i","errorCode":null,"errorMessage":"neither `objdump` nor `llvm-objdump` is on PATH; install binutils (Linux) or LLVM (macOS) to run this audit","messagePattern":"neither `objdump` nor `llvm-objdump` is on PATH; install binutils \\(Linux\\) or LLVM \\(macOS\\) to run this audit","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"scripts/audit_wheel_glibc_symbols.py","lineNumber":101,"sourceCode":"    \"\"\"\n    m = re.search(r\"manylinux_(\\d+)_(\\d+)_\", wheel_filename)\n    if m:\n        return (int(m.group(1)), int(m.group(2)))\n    # `manylinux2014_x86_64` is the legacy alias for manylinux_2_17.\n    if \"manylinux2014_\" in wheel_filename:\n        return (2, 17)\n    if \"manylinux1_\" in wheel_filename:\n        return (2, 5)\n    return None\n\n\ndef list_undef_symbols(so_path: Path) -> list[tuple[str, str]]:\n    \"\"\"Return [(symbol_name, glibc_version_or_empty), ...] for every\n    UND (undefined) dynamic symbol in `so_path`.\n    \"\"\"\n    objdump = shutil.which(\"objdump\") or shutil.which(\"llvm-objdump\")\n    if not objdump:\n        raise RuntimeError(\n            \"neither `objdump` nor `llvm-objdump` is on PATH; \"\n            \"install binutils (Linux) or LLVM (macOS) to run this audit\"\n        )\n    out = subprocess.run(\n        [objdump, \"-T\", str(so_path)],\n        check=True,\n        capture_output=True,\n        text=True,\n    ).stdout\n    found = []\n    for line in out.splitlines():\n        # `objdump -T` lines: `address SECTION ... NAME` where SECTION\n        # contains `*UND*` for undefined references and a versioned\n        # symbol name like `__isoc23_strtoll@GLIBC_2.38` or unversioned.\n        if \"*UND*\" not in line:\n            continue\n        # The last whitespace-separated token is the (versioned) symbol.\n        token = line.split()[-1]","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/scripts/audit_wheel_glibc_symbols.py#L83-L119","documentation":"audit_wheel_glibc_symbols.py shells out to objdump -T to enumerate undefined dynamic symbols of bundled .so files and compare their glibc version requirements against the wheel's manylinux tag. It requires either GNU objdump (binutils) or llvm-objdump on PATH; with neither found via shutil.which, it raises immediately rather than producing an incomplete audit.","triggerScenarios":"Running scripts/audit_wheel_glibc_symbols.py on a machine without binutils or LLVM installed — minimal Docker images (slim/distroless builders), fresh macOS without LLVM, CI containers that never installed binutils, or a PATH that hides /usr/bin.","commonSituations":"Running the wheel audit in a slim CI image (python:3.x-slim has no binutils); macOS where objdump is not part of default CLI tools and llvm-objdump is not installed; local venv scripts dir shadowing PATH.","solutions":["Linux/CI: install binutils (apt-get install -y binutils, or the distro equivalent)","macOS: brew install llvm and ensure $(brew --prefix llvm)/bin is on PATH so llvm-objdump resolves","Or point PATH at an existing toolchain image / run the audit inside a manylinux builder container that already has objdump"],"exampleFix":"# before\npython scripts/audit_wheel_glibc_symbols.py dist/*.whl  # RuntimeError: no objdump\n\n# after (Debian/CI)\napt-get update && apt-get install -y binutils\npython scripts/audit_wheel_glibc_symbols.py dist/*.whl","handlingStrategy":"validation","validationCode":"import shutil, sys\n\n# Run before the audit script\ndef objdump_available() -> bool:\n    return shutil.which(\"objdump\") is not None or shutil.which(\"llvm-objdump\") is not None\n\nif not objdump_available():\n    sys.exit(\"objdump/llvm-objdump missing — apt-get install binutils (or brew install llvm)\")","typeGuard":"import shutil\n\ndef has_objdump() -> bool:\n    \"\"\"True when the wheel audit can run on this machine.\"\"\"\n    return shutil.which(\"objdump\") is not None or shutil.which(\"llvm-objdump\") is not None","tryCatchPattern":null,"preventionTips":["Install binutils in CI images that run wheel audits (apt-get install -y binutils)","On macOS, brew install llvm and add its bin dir to PATH so llvm-objdump resolves","Fail the audit job early on a missing-toolcheck instead of deep inside symbol parsing"],"tags":["tooling","ci","python","packaging","environment"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}