Fixes for Xcode 10's new build system
- Create a Run Script phase to write out dummy files for Objective-C sources
in test targets. This silences some Xcode 10 warnings about .d files not
being present, as well as issues with <target>_dependency_info.dat files.
- Add the Xcode processed Info.plist file as an input to the bazel_build.py
script to ensure it is processed before our script. This allows our script
to safely overwrite it.
PiperOrigin-RevId: 213950894
diff --git a/src/TulsiGenerator/PBXTargetGenerator.swift b/src/TulsiGenerator/PBXTargetGenerator.swift
index 092d4ac..4bf101d 100644
--- a/src/TulsiGenerator/PBXTargetGenerator.swift
+++ b/src/TulsiGenerator/PBXTargetGenerator.swift
@@ -1162,6 +1162,11 @@
target.buildPhases.append(testBuildPhase)
}
if !testSourceFileInfos.isEmpty || !testNonArcSourceFileInfos.isEmpty {
+ if !containsSwift {
+ let allSources = testSourceFileInfos + testNonArcSourceFileInfos
+ let testBuildPhase = createGenerateDummyDependencyFilesTestBuildPhase(allSources)
+ target.buildPhases.append(testBuildPhase)
+ }
var fileReferences = generateFileReferencesForFileInfos(testSourceFileInfos)
let (nonARCFiles, nonARCSettings) =
generateFileReferencesAndSettingsForNonARCFileInfos(testNonArcSourceFileInfos)
@@ -1584,6 +1589,30 @@
return buildPhase
}
+ private func createGenerateDummyDependencyFilesTestBuildPhase(_ sources: [BazelFileInfo]) -> PBXShellScriptBuildPhase {
+ let files = sources.map { ($0.subPath as NSString).deletingPathExtension.pbPathLastComponent }
+ let shellScript = """
+# Script to generate dependency files Xcode expects when running tests.
+set -eu
+ARCH_ARRAY=($ARCHS)
+FILES=(\(files.map { $0.escapingForShell }.joined(separator: " ")))
+for ARCH in "${ARCH_ARRAY[@]}"
+do
+ mkdir -p "$OBJECT_FILE_DIR_normal/$ARCH/"
+ rm -f "$OBJECT_FILE_DIR_normal/$ARCH/${PRODUCT_NAME}_dependency_info.dat"
+ printf '\\x00\\x31\\x00' >"$OBJECT_FILE_DIR_normal/$ARCH/${PRODUCT_NAME}_dependency_info.dat"
+ for FILE in "${FILES[@]}"
+ do
+ touch "$OBJECT_FILE_DIR_normal/$ARCH/$FILE.d"
+ done
+done
+"""
+ let buildPhase = PBXShellScriptBuildPhase(shellScript: shellScript, shellPath: "/bin/bash")
+ buildPhase.showEnvVarsInLog = true
+ buildPhase.mnemonic = "ObjcDummy"
+ return buildPhase
+ }
+
private func createBuildPhaseForRuleEntry(_ entry: RuleEntry)
-> PBXShellScriptBuildPhase? {
let buildLabel = entry.label.value
@@ -1599,7 +1628,14 @@
"\(changeDirectoryAction)\n" +
"exec \(commandLine)"
- let buildPhase = PBXShellScriptBuildPhase(shellScript: shellScript, shellPath: "/bin/bash")
+ // Using the Info.plist as an input forces Xcode to run this after processing the Info.plist,
+ // allowing our script to safely overwrite the Info.plist after Xcode does its processing.
+ let inputPaths = ["$(TARGET_BUILD_DIR)/$(INFOPLIST_PATH)"]
+ let buildPhase = PBXShellScriptBuildPhase(
+ shellScript: shellScript,
+ shellPath: "/bin/bash",
+ inputPaths: inputPaths
+ )
buildPhase.showEnvVarsInLog = true
buildPhase.mnemonic = "BazelBuild"
return buildPhase
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index f5c8323..3785341 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -559,7 +559,6 @@
let workspaceSharedDataURL = projectURL.appendingPathComponent("project.xcworkspace/xcshareddata")
let sharedWorkspaceSettings: [String: Any] = [
- "BuildSystemType": "Original",
"IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded": false as AnyObject,
]
try writeWorkspaceSettings(sharedWorkspaceSettings,
diff --git a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
index c6eeec0..58f0679 100644
--- a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
@@ -995,6 +995,7 @@
expectedBuildPhases: [
BazelShellScriptBuildPhaseDefinition(bazelPath: bazelPath, buildTarget: rule1BuildTarget),
SourcesBuildPhaseDefinition(files: testSources, mainGroup: project.mainGroup),
+ ObjcDummyShellScriptBuildPhaseDefinition(),
]
)
assertTarget(expectedTarget, inTargets: targets)
@@ -1113,7 +1114,8 @@
expectedBuildPhases: [
SourcesBuildPhaseDefinition(files: testSources, mainGroup: project.mainGroup),
BazelShellScriptBuildPhaseDefinition(bazelPath: bazelPath,
- buildTarget: testRuleBuildTarget)
+ buildTarget: testRuleBuildTarget),
+ ObjcDummyShellScriptBuildPhaseDefinition(),
]
)
assertTarget(expectedTarget, inTargets: targets)
@@ -1200,7 +1202,8 @@
expectedBuildPhases: [
SourcesBuildPhaseDefinition(files: testSources, mainGroup: project.mainGroup),
BazelShellScriptBuildPhaseDefinition(bazelPath: bazelPath,
- buildTarget: "\(testRulePackage):\(testRuleTargetName)")
+ buildTarget: "\(testRulePackage):\(testRuleTargetName)"),
+ ObjcDummyShellScriptBuildPhaseDefinition(),
]
)
assertTarget(expectedTarget, inTargets: targets)
@@ -1408,7 +1411,8 @@
expectedBuildPhases: [
SourcesBuildPhaseDefinition(files: testSources, mainGroup: project.mainGroup),
BazelShellScriptBuildPhaseDefinition(bazelPath: bazelPath,
- buildTarget: testRuleBuildTarget)
+ buildTarget: testRuleBuildTarget),
+ ObjcDummyShellScriptBuildPhaseDefinition(),
]
)
assertTarget(expectedTarget, inTargets: targets)
@@ -2850,6 +2854,24 @@
}
}
+ private class ObjcDummyShellScriptBuildPhaseDefinition: BuildPhaseDefinition {
+ init() {
+ super.init(isa: "PBXShellScriptBuildPhase", files: [], mnemonic: "ObjcDummy")
+ }
+
+ override func validate(_ phase: PBXBuildPhase, line: UInt = #line) {
+ super.validate(phase, line: line)
+
+ // Guaranteed by the test infrastructure below, failing this indicates a programming error in
+ // the test fixture, not in the code being tested.
+ let scriptBuildPhase = phase as! PBXShellScriptBuildPhase
+
+ let script = scriptBuildPhase.shellScript
+ XCTAssert(script.contains("touch"), "Build script does not contain 'touch'.",
+ line: line)
+ }
+ }
+
private func fileRefForPath(_ path: String) -> PBXReference? {
let components = path.components(separatedBy: "/")
var node = project.mainGroup