Hive
Buildable folders on static framework with resources: sources leak into the resource bundle target, localized resources stay in the framework
GitHub issue · Open
What happened?
For a .staticFramework target whose buildableFolders contain both sources and localized resources, Tuist attaches the same synchronized group to both the framework (Kit) and the generated bundle target (Repro_Kit), then subtracts files via membership exceptions:
Kit: membershipExceptions = (ru.lproj/Localizable.strings, en.lproj/Localizable.strings)
Repro_Kit: membershipExceptions = (Greeting.swift)
This causes two problems:
- Localized resources stay in the framework.
Kit.frameworkstill containsen.lproj/andru.lproj/. Xcode doesn’t match per-locale paths in exceptions for localized files; it expects the variant-group form"/Localized: Localizable.strings"(the form Xcode itself writes when you uncheck target membership of a localized file). - New sources leak into the bundle target. The bundle target’s exceptions are a snapshot of the
.swiftfiles at generation time. Any.swiftfile added afterwards (without regenerating) is compiled intoRepro_Kittoo. It either fails to build (cannot find '…' in scope) or silently produces an executable inside the bundle. That defeats the main benefit of buildable folders.
Expected: behaviour like SwiftPM: sources go only to the framework, resources only to the bundle, and new source files work without regenerating.
I verified the following by editing the generated project.pbxproj by hand: attach the group only to the framework target. For the bundle target, use membership exceptions as inclusions: for a target that doesn’t list the group in fileSystemSynchronizedGroups, Xcode treats membershipExceptions as files added to that target. Use the /Localized: form:
/* Kit exception set */
membershipExceptions = (
- ru.lproj/Localizable.strings,
- en.lproj/Localizable.strings,
+ "/Localized: Localizable.strings",
);
/* Repro_Kit exception set */
membershipExceptions = (
- Greeting.swift,
+ "/Localized: Localizable.strings",
);
/* Repro_Kit native target */
-fileSystemSynchronizedGroups = (
- 28740BEAE30BDFD6C23A822C /* Sources */,
-);
Result: Kit.framework has no .lproj; Repro_Kit.bundle contains only en.lproj, ru.lproj, Info.plist. A new .swift file compiles only into Kit without regenerating, and a new locale (de.lproj/Localizable.strings) is picked up into the bundle without regenerating. Remaining limitation: a brand-new non-localized resource needs tuist generate to be routed to the bundle.
Possibly related: #8547 / #8548.
How do we reproduce it?
Sample project attached (tuist-buildable-folders-repro.zip, steps also in its README).
tuist generate --no-openxcodebuild build -workspace Repro.xcworkspace -scheme Kit -destination "generic/platform=iOS Simulator" -derivedDataPath .ddls .dd/Build/Products/Debug-iphonesimulator/Kit.framework→ containsen.lprojandru.lproj- Without regenerating:
cp Extra/Added.swift Sources/ - Repeat step 2 → build fails,
Added.swiftis compiled with-module-name Repro_Kit
tuist-buildable-folders-repro.zip
Error log
Sources/Added.swift:2:24: error: cannot find 'Greeting' in scope
(compiled as part of target Repro_Kit, -module-name Repro_Kit)
No error for problem 1: Kit.framework silently contains en.lproj/ and ru.lproj/.
macOS version
26.3
Tuist version
4.210.0
Xcode version
26.3
Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.
Start a Flight and preserve its objective, outcome, and session here.
No GitHub comments yet.