auditwheel

repository·main·Indexed 19 days ago

https://github.com/pypa/auditwheel

A command-line tool used to audit and repair Python wheels for Linux and Android. It ensures wheels with pre-compiled binary extensions are compatible with distribution standards like manylinux and android by bundling necessary shared libraries. Key features include the `show` command for inspecting dependencies, the `repair` command for vendoring external libraries and updating platform tags, and the `lddtree` command for analyzing shared library dependencies.

Tokens
4K
Snippets
17
Records
20
Agent score
68%

What's inside auditwheel

  1. Limitations of auditwheel

    main

    Users should be aware of the following technical limitations:

    1. Dynamic Loading: auditwheel relies on DT_NEEDED information (similar to ldd). It cannot detect dependencies that are loaded dynamically at runtime via ctypes, cffi (from Python), or dlopen (from C/C++).
    2. Core Library Versioning: auditwheel cannot fix binaries that were compiled against a version of libc or libstdc++ that is too recent. Because of symbol versioning, code compiled on a new system will not run on older systems. To avoid this, always perform builds on an older distribution (like a manylinux Docker image).
  2. Requirements for using auditwheel

    main

    To use auditwheel, ensure your environment meets the following requirements:

    • OS: Linux (macOS may be used specifically for building Android wheels).
    • Python: 3.10 or higher.
    • patchelf: version 0.14 or higher.
    • Linkage: The system must use ELF-based linkage.

    Recommendation: To ensure compatibility, build wheels on older Linux distributions. It is highly recommended to use the pre-built manylinux Docker images instead of building on a modern host OS.

    $ docker run -i -t -v `pwd`:/io quay.io/pypa/manylinux_2_28_x86_64 /bin/bash
  3. Handle `repair` errors related to ABI compatibility

    main

    The repair command may fail if the wheel's contents are incompatible with the requested platform's ABI (Application Binary Interface). Common error scenarios include:

    • Too-recent versioned symbols: The wheel contains symbols from a version of a library newer than what the target platform supports. You must recompile the wheel on an older toolchain.
    • UCS2 vs Wide-Unicode: The wheel was compiled against a UCS2 build of Python, but the target platform requires a wide-unicode build.
    • Black-listed symbols: The wheel depends on symbols that are explicitly black-listed for the target platform.
    • Unsupported ISA extensions: The wheel depends on CPU instruction set extensions (like AVX) that are not supported by the target machine policy.
  4. Exclude specific libraries from `repair` using `--exclude`

    main

    When running repair, you can prevent certain shared libraries from being copied into the wheel by using the --exclude flag. This is useful if you want to ensure the wheel still relies on a system-provided version of a specific library. You can specify this flag multiple times and use wildcards.

    Note: If you exclude a library, you must ensure that your wheel's metadata correctly reflects that this dependency is still required by the environment.

    auditwheel repair my_wheel.whl --exclude "libfoo.so.*" --exclude "libbar.so.1"
  5. Repair a wheel with auditwheel repair

    main

    Use the auditwheel repair command to make a wheel compatible with manylinux or android platform tags. The tool copies required external shared libraries into the wheel itself and automatically modifies RPATH entries so the libraries are found at runtime. This effectively bundles the dependencies without requiring changes to the original build system.

    $ auditwheel repair cffi-1.5.2-cp35-cp35m-linux_x86_64.whl
  6. Inspect a wheel with auditwheel show

    main

    Use the auditwheel show command to inspect a Python wheel. It identifies external shared libraries that the wheel depends on (beyond those allowed by manylinux policies) and checks for versioned symbols that exceed the allowed ABI. This helps determine what dependencies need to be eliminated or bundled to achieve a specific platform tag (e.g., manylinux1_x86_64).

    $ auditwheel show cffi-1.5.0-cp35-cp35m-linux_x86_64.whl
  7. Add or remove platform tags from a wheel

    main

    The add_platforms function updates a wheel's filename and its internal WHEEL metadata to include new platform tags (e.g., moving from linux_x86_64 to manylinux_2_28_x86_64).

    • platforms: A list of platform tags to add.
    • remove_platforms: An iterable of platform tags to remove.
    • Side Effects:
      • Updates the WHEEL file's Tag headers.
      • If the wheel is no longer a pure Python wheel (e.g., adding a platform tag to an any wheel), it sets Root-Is-Purelib to False in the WHEEL file.
      • Updates the out_wheel attribute of the provided InWheelCtx to the new filename.
    from auditwheel.wheeltools import InWheelCtx, add_platforms
    from pathlib import Path
    
    in_wheel = Path("my_package-1.0-cp39-cp39-any.whl")
    
    with InWheelCtx(in_wheel) as ctx:
        # Add manylinux tags and remove the 'any' tag
        add_platforms(
            wheel_ctx=ctx, 
            platforms=['manylinux_2_28_x86_64'], 
            remove_platforms=['any']
        )
        # The new wheel filename is now stored in ctx.out_wheel
  8. Handle auditwheel errors using AuditwheelError

    main

    When integrating with auditwheel programmatically, you can catch AuditwheelError to handle general failures during the auditing or repair process. All specific error types in the package inherit from this base class.

    Specific subclasses include:

    • InvalidLibcError: Raised when the detected libc is incompatible.
    • WheelToolsError: Raised when external wheel tools encounter issues.
    • NonPlatformWheelError: Raised when the wheel does not appear to be a platform wheel (e.g., it contains no ELF binaries).
    from auditwheel import AuditwheelError, NonPlatformWheelError
    
    try:
        # Perform auditwheel operations
        pass
    except NonPlatformWheelError as e:
        print(f"The wheel is not a platform wheel: {e.message}")
    except AuditwheelError as e:
        print(f"An auditwheel error occurred: {e.message}")
  9. Manage wheel contents with InWheelCtx

    main

    The InWheelCtx context manager allows you to unpack a wheel, perform modifications on its contents in a temporary directory, and automatically repack it into a new wheel file upon exit.

    Key features:

    • Automatic Repacking: If out_wheel is provided, the context manager rewrites the RECORD file (to ensure hashes match the new contents) and zips the directory back into a .whl file.
    • File Iteration: Use iter_files() to iterate over the files listed in the wheel's RECORD file.
    • Context Return: Unlike the standard InWheel, InWheelCtx returns itself from __enter__, allowing you to configure properties like out_wheel after entering the context.

    Note: If you modify files, the RECORD file is automatically updated to reflect new hashes and file sizes, and any existing RECORD.jws signatures are removed to prevent invalidation errors.

    from auditwheel.wheeltools import InWheelCtx
    from pathlib import Path
    
    in_wheel = Path("my_package-1.0-cp39-cp39-linux_x86_64.whl")
    
    with InWheelCtx(in_wheel) as ctx:
        # Set the output path after entering the context
        ctx.out_wheel = Path("my_package-1.0-cp39-cp39-manylinux_2_28_x86_64.whl")
        
        # Iterate through files listed in the RECORD
        for file_path in ctx.iter_files():
            print(f"Processing {file_path}")
            # Perform modifications here...
    
    # Upon exiting, the new wheel is written to ctx.out_wheel
  10. Get platform tags from a wheel filename

    main

    The get_wheel_platforms(filename: str) function parses a wheel filename and returns a sorted list of unique platform tags extracted from the filename components.

    from auditwheel.wheeltools import get_wheel_platforms
    
    # Example filename with multiple tags (if supported by parser)
    filename = "my_package-1.0-cp39-cp39-macosx_10_9_x86_64.whl"
    platforms = get_wheel_platforms(filename)
    # Output: ['macosx_10_9_x86_64']
  11. Access error messages via the .message property

    main

    All AuditwheelError exceptions provide a .message property that returns the error string. This is useful for extracting the human-readable reason for a failure during automated processing.

    # Assuming 'e' is an instance of AuditwheelError
    error_text = e.message