Skip to content

Commit fc3609a

Browse files
Tantalum73Andreas Neusuessowenv
authored
[6.3]Check ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS and STRING_CATALOG_GENERATE_SYMBOLS build settings before moving compilation of Asset Catalog and String Catalog into Souece phase (#1176)
* Check ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS and STRING_CATALOG_GENERATE_SYMBOLS build settings before moving compilation of Asset Catalog and String Catalog into Souece phase * Update tests for 6.3 branch --------- Co-authored-by: Andreas Neusuess <andreas_n@apple.com> Co-authored-by: Owen Voorhees <ovoorhees@apple.com>
1 parent 3f6bde8 commit fc3609a

5 files changed

Lines changed: 178 additions & 9 deletions

File tree

Sources/SWBApplePlatform/Plugin.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,10 @@ struct ActoolInputFileGroupingStrategyExtension: InputFileGroupingStrategyExtens
181181
return ["actool": Factory()]
182182
}
183183

184-
func fileTypesCompilingToSwiftSources() -> [String] {
184+
func fileTypesCompilingToSwiftSources(scope: MacroEvaluationScope) -> [String] {
185+
guard scope.evaluate(BuiltinMacros.ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS) else {
186+
return []
187+
}
185188
return ["folder.abstractassetcatalog"]
186189
}
187190
}
@@ -196,7 +199,7 @@ struct ImageScaleFactorsInputFileGroupingStrategyExtension: InputFileGroupingStr
196199
return ["image-scale-factors": Factory()]
197200
}
198201

199-
func fileTypesCompilingToSwiftSources() -> [String] {
202+
func fileTypesCompilingToSwiftSources(scope: MacroEvaluationScope) -> [String] {
200203
return []
201204
}
202205
}
@@ -211,7 +214,7 @@ struct LocalizationInputFileGroupingStrategyExtension: InputFileGroupingStrategy
211214
return ["region": Factory()]
212215
}
213216

214-
func fileTypesCompilingToSwiftSources() -> [String] {
217+
func fileTypesCompilingToSwiftSources(scope: MacroEvaluationScope) -> [String] {
215218
return []
216219
}
217220
}
@@ -226,7 +229,10 @@ struct XCStringsInputFileGroupingStrategyExtension: InputFileGroupingStrategyExt
226229
return ["xcstrings": Factory()]
227230
}
228231

229-
func fileTypesCompilingToSwiftSources() -> [String] {
232+
func fileTypesCompilingToSwiftSources(scope: MacroEvaluationScope) -> [String] {
233+
guard scope.evaluate(BuiltinMacros.STRING_CATALOG_GENERATE_SYMBOLS) else {
234+
return []
235+
}
230236
return ["text.json.xcstrings"]
231237
}
232238
}

Sources/SWBCore/Extensions/InputFileGroupingStrategyExtension.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
public import SWBUtil
14+
public import SWBMacro
1415

1516
public struct InputFileGroupingStrategyExtensionPoint: ExtensionPoint, Sendable {
1617
public typealias ExtensionProtocol = InputFileGroupingStrategyExtension
@@ -22,5 +23,5 @@ public struct InputFileGroupingStrategyExtensionPoint: ExtensionPoint, Sendable
2223

2324
public protocol InputFileGroupingStrategyExtension: Sendable {
2425
func groupingStrategies() -> [String: any InputFileGroupingStrategyFactory]
25-
func fileTypesCompilingToSwiftSources() -> [String]
26+
func fileTypesCompilingToSwiftSources(scope: MacroEvaluationScope) -> [String]
2627
}

Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/FilesBasedBuildPhaseTaskProducer.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,10 @@ extension PluginManager {
325325
/// Returns identifiers of file types that can generate sources, and therefore need to be processed within the Sources build phase (at least if there are any existing source files).
326326
///
327327
/// Asset Catalogs would be one example of this, so that they can generate symbols.
328-
func fileTypesProducingGeneratedSources() -> [String] {
328+
func fileTypesProducingGeneratedSources(scope: MacroEvaluationScope) -> [String] {
329329
var compileToSwiftFileTypes : [String] = []
330330
for groupingStragegyExtensions in extensions(of: InputFileGroupingStrategyExtensionPoint.self) {
331-
compileToSwiftFileTypes.append(contentsOf: groupingStragegyExtensions.fileTypesCompilingToSwiftSources())
331+
compileToSwiftFileTypes.append(contentsOf: groupingStragegyExtensions.fileTypesCompilingToSwiftSources(scope: scope))
332332
}
333333
return compileToSwiftFileTypes
334334
}
@@ -614,7 +614,7 @@ package class FilesBasedBuildPhaseTaskProducerBase: PhasedTaskProducer {
614614
// Reorder resolvedBuildFiles so that file types which compile to Swift appear first in the list and so are processed first.
615615
// This is needed because generated sources aren't added to the the main source code list.
616616
// rdar://102834701 (File grouping for 'collection groups' is sensitive to ordering of build phase members)
617-
let compileToSwiftFileTypes = context.workspaceContext.core.pluginManager.fileTypesProducingGeneratedSources()
617+
let compileToSwiftFileTypes = context.workspaceContext.core.pluginManager.fileTypesProducingGeneratedSources(scope: scope)
618618
var compileToSwiftFiles = [ResolvedBuildFile]()
619619
var otherBuildFiles = [ResolvedBuildFile]()
620620
for resolvedBuildFile in resolvedBuildFiles {
@@ -792,7 +792,7 @@ package class FilesBasedBuildPhaseTaskProducerBase: PhasedTaskProducer {
792792
return []
793793
}
794794

795-
let fileIdentifiersGeneratingSources = context.workspaceContext.core.pluginManager.fileTypesProducingGeneratedSources()
795+
let fileIdentifiersGeneratingSources = context.workspaceContext.core.pluginManager.fileTypesProducingGeneratedSources(scope: scope)
796796
guard !fileIdentifiersGeneratingSources.isEmpty else {
797797
return []
798798
}

Tests/SWBTaskConstructionTests/AssetCatalogTaskConstructionTests.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,75 @@ fileprivate struct AssetCatalogTaskConstructionTests: CoreBasedTests {
528528
}
529529
}
530530
}
531+
532+
/// When asset symbol generation is disabled, the asset catalog must stay in the Resources phase
533+
/// and not be moved to Sources. This matters for projects where the xcassets is generated by a
534+
/// preceding script phase and doesn't exist during Sources processing.
535+
@Test(.requireSDKs(.macOS))
536+
func disabledAssetSymbolGeneration() async throws {
537+
let swiftFeatures = try await self.swiftFeatures
538+
539+
let testProject = try await TestProject(
540+
"Project",
541+
groupTree: TestGroup(
542+
"ProjectSources",
543+
path: "Sources",
544+
children: [
545+
TestFile("App.swift"),
546+
TestFile("Assets.xcassets"),
547+
]
548+
),
549+
buildConfigurations: [
550+
TestBuildConfiguration("Debug", buildSettings: [
551+
"PRODUCT_NAME": "$(TARGET_NAME)",
552+
"ASSETCATALOG_EXEC": actoolPath.str,
553+
])
554+
],
555+
targets: [
556+
TestStandardTarget(
557+
"App",
558+
type: .framework,
559+
buildConfigurations: [
560+
TestBuildConfiguration("Debug", buildSettings: [
561+
"SKIP_INSTALL": "YES",
562+
"SWIFT_EXEC": swiftCompilerPath.str,
563+
"SWIFT_VERSION": "5.5",
564+
"GENERATE_INFOPLIST_FILE": "YES",
565+
"ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS": "NO",
566+
// Disable phase fusion so Sources and Resources have separate gate
567+
// tasks, allowing us to verify the xcassets file stays in Resources.
568+
"FUSE_BUILD_PHASES": "NO",
569+
]),
570+
],
571+
buildPhases: [
572+
TestSourcesBuildPhase([
573+
"App.swift",
574+
]),
575+
TestResourcesBuildPhase([
576+
"Assets.xcassets",
577+
]),
578+
]
579+
)
580+
]
581+
)
582+
583+
let tester = try await TaskConstructionTester(getCore(), testProject)
584+
585+
await tester.checkBuild(runDestination: .macOS) { results in
586+
results.checkNoDiagnostics()
587+
588+
results.checkTarget("App") { target in
589+
results.checkNoTask(.matchTarget(target), .matchRuleType("GenerateAssetSymbols"))
590+
591+
// The asset catalog must stay in the Resources phase when symbol generation is
592+
// disabled. Verify by checking that asset catalog compilation follows Swift
593+
// compilation through the phase gate (Resources runs after Sources).
594+
let targetArchitecture = results.runDestinationTargetArchitecture
595+
let swiftRuleType = swiftFeatures.has(.emitLocalizedStrings) ? "SwiftDriver Compilation" : "CompileSwiftSources"
596+
results.checkTask(.matchTarget(target), .matchRuleType("CompileAssetCatalogVariant"), .matchRuleItem("thinned")) { compileAssetCatalogTask in
597+
results.checkTaskFollows(compileAssetCatalogTask, .matchTarget(target), .matchRuleType(swiftRuleType), .matchRuleItem("normal"), .matchRuleItem(targetArchitecture))
598+
}
599+
}
600+
}
601+
}
531602
}

Tests/SWBTaskConstructionTests/XCStringsSymbolGenTests.swift

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,4 +1070,95 @@ fileprivate struct XCStringsSymbolGenTests: CoreBasedTests {
10701070
}
10711071
}
10721072

1073+
/// When string catalog symbol generation is disabled, the xcstrings file must stay in the Resources
1074+
/// phase and not be moved to Sources.
1075+
@Test(.requireSDKs(.macOS))
1076+
func disabledSymbolGeneration() async throws {
1077+
let swiftFeatures = try await self.swiftFeatures
1078+
1079+
let testProject = try await TestProject(
1080+
"Project",
1081+
groupTree: TestGroup(
1082+
"ProjectSources",
1083+
path: "Sources",
1084+
children: [
1085+
TestFile("MyFramework.swift"),
1086+
TestFile("Localizable.xcstrings"),
1087+
]
1088+
),
1089+
buildConfigurations: [
1090+
TestBuildConfiguration("Debug", buildSettings: [
1091+
"PRODUCT_NAME": "$(TARGET_NAME)",
1092+
])
1093+
],
1094+
targets: [
1095+
TestStandardTarget(
1096+
"MyFramework",
1097+
type: .framework,
1098+
buildConfigurations: [
1099+
TestBuildConfiguration("Debug", buildSettings: [
1100+
"SKIP_INSTALL": "YES",
1101+
"SWIFT_EXEC": swiftCompilerPath.str,
1102+
"SWIFT_VERSION": "5.5",
1103+
"GENERATE_INFOPLIST_FILE": "YES",
1104+
"STRING_CATALOG_GENERATE_SYMBOLS": "NO",
1105+
// Disable phase fusion so Sources and Resources have separate gate
1106+
// tasks, allowing us to verify the xcstrings file stays in Resources.
1107+
"FUSE_BUILD_PHASES": "NO",
1108+
]),
1109+
],
1110+
buildPhases: [
1111+
TestSourcesBuildPhase([
1112+
"MyFramework.swift"
1113+
]),
1114+
TestResourcesBuildPhase([
1115+
"Localizable.xcstrings"
1116+
])
1117+
]
1118+
)
1119+
],
1120+
developmentRegion: "en"
1121+
)
1122+
1123+
let core = try await getCore()
1124+
let xcstringsTool = MockXCStringsTool(relativeOutputFilePaths: [ "/tmp/Test/Project/Sources/Localizable.xcstrings" : [
1125+
"en.lproj/Localizable.strings",
1126+
"en.lproj/Localizable.stringsdict",
1127+
"de.lproj/Localizable.strings",
1128+
"de.lproj/Localizable.stringsdict",
1129+
]], requiredCommandLine: [
1130+
"xcstringstool", "compile",
1131+
"--dry-run",
1132+
"--output-directory", "/tmp/Test/Project/build/Project.build/Debug/MyFramework.build",
1133+
"/tmp/Test/Project/Sources/Localizable.xcstrings"
1134+
])
1135+
1136+
let tester = try TaskConstructionTester(core, testProject)
1137+
1138+
await tester.checkBuild(runDestination: .macOS, clientDelegate: xcstringsTool) { results in
1139+
results.checkNoDiagnostics()
1140+
1141+
results.checkTarget("MyFramework") { target in
1142+
results.checkNoTask(.matchTarget(target), .matchRuleType("GenerateStringSymbols"))
1143+
results.checkNoTask(.matchTarget(target), .matchRuleType("CpResource"))
1144+
1145+
results.checkTask(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/Project/build/Debug/MyFramework.framework/Versions/A/Resources/en.lproj/Localizable.strings", "/tmp/Test/Project/build/Project.build/Debug/MyFramework.build/en.lproj/Localizable.strings"])) { _ in }
1146+
results.checkTask(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/Project/build/Debug/MyFramework.framework/Versions/A/Resources/en.lproj/Localizable.stringsdict", "/tmp/Test/Project/build/Project.build/Debug/MyFramework.build/en.lproj/Localizable.stringsdict"])) { _ in }
1147+
results.checkTask(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/Project/build/Debug/MyFramework.framework/Versions/A/Resources/de.lproj/Localizable.strings", "/tmp/Test/Project/build/Project.build/Debug/MyFramework.build/de.lproj/Localizable.strings"])) { _ in }
1148+
results.checkTask(.matchTarget(target), .matchRule(["CopyStringsFile", "/tmp/Test/Project/build/Debug/MyFramework.framework/Versions/A/Resources/de.lproj/Localizable.stringsdict", "/tmp/Test/Project/build/Project.build/Debug/MyFramework.build/de.lproj/Localizable.stringsdict"])) { _ in }
1149+
1150+
results.checkNoTask(.matchTarget(target), .matchRuleType("CopyStringsFile"))
1151+
1152+
// The xcstrings file must stay in the Resources phase when symbol generation is
1153+
// disabled. Verify by checking that xcstrings compilation follows Swift compilation
1154+
// through the phase gate (Resources runs after Sources).
1155+
let targetArchitecture = results.runDestinationTargetArchitecture
1156+
let swiftRuleType = swiftFeatures.has(.emitLocalizedStrings) ? "SwiftDriver Compilation" : "CompileSwiftSources"
1157+
results.checkTask(.matchTarget(target), .matchRuleType("CompileXCStrings")) { compileXCStringsTask in
1158+
results.checkTaskFollows(compileXCStringsTask, .matchTarget(target), .matchRuleType(swiftRuleType), .matchRuleItem("normal"), .matchRuleItem(targetArchitecture))
1159+
}
1160+
}
1161+
}
1162+
}
1163+
10731164
}

0 commit comments

Comments
 (0)