Rename CZlib system module to FTZlib to avoid Linux collisions#3
Open
penguinboi wants to merge 1 commit into
Open
Rename CZlib system module to FTZlib to avoid Linux collisions#3penguinboi wants to merge 1 commit into
penguinboi wants to merge 1 commit into
Conversation
The system library module was previously named CZlib, the same name ZIPFoundation uses for its zlib wrapper. When both packages are pulled into the same SwiftPM resolution graph, the Linux toolchain rejects the duplicate module declaration and aborts the build: error: redefinition of module 'CZlib' macOS's linker tolerates the collision, but Linux does not. Renaming to FTZlib namespaces the module so it cannot collide with other packages that wrap zlib.
penguinboi
pushed a commit
to penguinboi/swiftarr
that referenced
this pull request
Apr 27, 2026
velocityzen/FileType ships a system library module called CZlib that collides with ZIPFoundation's identically-named module. The macOS toolchain accepts the duplicate, but Linux rejects it with "redefinition of module 'CZlib'", which broke the release Docker build for this PR. Point the dependency at penguinboi/FileType, which renames the system module to FTZlib. Verified via `docker build` against this repo's Dockerfile: full release build now succeeds in ~160s. Upstream PR is open at velocityzen/FileType#3; the fork pin will be removed once it lands.
13 tasks
cohoe
pushed a commit
to jocosocial/swiftarr
that referenced
this pull request
Apr 29, 2026
* feat: add Cvips system module with C shim functions for libvips Cvips is a system library target wrapping libvips via pkg-config. CvipsShim compiles typed C wrapper functions around variadic vips calls that Swift cannot call directly. * refactor: rename GDError to ImageError * feat: add SwiftarrImage libvips wrapper with comprehensive tests Implements the core image wrapper class backed by libvips, replacing GDImage for image load/resize/crop/flatten/export operations. Key changes: - SwiftarrImage.swift: VipsImage-backed class with RAII cleanup - SwiftarrImageTests.swift: 17 tests covering all operations - shim.c: fix vips_image_new_from_buffer calling convention (returns VipsImage* directly, not via output param), add swiftarr_vips_copy shim, change thumbnail resize mode to VIPS_SIZE_FORCE - Disable old GD-dependent files (Image.swift, Format.swift, ImageHandler.swift, ImageController.swift) with temporary stubs to keep the project building during migration * infra: initialize libvips at app startup * refactor: remove libgd, gdOverrides, and GD format machinery * feat: rewrite ImageHandler and ImageController to use SwiftarrImage (libvips) Replace all GDImage usage with SwiftarrImage in the image upload pipeline and generated image endpoints (QR codes, identicons). All uploaded images are now re-encoded as JPEG via libvips, eliminating format/orientation tracking. Fix identicon color2 bug that used r1 instead of r2. Remove dead `import gd` and gdSupportsFileType calls from configure.swift. * infra: replace libgd with libvips in Docker build * test: add HEIC/AVIF/JXL loading, pipeline, and identicon tests 12 new tests covering format support, loadImageFromData alpha flattening, and identicon determinism/dimensions. * fix: use VIPS_SIZE_BOTH for resize and add aspect ratio + pipeline tests VIPS_SIZE_FORCE could distort aspect ratio. VIPS_SIZE_BOTH fits within the bounding box preserving ratio, allowing both up and downscaling. Also adds tests for aspect ratio preservation and the crop→resize user profile pipeline. * feat: preserve animated GIF/WebP uploads when allowAnimatedImages is true Animated formats are detected via magic bytes and saved as original data instead of re-encoding to JPEG. Thumbnails are always static JPEG. Respects the existing Settings.shared.allowAnimatedImages toggle. * feat: preserve original format for unmodified uploads Matches original behavior: images that don't need resizing or cropping are saved in their original format (PNG stays PNG, GIF stays GIF). Only modified images (resized, cropped, profile avatars) are re-encoded as JPEG. Animated GIF/WebP passthrough respects allowAnimatedImages. * fix: always re-encode JPEGs to apply EXIF orientation Original JPEG bytes carry the pre-autorot EXIF orientation tag. Saving them as-is causes sideways display in viewers that ignore EXIF. Matches original libgd behavior which always re-encoded JPEGs. May fix #516. * style: fix indentation to tabs, update comments from review Convert SwiftarrImage.swift and tests to tab indentation matching project convention. Update ABOUTME and doc comments to describe current code rather than historical context. * fix: re-encode non-web formats and use nearest-neighbor for pixel art HEIC/AVIF/JXL/TIFF/BMP uploads are always re-encoded as JPEG since browsers can't reliably display them. Prevents saving non-web bytes with a .jpg extension. QR codes and identicons now use nearest-neighbor interpolation for crisp pixel-art scaling, matching the original libgd behavior. * chore: remove .claude/settings.local.json from tracking * test: add realistic image size tests (3000x2000, 4032x3024, profile crop) * fix: match thumbnail extension to full image format Thumbnails were saved as .jpg while passthrough images kept their original extension (.png, .gif, .webp). The UI looks up thumbnails using the full image's filename, causing broken links for non-JPEG passthrough uploads. * feat: add GIF and WebP export for correct thumbnail format Thumbnails for GIF/WebP uploads are now exported in the matching format instead of JPEG data with a mismatched extension. Ensures the app and browser both get correct content types. * feat: animated GIF/WebP thumbnails preserve all frames Thumbnails for animated uploads now resize all frames using vips_thumbnail_buffer with [n=-1], producing properly sized animated thumbnails instead of static single-frame previews. * fix: address review feedback — install docs and Sendable warnings Update macOS and Linux install docs to reflect the libvips migration (libvips-dev / vips-devel / brew install vips). Move loadImageFromData, createThumbnail, isAnimatableFormat, and detectExtension out of the APIRouteCollection extension and into top-level functions. The static methods captured Self.Type when called inside the threadPool isolated closure, producing #SendableMetatypes warnings. Free functions have no Self capture. * chore: address review nits — Fedora provider and remove ABOUTME headers - Add `.yum(["vips-devel"])` to the Cvips system library providers for Fedora dev experience parity. - Remove `// ABOUTME:` headers from new files. They were a personal convention rather than a project standard. * refactor: detect image formats with FileType library Replace hand-rolled magic-byte sniffing in isAnimatableFormat and detectExtension with the velocityzen/FileType package. Same goes for the inline JPEG header check in processImage. FileType matches against a curated set of image signatures and lets us narrow detection to the image MIME group, so non-image uploads no longer accidentally get a plausible-looking extension. Bumps swift-tools-version to 6.2 (FileType requires it; the project's .swift-version is already pinned to 6.2.0). * test: cover FileType-backed format detection helpers directly Adds 11 tests for isAnimatableFormat and detectExtension. Each helper is hit with real JPEG/PNG/GIF/WebP buffers (exported via SwiftarrImage) plus a non-image (zip) and garbage payload to verify the .image MIME-group filter rejects non-images cleanly. * fix: pin FileType to fork that namespaces its zlib module velocityzen/FileType ships a system library module called CZlib that collides with ZIPFoundation's identically-named module. The macOS toolchain accepts the duplicate, but Linux rejects it with "redefinition of module 'CZlib'", which broke the release Docker build for this PR. Point the dependency at penguinboi/FileType, which renames the system module to FTZlib. Verified via `docker build` against this repo's Dockerfile: full release build now succeeds in ~160s. Upstream PR is open at velocityzen/FileType#3; the fork pin will be removed once it lands. * ci: install vips for docs build The Generate Documentation workflow runs `swift build` (via sourcekitten) on a macOS runner to extract symbol info. It was still brewing the old `gd` dependency, which silently worked while libgd was in the source tree but fails now that the build resolves `pkg-config --exists vips` instead. * ci: build docs in a Linux Swift 6.2 container The macOS runner ships Swift 6.1.2, but the package now requires swift-tools-version 6.2 (FileType dependency), so `sourcekitten doc --spm` fails before it can extract symbols. Run the docs build in the swift:6.2-noble container instead. Matches the toolchain the main build uses, and stays consistent automatically the next time the project bumps Swift. Side effects: install SourceKitten from source (no apt package), bump actions/checkout from v2 to v4 (the v2 deprecation warning was already in the build log), and switch the system dependency from brew to apt. * Preserve alpha in PNG/GIF/WebP thumbnails Previously loadImageFromData unconditionally flattened alpha onto white, which made sense under libgd (always exported JPEG) but no longer fits the per-format export pipeline. The full image preserved alpha by passing original bytes through, while the thumbnail was generated from the in-memory flattened copy, so transparent PNGs would lose alpha in their thumbnails but keep it at full size. Move the flatten to the two JPEG export sites instead: - thumbnailData() flattens only when writing JPEG - the modified-image full re-encode flattens before JPEG output PNG/GIF/WebP thumbnails now keep their transparency, matching the full image. Animated GIF/WebP thumbnails are unchanged (they bypass the flattened in-memory copy via vips_animated_thumbnail). Adds 4 new unit tests; updates the now-inverted alpha-flatten test. --------- Co-authored-by: Skyler Lister Aley <slisteraley@curtail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
FileTypedeclares its zlib system library wrapper as a module namedCZlib. That generic name collides with other Swift packages that wrap zlib the same way — most notablyweichsel/ZIPFoundation, which also calls its moduleCZlib. When both packages end up in the same SwiftPM resolution graph, the Linux toolchain rejects the duplicate module declaration:The macOS toolchain currently tolerates the collision, but Linux builds (including release Docker images for server-side Swift projects) fail outright. We hit this in jocosocial/swiftarr#548 when adopting FileType alongside an existing ZIPFoundation dependency.
Fix
Rename the system library module from
CZlibtoFTZlib(FileType-namespaced):Sources/CZlib/→Sources/FTZlib/(modulemap + shim header)module CZlib [system]→module FTZlib [system]in the modulemapimport CZlib→import FTZlibinSources/FileType/zip+office.swiftdependenciesupdated inPackage.swiftPublic API is untouched — only the internal system module name changes. Downstream packages don't see the rename.
Verification
swift build— clean (macOS 14, Swift 6.2)swift test— all 27 tests passjocosocial/swiftarrbuilding inside the project's Docker image (Ubuntu Noble + Swift 6.2): theredefinition of module 'CZlib'error is gone, full release build succeeds in ~160s.Rationale for the name
System library module names should be unique enough that they can't collide with other packages wrapping the same C library.
FTZlibfollows the convention of prefixing with the project initials (similar to how Apple usesNIO*for SwiftNIO's modules). Open to a different name if you'd prefer something else.