Hive Hive
Sign in

feat(cli): Support library products in the module cache

GitHub issue · Closed

Metadata
Source
tuist/tuist #11290
Updated
Jun 24, 2026
Domains
Cache
Details

Adds Module Cache support for static and dynamic library products, building on the XCTest and Swift Testing support framework cache work from #11281.

Related PRs

What changed

  • Static and dynamic library targets are now treated as cacheable binary products in hashing, EE binary target selection, and warm generation.
  • Cache warm now creates library XCFrameworks with xcodebuild -create-xcframework -library, and passes -headers when the source target declares public headers.
  • XCFramework Info.plist decoding now preserves HeadersPath, and graph traversal exposes cached library Swift module directories and public header directories to generated targets.
  • Added a complex acceptance fixture that combines static libraries, dynamic libraries, static frameworks, dynamic frameworks, Swift imports, and a public C header smoke build.
  • Updated the Module Cache guide and changelog to document library support, including Swift modules and public C/Objective-C headers.

Why it changed

.xcframework artifacts support both frameworks and libraries, but the module cache flow only selected framework products for binary caching. That meant projects using static or dynamic library targets still had to rebuild those modules from source, even when their graph could otherwise be restored from cached binaries.

The missing piece was not just selecting libraries. Generated projects also need the metadata required to compile against a cached library artifact. Swift libraries need their .swiftmodule directories in the include paths, and C/Objective-C libraries need public headers from the XCFramework slice.

Root cause

The cacheable product lists and EE binary scheme selection were framework-centric. The warm step always emitted -framework arguments when creating XCFrameworks, so library products were never produced as cache artifacts. On restore, graph traversal only propagated public headers and Swift include paths for direct .library dependencies, not for library-based .xcframework dependencies.

Solution rationale

The implementation uses Xcode’s native XCFramework library support instead of introducing a custom artifact format or wrapping libraries as frameworks. For library products, cache warm now emits -library arguments and includes -headers when public headers exist. On restore, Tuist reads the standard HeadersPath metadata that Xcode writes into XCFramework Info.plist files and maps it back into header search paths.

This keeps the artifact format aligned with Xcode, preserves the existing framework cache behavior, and lets mixed framework/library graphs use the same binary cache pipeline.

User and developer impact

Projects with static or dynamic library targets can now reuse module cache binaries across local and CI builds. Mixed graphs can cache reusable library modules without forcing those modules to become frameworks. Test bundles remain excluded from binary caching, but framework and library targets that tests depend on can be cached.

How to test locally

  • TUIST_EE=1 TUIST_ENABLE_CACHING=1 tuist install --path .
  • TUIST_EE=1 TUIST_ENABLE_CACHING=1 tuist generate run --no-open --cache-profile none --path . tuist ProjectDescription TuistCoreTests TuistCacheTests TuistCacheEETests TuistCacheEEAcceptanceTests
  • TUIST_EE=1 TUIST_ENABLE_CACHING=1 tuist generate run --no-open --cache-profile none --path . tuist ProjectDescription TuistCacheEETests
  • xcodebuild test -workspace Tuist.xcworkspace -scheme TuistUnitTests '-only-testing:TuistCoreTests/GraphTraverserTests/test_librariesPublicHeadersFolders_includesLibraryXCFrameworkHeaders' '-only-testing:TuistCoreTests/GraphTraverserTests/test_librariesSwiftIncludePaths_includesLibraryXCFrameworkSwiftModules' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=""
  • xcodebuild test -workspace Tuist.xcworkspace -scheme TuistUnitTests '-only-testing:TuistCacheEETests/GenerateCacheableSchemesGraphMapperTests/test_map_when_cacheable_schemes_are_generated' '-only-testing:TuistCacheEETests/TargetsToCacheBinariesGraphMapperTests/test_map_when_library_binaries_are_fetched_successfully' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=""
  • xcodebuild test -workspace Tuist.xcworkspace -scheme TuistCacheEEAcceptanceTests '-only-testing:TuistCacheEEAcceptanceTests/TuistCacheEEAcceptanceTests/generated_macos_tool_with_cached_libraries_and_frameworks()' CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY=""
  • git diff --check
Comments
T
tuist[bot] Jun 15, 2026

🛠️ Tuist Run Report 🛠️

Tests 🧪
Scheme Status Cache hit rate Tests Skipped Ran Commit
TuistAcceptanceTests 0 % 0 0 0 829e16b08
TuistUnitTests 85 % 2981 5 2976 829e16b08
Flaky Tests ⚠️
  • TuistUnitTests: 3 flaky tests (View all)
Test case Module Suite
parseTestStatuses_returnsCorrectStatuses() TuistXCResultServiceTests XCResultServiceTests
parseTestStatuses_extractsModuleAndSuiteNames() TuistXCResultServiceTests XCResultServiceTests
parseTestWithCustomLabelXCResult() TuistXCResultServiceTests XCResultServiceTests
Builds 🔨
Scheme Status Duration Commit
TuistAcceptanceTests 1m 25s 829e16b08
TuistUnitTests 2m 47s 829e16b08
TA
tuist-atlas[bot] Jun 17, 2026

This feature is now available in 4.201.0-canary.5. Update to this version to use library products in the module cache.

TA
tuist-atlas[bot] Jun 18, 2026

Support for library products in the module cache is now available in 4.201.0-canary.8. Update to this version to cache static and dynamic library targets as binary products alongside frameworks.

TA
tuist-atlas[bot] Jun 18, 2026

The support for library products in the module cache is now available in 4.201.0-canary.7. This change allows static and dynamic library targets to be cached as binary XCFrameworks using -create-xcframework -library, with proper handling of public headers and Swift module directories on restore.

Update to 4.201.0-canary.7 to use this feature.

TA
tuist-atlas[bot] Jun 18, 2026

The changes to support library products in the module cache are now available in version 4.201.0-canary.6. Update to this version to use the new library caching capabilities for static and dynamic library targets.

TA
tuist-atlas[bot] Jun 19, 2026

Support for library products in the module cache is now available in 4.201.0-canary.9. Static and dynamic library targets are now treated as cacheable binary products in hashing, binary target selection, and warm generation. Projects with static or dynamic library targets can now reuse module cache binaries across local and CI builds. Update to 4.201.0-canary.9 to use this feature.

TA
tuist-atlas[bot] Jun 19, 2026

The changes from this pull request are now available in version 4.201.0-canary.13. Update to that version to use the library products module cache support.

TA
tuist-atlas[bot] Jun 19, 2026

Support for library products in the module cache is now available in 4.201.0-canary.12. Static and dynamic library targets are now treated as cacheable binary products, with library XCFrameworks created using xcodebuild -create-xcframework -library. Update to this version to enable library caching in your projects.

TA
tuist-atlas[bot] Jun 19, 2026

Support for library products in the module cache is now available in 4.201.0-canary.11. Static and dynamic library targets are now treated as cacheable binary products, with cache warm creating library XCFrameworks and graph traversal exposing cached library Swift module directories and public header directories to generated targets.

Update to 4.201.0-canary.11 to use this feature.

TA
tuist-atlas[bot] Jun 19, 2026

This is now available in 4.201.0-canary.10. Update to pick up library product support in the module cache.

TA
tuist-atlas[bot] Jun 20, 2026

Support for library products in the module cache is now available in 4.201.0-canary.18. Update to this version to use it.

TA
tuist-atlas[bot] Jun 20, 2026

Support for library products in the module cache is now available in 4.201.0-canary.17. Update to this version to cache static and dynamic library targets.

TA
tuist-atlas[bot] Jun 20, 2026

The fix for library products support in the module cache is now available in 4.201.0-canary.16. Update to this version to enable caching for static and dynamic library targets alongside framework products.

TA
tuist-atlas[bot] Jun 20, 2026

Support for library products in the module cache is now available in 4.201.0-canary.15. Static and dynamic library targets are now treated as cacheable binary products, allowing projects using library targets to reuse module cache binaries across local and CI builds. Update to this version to use the new library caching capabilities.

TA
tuist-atlas[bot] Jun 20, 2026

The support for library products in the module cache is now available in version 4.201.0-canary.14. Update to this version to use the new library caching capabilities for static and dynamic library targets.

TA
tuist-atlas[bot] Jun 21, 2026

Support for library products (static and dynamic libraries) in the module cache is now available in 4.201.0-canary.19. This extends the module cache to library products, allowing cached library XCFrameworks with proper Swift module and public header handling. Update to 4.201.0-canary.19 to use this feature.