Skip to content

Commit f4a8141

Browse files
authored
Merge pull request #982 from owenv/owenv/case
Ensure TARGET_TEMP_DIR values do not collide when package PIF targets differ only in case
2 parents 26a91ef + 4d145f2 commit f4a8141

File tree

4 files changed

+78
-2
lines changed

4 files changed

+78
-2
lines changed

Sources/SWBCore/Settings/BuiltinMacros.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ public final class BuiltinMacros {
220220
public static let TARGET_BUILD_DIR = BuiltinMacros.declarePathMacro("TARGET_BUILD_DIR")
221221
public static let TARGET_BUILD_SUBPATH = BuiltinMacros.declarePathMacro("TARGET_BUILD_SUBPATH")
222222
public static let TARGET_NAME = BuiltinMacros.declareStringMacro("TARGET_NAME")
223+
public static let TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR = BuiltinMacros.declareStringMacro("TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR")
223224
public static let TARGET_TEMP_DIR = BuiltinMacros.declarePathMacro("TARGET_TEMP_DIR")
224225
// FIXME: This macro should be deprecated.
225226
public static let TARGETNAME = BuiltinMacros.declareStringMacro("TARGETNAME")
@@ -2376,6 +2377,7 @@ public final class BuiltinMacros {
23762377
TARGET_DEVICE_OS_VERSION,
23772378
TARGET_DEVICE_PLATFORM_NAME,
23782379
TARGET_NAME,
2380+
TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR,
23792381
TARGET_TEMP_DIR,
23802382
TEMP_DIR,
23812383
TEMP_FILES_DIR,

Sources/SWBCore/Settings/Settings.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2953,14 +2953,26 @@ private class SettingsBuilder: ProjectMatchLookup {
29532953
table.push(BuiltinMacros.PROJECT_DIR, literal: project.sourceRoot.str)
29542954
table.push(BuiltinMacros.PROJECT_TEMP_DIR, Static { BuiltinMacros.namespace.parseString("$(OBJROOT)/$(PROJECT_NAME).build") })
29552955

2956+
do {
2957+
// A fair number of Swift packages have products/targets which only differ in case. In order to avoid collisions
2958+
// of build intermediates on case-insensitive file systems, add a discriminant if we detect this.
2959+
var seenTargetNames: Set<String> = []
2960+
for target in project.targets {
2961+
if !seenTargetNames.insert(target.name.lowercased()).inserted {
2962+
table.push(BuiltinMacros.TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR, Static { BuiltinMacros.namespace.parseString("$(TARGET_NAME:__md5)") })
2963+
break
2964+
}
2965+
}
2966+
}
2967+
29562968
if usePerConfigurationBuildLocations {
29572969
table.push(BuiltinMacros.CONFIGURATION_BUILD_DIR, Static { BuiltinMacros.namespace.parseString("$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)") })
29582970
table.push(BuiltinMacros.CONFIGURATION_TEMP_DIR, Static { BuiltinMacros.namespace.parseString("$(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)") })
29592971
} else {
29602972
table.push(BuiltinMacros.CONFIGURATION_BUILD_DIR, Static { BuiltinMacros.namespace.parseString("$(BUILD_DIR)") })
29612973
table.push(BuiltinMacros.CONFIGURATION_TEMP_DIR, Static { BuiltinMacros.namespace.parseString("$(PROJECT_TEMP_DIR)") })
29622974
}
2963-
table.push(BuiltinMacros.TARGET_TEMP_DIR, Static { BuiltinMacros.namespace.parseString("$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME).build") })
2975+
table.push(BuiltinMacros.TARGET_TEMP_DIR, Static { BuiltinMacros.namespace.parseString("$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME)$(TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR).build") })
29642976
table.push(BuiltinMacros.TARGET_BUILD_DIR, Static { BuiltinMacros.namespace.parseString("$(CONFIGURATION_BUILD_DIR)$(TARGET_BUILD_SUBPATH)") })
29652977
table.push(BuiltinMacros.BUILT_PRODUCTS_DIR, Static { BuiltinMacros.namespace.parseString("$(CONFIGURATION_BUILD_DIR)") })
29662978
table.push(BuiltinMacros.DEVELOPMENT_LANGUAGE, literal: project.developmentRegion ?? "en")

Sources/SWBCore/Specs/CoreBuildSystem.xcspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2987,7 +2987,7 @@ For more information on mergeable libraries, see [Configuring your project to us
29872987
{
29882988
Name = "TARGET_TEMP_DIR";
29892989
Type = Path;
2990-
DefaultValue = "$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME).build";
2990+
DefaultValue = "$(CONFIGURATION_TEMP_DIR)/$(TARGET_NAME)$(TARGET_NAME_CASE_SENSITIVITY_DISCRIMINATOR).build";
29912991
Description = "Identifies the directory containing the target’s intermediate build files. Run Script build phases should place intermediate files at the location indicated by `DERIVED_FILE_DIR`, not the directory identified by this build setting.";
29922992
},
29932993
{

Tests/SWBBuildSystemTests/PackageBuildOperationTests.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,68 @@ fileprivate struct PackageBuildOperationTests: CoreBasedTests {
470470
}
471471
}
472472

473+
// Regression test which ensures we can build successfully when a project has two targets whose
474+
// names only differ in case. Previously this would fail because the intermediate TARGET_TEMP_DIRs would
475+
// collide.
476+
@Test(.requireSDKs(.host))
477+
func packageCaseInsensitiveCollisions() async throws {
478+
try await withTemporaryDirectory { tmpDir in
479+
let testWorkspace = try await TestWorkspace(
480+
"Test",
481+
sourceRoot: tmpDir.join("Test"),
482+
projects: [
483+
TestProject(
484+
"aProject",
485+
groupTree: TestGroup(
486+
"Sources",
487+
children: [
488+
TestFile("file_1.swift"),
489+
TestFile("file_2.swift"),
490+
]),
491+
buildConfigurations: [TestBuildConfiguration(
492+
"Debug",
493+
buildSettings: [
494+
"PRODUCT_NAME": "$(TARGET_NAME)",
495+
"SWIFT_VERSION": swiftVersion,
496+
"DSTROOT": tmpDir.join("dstroot").str,
497+
])],
498+
targets: [
499+
TestStandardTarget(
500+
"Library",
501+
type: .staticLibrary,
502+
buildPhases: [
503+
TestSourcesBuildPhase(["file_1.swift"]),
504+
], dependencies: ["library"]),
505+
TestStandardTarget(
506+
"library",
507+
type: .staticLibrary,
508+
buildPhases: [
509+
TestSourcesBuildPhase(["file_2.swift"]),
510+
]),
511+
])])
512+
513+
let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false)
514+
515+
try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("aProject/file_1.swift")) { stream in
516+
stream <<<
517+
"""
518+
public let x = 42
519+
"""
520+
}
521+
522+
try await tester.fs.writeFileContents(testWorkspace.sourceRoot.join("aProject/file_2.swift")) { stream in
523+
stream <<<
524+
"""
525+
public let y = 10
526+
"""
527+
}
528+
529+
try await tester.checkBuild(runDestination: .host) { results in
530+
results.checkNoDiagnostics()
531+
}
532+
}
533+
}
534+
473535
@Test(.requireSDKs(.macOS))
474536
func packageModuleAliasing() async throws {
475537
try await withTemporaryDirectory { tmpDirPath async throws -> Void in

0 commit comments

Comments
 (0)