From e5b144c5e3c7035260b3347ff3e662662ae3bf75 Mon Sep 17 00:00:00 2001 From: Fabian Witt Date: Thu, 5 Nov 2026 15:57:58 +0100 Subject: [PATCH 1/2] fix(build): ship only the native library lib.py loads in the wheels copy_platform_libraries() copied every file of the c2pa-rs release archive into src/c2pa/libs/, and package_data ships all of them. Next to the shared library that lib.py loads via ctypes, the archives contain a static library, import library, debug symbols and dep-info files (c2pa_c.lib, c2pa_c.dll.lib, c2pa_c.dll.exp, c2pa_c.pdb, libc2pa_c.rlib, libc2pa_c.dylib.dSYM.zip, *.d). None of them is used at runtime. Copy only c2pa_c.dll / libc2pa_c.dylib / libc2pa_c.so, and fail the build if that file is missing instead of packaging whatever the folder holds. Measured with c2pa-rs v0.91.10: the win_amd64 wheel shrinks from 94,949,858 to 9,028,773 bytes. Refs #346. --- setup.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index ddf6e985..be475ad5 100644 --- a/setup.py +++ b/setup.py @@ -117,8 +117,24 @@ def get_current_platform(): return "linux_aarch64" return "linux_x86_64" +def get_native_library_name(platform_name): + """Get the file name of the native library that src/c2pa/lib.py loads.""" + if platform_name.endswith('windows-msvc'): + return "c2pa_c.dll" + elif platform_name.endswith('apple-darwin'): + return "libc2pa_c.dylib" + elif platform_name.endswith('linux-gnu'): + return "libc2pa_c.so" + else: + raise ValueError(f"Unknown platform: {platform_name}") + def copy_platform_libraries(platform_name, clean_first=False): - """Copy libraries for a specific platform to the package libs directory. + """Copy the native library for a specific platform to the package libs directory. + + Only the library loaded at runtime is copied. The c2pa-rs release archives + also contain static libraries, debug symbols and build metadata + (.lib, .rlib, .pdb, .dSYM, .d), which are not needed and would otherwise + end up in the wheel. Args: platform_name: The platform to copy libraries for @@ -126,14 +142,13 @@ def copy_platform_libraries(platform_name, clean_first=False): """ platform_dir = ARTIFACTS_DIR / platform_name - # Ensure the platform directory exists and contains files + # Ensure the platform directory exists and contains the library if not platform_dir.exists(): raise ValueError(f"Platform directory not found: {platform_dir}") - # Get list of all files in the platform directory - platform_files = list(platform_dir.glob('*')) - if not platform_files: - raise ValueError(f"No files found in platform directory: {platform_dir}") + library_file = platform_dir / get_native_library_name(platform_name) + if not library_file.is_file(): + raise ValueError(f"Native library not found: {library_file}") # Clean and recreate the package libs directory if requested if clean_first and PACKAGE_LIBS_DIR.exists(): @@ -142,10 +157,7 @@ def copy_platform_libraries(platform_name, clean_first=False): # Ensure the package libs directory exists PACKAGE_LIBS_DIR.mkdir(parents=True, exist_ok=True) - # Copy files from platform-specific directory to the package libs directory - for file in platform_files: - if file.is_file(): - shutil.copy2(file, PACKAGE_LIBS_DIR / file.name) + shutil.copy2(library_file, PACKAGE_LIBS_DIR / library_file.name) def find_available_platforms(): """Scan the artifacts directory for available platform-specific libraries.""" From b172cea6c71523e097288f36a9f235324b5e3ad2 Mon Sep 17 00:00:00 2001 From: Fabian Witt Date: Sun, 8 Nov 2026 10:45:19 +0100 Subject: [PATCH 2/2] refactor(build): look up the native library in PLATFORM_FOLDERS PLATFORM_FOLDERS already listed the seven c2pa-rs platform folders, but only its keys were read. Its values now name the library that lib.py loads, so copy_platform_libraries() takes the file name from there and the separate get_native_library_name() mapping is gone. An unknown platform still fails the build. PLATFORM_EXTENSIONS was a third mapping that nothing read, so it is removed. Also applies the docstring wording suggested in review. --- setup.py | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/setup.py b/setup.py index be475ad5..e90bb79e 100644 --- a/setup.py +++ b/setup.py @@ -26,24 +26,16 @@ def get_version(): VERSION = get_version() PACKAGE_NAME = "c2pa-python" # Define package name as a constant -# Define platform to library extension mapping (for reference only) -PLATFORM_EXTENSIONS = { - 'win_amd64': 'dll', - 'win_arm64': 'dll', - 'apple-darwin': 'dylib', # universal - 'linux_x86_64': 'so', - 'linux_aarch64': 'so', -} - -# Based on what c2pa-rs repo publishes +# Based on what c2pa-rs repo publishes: each platform folder and the +# native library in it that src/c2pa/lib.py loads PLATFORM_FOLDERS = { - 'universal-apple-darwin': 'dylib', - 'aarch64-apple-darwin': 'dylib', - 'x86_64-apple-darwin': 'dylib', - 'x86_64-pc-windows-msvc': 'dll', - 'aarch64-pc-windows-msvc': 'dll', - 'x86_64-unknown-linux-gnu': 'so', - 'aarch64-unknown-linux-gnu': 'so', + 'universal-apple-darwin': 'libc2pa_c.dylib', + 'aarch64-apple-darwin': 'libc2pa_c.dylib', + 'x86_64-apple-darwin': 'libc2pa_c.dylib', + 'x86_64-pc-windows-msvc': 'c2pa_c.dll', + 'aarch64-pc-windows-msvc': 'c2pa_c.dll', + 'x86_64-unknown-linux-gnu': 'libc2pa_c.so', + 'aarch64-unknown-linux-gnu': 'libc2pa_c.so', } # Directory structure @@ -117,21 +109,10 @@ def get_current_platform(): return "linux_aarch64" return "linux_x86_64" -def get_native_library_name(platform_name): - """Get the file name of the native library that src/c2pa/lib.py loads.""" - if platform_name.endswith('windows-msvc'): - return "c2pa_c.dll" - elif platform_name.endswith('apple-darwin'): - return "libc2pa_c.dylib" - elif platform_name.endswith('linux-gnu'): - return "libc2pa_c.so" - else: - raise ValueError(f"Unknown platform: {platform_name}") - def copy_platform_libraries(platform_name, clean_first=False): """Copy the native library for a specific platform to the package libs directory. - Only the library loaded at runtime is copied. The c2pa-rs release archives + Only the library loaded at runtime is copied. The native Rust lib release archives also contain static libraries, debug symbols and build metadata (.lib, .rlib, .pdb, .dSYM, .d), which are not needed and would otherwise end up in the wheel. @@ -146,7 +127,11 @@ def copy_platform_libraries(platform_name, clean_first=False): if not platform_dir.exists(): raise ValueError(f"Platform directory not found: {platform_dir}") - library_file = platform_dir / get_native_library_name(platform_name) + library_name = PLATFORM_FOLDERS.get(platform_name) + if library_name is None: + raise ValueError(f"Unknown platform: {platform_name}") + + library_file = platform_dir / library_name if not library_file.is_file(): raise ValueError(f"Native library not found: {library_file}")