From bc2ce145f0e5dd9630b5f8369853a3ad90ca6adb Mon Sep 17 00:00:00 2001 From: Adin Cebic Date: Fri, 17 Apr 2026 19:22:37 +0200 Subject: [PATCH] project-relative lldbinit Signed-off-by: Adin Cebic --- .../lib/XCScheme/src/BuildableReference.swift | 2 +- .../lib/XCScheme/src/CreateLaunchAction.swift | 10 + .../XCScheme/src/CreateProfileAction.swift | 10 + .../lib/XCScheme/src/CreateTestAction.swift | 10 + .../test/CreateLaunchActionTests.swift | 29 ++ .../test/CreateProfileActionTests.swift | 25 ++ .../XCScheme/test/CreateTestActionTests.swift | 26 ++ tools/generators/pbxproj_prefix/README.md | 4 +- .../Generator/PBXProjectBuildSettings.swift | 2 +- .../test/PBXProjectBuildSettingsTests.swift | 6 +- tools/generators/xcschemes/README.md | 3 + .../src/Generator/CreateScheme.swift | 38 +++ .../xcschemes/test/CreateSchemeTests.swift | 262 ++++++++++++++++++ .../create_lldbinit.sh | 18 -- 14 files changed, 420 insertions(+), 25 deletions(-) create mode 100644 tools/generators/xcschemes/test/CreateSchemeTests.swift diff --git a/tools/generators/lib/XCScheme/src/BuildableReference.swift b/tools/generators/lib/XCScheme/src/BuildableReference.swift index 82bc8e16de..752f6ca966 100644 --- a/tools/generators/lib/XCScheme/src/BuildableReference.swift +++ b/tools/generators/lib/XCScheme/src/BuildableReference.swift @@ -2,7 +2,7 @@ public struct BuildableReference: Equatable, Hashable { public let blueprintIdentifier: String let buildableName: String public let blueprintName: String - let referencedContainer: String + public let referencedContainer: String public init( blueprintIdentifier: String, diff --git a/tools/generators/lib/XCScheme/src/CreateLaunchAction.swift b/tools/generators/lib/XCScheme/src/CreateLaunchAction.swift index 28ef7f7982..2e251c0d5f 100644 --- a/tools/generators/lib/XCScheme/src/CreateLaunchAction.swift +++ b/tools/generators/lib/XCScheme/src/CreateLaunchAction.swift @@ -12,6 +12,7 @@ public struct CreateLaunchAction { public func callAsFunction( buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, customWorkingDirectory: String?, enableAddressSanitizer: Bool, enableThreadSanitizer: Bool, @@ -27,6 +28,7 @@ public struct CreateLaunchAction { return callable( /*buildConfiguration:*/ buildConfiguration, /*commandLineArguments:*/ commandLineArguments, + /*customLLDBInitFile:*/ customLLDBInitFile, /*customWorkingDirectory:*/ customWorkingDirectory, /*enableAddressSanitizer:*/ enableAddressSanitizer, /*enableThreadSanitizer:*/ enableThreadSanitizer, @@ -48,6 +50,7 @@ extension CreateLaunchAction { public typealias Callable = ( _ buildConfiguration: String, _ commandLineArguments: [CommandLineArgument], + _ customLLDBInitFile: String?, _ customWorkingDirectory: String?, _ enableAddressSanitizer: Bool, _ enableThreadSanitizer: Bool, @@ -64,6 +67,7 @@ extension CreateLaunchAction { public static func defaultCallable( buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, customWorkingDirectory: String?, enableAddressSanitizer: Bool, enableThreadSanitizer: Bool, @@ -100,6 +104,12 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" ) } + if let customLLDBInitFile { + components.append( + #"customLLDBInitFile = "\#(customLLDBInitFile)""# + ) + } + if enableAddressSanitizer { components.append(#"enableAddressSanitizer = "YES""#) } diff --git a/tools/generators/lib/XCScheme/src/CreateProfileAction.swift b/tools/generators/lib/XCScheme/src/CreateProfileAction.swift index 179eaccd1b..b85bc7c1c5 100644 --- a/tools/generators/lib/XCScheme/src/CreateProfileAction.swift +++ b/tools/generators/lib/XCScheme/src/CreateProfileAction.swift @@ -12,6 +12,7 @@ public struct CreateProfileAction { public func callAsFunction( buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, customWorkingDirectory: String?, environmentVariables: [EnvironmentVariable], postActions: [ExecutionAction], @@ -22,6 +23,7 @@ public struct CreateProfileAction { return callable( /*buildConfiguration:*/ buildConfiguration, /*commandLineArguments:*/ commandLineArguments, + /*customLLDBInitFile:*/ customLLDBInitFile, /*customWorkingDirectory:*/ customWorkingDirectory, /*environmentVariables:*/ environmentVariables, /*postActions:*/ postActions, @@ -38,6 +40,7 @@ extension CreateProfileAction { public typealias Callable = ( _ buildConfiguration: String, _ commandLineArguments: [CommandLineArgument], + _ customLLDBInitFile: String?, _ customWorkingDirectory: String?, _ environmentVariables: [EnvironmentVariable], _ postActions: [ExecutionAction], @@ -49,6 +52,7 @@ extension CreateProfileAction { public static func defaultCallable( buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, customWorkingDirectory: String?, environmentVariables: [EnvironmentVariable], postActions: [ExecutionAction], @@ -66,6 +70,12 @@ buildConfiguration = "\#(buildConfiguration)" """#, ] + if let customLLDBInitFile { + components.append( + #"customLLDBInitFile = "\#(customLLDBInitFile)""# + ) + } + if let customWorkingDirectory { components.append( #""" diff --git a/tools/generators/lib/XCScheme/src/CreateTestAction.swift b/tools/generators/lib/XCScheme/src/CreateTestAction.swift index ddd6b53415..53bdb2b329 100644 --- a/tools/generators/lib/XCScheme/src/CreateTestAction.swift +++ b/tools/generators/lib/XCScheme/src/CreateTestAction.swift @@ -15,6 +15,7 @@ public struct CreateTestAction { codeCoverage: Bool, buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, enableAddressSanitizer: Bool, enableThreadSanitizer: Bool, enableUBSanitizer: Bool, @@ -33,6 +34,7 @@ public struct CreateTestAction { /*codeCoverage:*/ codeCoverage, /*buildConfiguration:*/ buildConfiguration, /*commandLineArguments:*/ commandLineArguments, + /*customLLDBInitFile:*/ customLLDBInitFile, /*enableAddressSanitizer:*/ enableAddressSanitizer, /*enableThreadSanitizer:*/ enableThreadSanitizer, /*enableUBSanitizer:*/ enableUBSanitizer, @@ -57,6 +59,7 @@ extension CreateTestAction { _ codeCoverage: Bool, _ buildConfiguration: String, _ commandLineArguments: [CommandLineArgument], + _ customLLDBInitFile: String?, _ enableAddressSanitizer: Bool, _ enableThreadSanitizer: Bool, _ enableUBSanitizer: Bool, @@ -76,6 +79,7 @@ extension CreateTestAction { codeCoverage: Bool, buildConfiguration: String, commandLineArguments: [CommandLineArgument], + customLLDBInitFile: String?, enableAddressSanitizer: Bool, enableThreadSanitizer: Bool, enableUBSanitizer: Bool, @@ -99,6 +103,12 @@ buildConfiguration = "\#(buildConfiguration)" """#, ] + if let customLLDBInitFile { + components.append( + #"customLLDBInitFile = "\#(customLLDBInitFile)""# + ) + } + if enableAddressSanitizer { components.append(#"enableAddressSanitizer = "YES""#) } diff --git a/tools/generators/lib/XCScheme/test/CreateLaunchActionTests.swift b/tools/generators/lib/XCScheme/test/CreateLaunchActionTests.swift index a9082f70a3..7fa61c857c 100644 --- a/tools/generators/lib/XCScheme/test/CreateLaunchActionTests.swift +++ b/tools/generators/lib/XCScheme/test/CreateLaunchActionTests.swift @@ -131,6 +131,33 @@ final class CreateLaunchActionTests: XCTestCase { XCTAssertNoDifference(action, expectedAction) } + func test_customLLDBInitFile() { + let buildConfiguration = "Release" + let customLLDBInitFile = "$(SRCROOT)/.lldbinit-rules_xcodeproj" + + let expectedAction = #""" + + +"""# + + let action = createLaunchActionWithDefaults( + buildConfiguration: buildConfiguration, + customLLDBInitFile: customLLDBInitFile + ) + + XCTAssertNoDifference(action, expectedAction) + } + func test_disableMainThreadChecker() { // Arrange @@ -585,6 +612,7 @@ final class CreateLaunchActionTests: XCTestCase { private func createLaunchActionWithDefaults( buildConfiguration: String, commandLineArguments: [CommandLineArgument] = [], + customLLDBInitFile: String? = nil, customWorkingDirectory: String? = nil, enableAddressSanitizer: Bool = false, enableThreadSanitizer: Bool = false, @@ -600,6 +628,7 @@ private func createLaunchActionWithDefaults( return CreateLaunchAction.defaultCallable( buildConfiguration: buildConfiguration, commandLineArguments: commandLineArguments, + customLLDBInitFile: customLLDBInitFile, customWorkingDirectory: customWorkingDirectory, enableAddressSanitizer: enableAddressSanitizer, enableThreadSanitizer: enableThreadSanitizer, diff --git a/tools/generators/lib/XCScheme/test/CreateProfileActionTests.swift b/tools/generators/lib/XCScheme/test/CreateProfileActionTests.swift index 7bb1208369..c063ce05b5 100644 --- a/tools/generators/lib/XCScheme/test/CreateProfileActionTests.swift +++ b/tools/generators/lib/XCScheme/test/CreateProfileActionTests.swift @@ -104,6 +104,29 @@ final class CreateProfileActionTests: XCTestCase { XCTAssertNoDifference(prefix, expectedPrefix) } + func test_customLLDBInitFile() { + let buildConfiguration = "Profile" + let customLLDBInitFile = "$(SRCROOT)/.lldbinit-rules_xcodeproj" + + let expectedPrefix = #""" + + +"""# + + let prefix = createProfileActionWithDefaults( + buildConfiguration: buildConfiguration, + customLLDBInitFile: customLLDBInitFile + ) + + XCTAssertNoDifference(prefix, expectedPrefix) + } + func test_environmentVariables() { // Arrange @@ -379,6 +402,7 @@ final class CreateProfileActionTests: XCTestCase { private func createProfileActionWithDefaults( buildConfiguration: String, commandLineArguments: [CommandLineArgument] = [], + customLLDBInitFile: String? = nil, customWorkingDirectory: String? = nil, environmentVariables: [EnvironmentVariable] = [], postActions: [ExecutionAction] = [], @@ -389,6 +413,7 @@ private func createProfileActionWithDefaults( return CreateProfileAction.defaultCallable( buildConfiguration: buildConfiguration, commandLineArguments: commandLineArguments, + customLLDBInitFile: customLLDBInitFile, customWorkingDirectory: customWorkingDirectory, environmentVariables: environmentVariables, postActions: postActions, diff --git a/tools/generators/lib/XCScheme/test/CreateTestActionTests.swift b/tools/generators/lib/XCScheme/test/CreateTestActionTests.swift index 1ee20ed9e7..31387d27ad 100644 --- a/tools/generators/lib/XCScheme/test/CreateTestActionTests.swift +++ b/tools/generators/lib/XCScheme/test/CreateTestActionTests.swift @@ -77,6 +77,30 @@ final class CreateTestActionTests: XCTestCase { XCTAssertNoDifference(action, expectedAction) } + func test_customLLDBInitFile() { + let buildConfiguration = "Debug" + let customLLDBInitFile = "$(SRCROOT)/.lldbinit-rules_xcodeproj" + + let expectedAction = #""" + + + + +"""# + + let action = createTestActionWithDefaults( + buildConfiguration: buildConfiguration, + customLLDBInitFile: customLLDBInitFile + ) + + XCTAssertNoDifference(action, expectedAction) + } + func test_disableMainThreadChecker() { // Arrange @@ -458,6 +482,7 @@ private func createTestActionWithDefaults( codeCoverage: Bool = false, buildConfiguration: String, commandLineArguments: [CommandLineArgument] = [], + customLLDBInitFile: String? = nil, enableAddressSanitizer: Bool = false, enableThreadSanitizer: Bool = false, enableUBSanitizer: Bool = false, @@ -476,6 +501,7 @@ private func createTestActionWithDefaults( codeCoverage: codeCoverage, buildConfiguration: buildConfiguration, commandLineArguments: commandLineArguments, + customLLDBInitFile: customLLDBInitFile, enableAddressSanitizer: enableAddressSanitizer, enableThreadSanitizer: enableThreadSanitizer, enableUBSanitizer: enableUBSanitizer, diff --git a/tools/generators/pbxproj_prefix/README.md b/tools/generators/pbxproj_prefix/README.md index 4c2d08f8eb..f0c640cace 100644 --- a/tools/generators/pbxproj_prefix/README.md +++ b/tools/generators/pbxproj_prefix/README.md @@ -195,7 +195,7 @@ Here is an example output: BAZEL_CONFIG = rules_xcodeproj; BAZEL_EXTERNAL = "$(BAZEL_OUTPUT_BASE)/external"; BAZEL_INTEGRATION_DIR = "$(INTERNAL_DIR)/bazel"; - BAZEL_LLDB_INIT = "$(HOME)/.lldbinit-rules_xcodeproj"; + BAZEL_LLDB_INIT = "$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit"; BAZEL_OUT = "$(PROJECT_DIR)/bazel-out"; BAZEL_OUTPUT_BASE = "$(_BAZEL_OUTPUT_BASE:standardizepath)"; BAZEL_WORKSPACE_ROOT = "$(SRCROOT)"; @@ -258,7 +258,7 @@ Here is an example output: BAZEL_CONFIG = rules_xcodeproj; BAZEL_EXTERNAL = "$(BAZEL_OUTPUT_BASE)/external"; BAZEL_INTEGRATION_DIR = "$(INTERNAL_DIR)/bazel"; - BAZEL_LLDB_INIT = "$(HOME)/.lldbinit-rules_xcodeproj"; + BAZEL_LLDB_INIT = "$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit"; BAZEL_OUT = "$(PROJECT_DIR)/bazel-out"; BAZEL_OUTPUT_BASE = "$(_BAZEL_OUTPUT_BASE:standardizepath)"; BAZEL_WORKSPACE_ROOT = "$(SRCROOT)"; diff --git a/tools/generators/pbxproj_prefix/src/Generator/PBXProjectBuildSettings.swift b/tools/generators/pbxproj_prefix/src/Generator/PBXProjectBuildSettings.swift index de6dc22efe..a1dde0136c 100644 --- a/tools/generators/pbxproj_prefix/src/Generator/PBXProjectBuildSettings.swift +++ b/tools/generators/pbxproj_prefix/src/Generator/PBXProjectBuildSettings.swift @@ -49,7 +49,7 @@ extension Generator { ), .init( key: "BAZEL_LLDB_INIT", - value: #""$(HOME)/.lldbinit-rules_xcodeproj""# + value: #""$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit""# ), .init( key: "BAZEL_OUT", diff --git a/tools/generators/pbxproj_prefix/test/PBXProjectBuildSettingsTests.swift b/tools/generators/pbxproj_prefix/test/PBXProjectBuildSettingsTests.swift index d02c3c64a6..c7ed5f8f8c 100644 --- a/tools/generators/pbxproj_prefix/test/PBXProjectBuildSettingsTests.swift +++ b/tools/generators/pbxproj_prefix/test/PBXProjectBuildSettingsTests.swift @@ -26,7 +26,7 @@ class PBXProjectBuildSettingsTests: XCTestCase { BAZEL_CONFIG = rxcp_custom_config; BAZEL_EXTERNAL = "$(BAZEL_OUTPUT_BASE)/external"; BAZEL_INTEGRATION_DIR = "$(INTERNAL_DIR)/bazel"; - BAZEL_LLDB_INIT = "$(HOME)/.lldbinit-rules_xcodeproj"; + BAZEL_LLDB_INIT = "$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit"; BAZEL_OUT = "$(PROJECT_DIR)/bazel-out"; BAZEL_OUTPUT_BASE = "$(_BAZEL_OUTPUT_BASE:standardizepath)"; BAZEL_WORKSPACE_ROOT = "$(SRCROOT)"; @@ -121,7 +121,7 @@ class PBXProjectBuildSettingsTests: XCTestCase { BAZEL_CONFIG = rxcp_custom_config; BAZEL_EXTERNAL = "$(BAZEL_OUTPUT_BASE)/external"; BAZEL_INTEGRATION_DIR = "$(INTERNAL_DIR)/bazel"; - BAZEL_LLDB_INIT = "$(HOME)/.lldbinit-rules_xcodeproj"; + BAZEL_LLDB_INIT = "$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit"; BAZEL_OUT = "$(PROJECT_DIR)/bazel-out"; BAZEL_OUTPUT_BASE = "$(_BAZEL_OUTPUT_BASE:standardizepath)"; BAZEL_SUPPRESS_COVERAGE_BUILD = YES; @@ -215,7 +215,7 @@ class PBXProjectBuildSettingsTests: XCTestCase { BAZEL_CONFIG = rxcp_custom_config; BAZEL_EXTERNAL = "$(BAZEL_OUTPUT_BASE)/external"; BAZEL_INTEGRATION_DIR = "$(INTERNAL_DIR)/bazel"; - BAZEL_LLDB_INIT = "$(HOME)/.lldbinit-rules_xcodeproj"; + BAZEL_LLDB_INIT = "$(PROJECT_FILE_PATH)/rules_xcodeproj/bazel.lldbinit"; BAZEL_OUT = "$(PROJECT_DIR)/bazel-out"; BAZEL_OUTPUT_BASE = "$(_BAZEL_OUTPUT_BASE:standardizepath)"; BAZEL_SEPARATE_INDEXBUILD_OUTPUT_BASE = YES; diff --git a/tools/generators/xcschemes/README.md b/tools/generators/xcschemes/README.md index 75ec1871d9..04b327fbd6 100644 --- a/tools/generators/xcschemes/README.md +++ b/tools/generators/xcschemes/README.md @@ -155,6 +155,7 @@ Here is an example output: selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES" + customLLDBInitFile = "/Users/brentley/Developer/rules_xcodeproj/tools/tools.xcodeproj/rules_xcodeproj/bazel.lldbinit" enableAddressSanitizer = "YES"> diff --git a/tools/generators/xcschemes/src/Generator/CreateScheme.swift b/tools/generators/xcschemes/src/Generator/CreateScheme.swift index aebcaeec34..860e1ab6d5 100644 --- a/tools/generators/xcschemes/src/Generator/CreateScheme.swift +++ b/tools/generators/xcschemes/src/Generator/CreateScheme.swift @@ -1,3 +1,4 @@ +import Foundation import OrderedCollections import PBXProj import XCScheme @@ -157,6 +158,7 @@ extension Generator.CreateScheme { defaultXcodeConfiguration let launchRunnable: Runnable? + let launchBuildableReference: BuildableReference? let canUseLaunchSchemeArgsEnv: Bool let wasCreatedForAppExtension: Bool switch schemeInfo.run.launchTarget { @@ -164,6 +166,7 @@ extension Generator.CreateScheme { canUseLaunchSchemeArgsEnv = true let buildableReference = primary.buildableReference + launchBuildableReference = buildableReference adjustBuildActionEntry( for: buildableReference, @@ -200,11 +203,13 @@ extension Generator.CreateScheme { .appendUpdateLldbInitAndCopyDSYMs(for: buildableReference) case let .path(path): launchRunnable = .path(path: path) + launchBuildableReference = nil canUseLaunchSchemeArgsEnv = false wasCreatedForAppExtension = false case .none: launchRunnable = nil + launchBuildableReference = nil canUseLaunchSchemeArgsEnv = false wasCreatedForAppExtension = false } @@ -219,9 +224,11 @@ extension Generator.CreateScheme { // MARK: Profile let profileRunnable: Runnable? + let profileBuildableReference: BuildableReference? switch schemeInfo.profile.launchTarget { case let .target(primary, extensionHost): let buildableReference = primary.buildableReference + profileBuildableReference = buildableReference adjustBuildActionEntry(for: buildableReference, include: .profiling) if let extensionHost { @@ -255,9 +262,11 @@ extension Generator.CreateScheme { case let .path(path): profileRunnable = .path(path: path) + profileBuildableReference = nil case .none: profileRunnable = nil + profileBuildableReference = nil } for buildOnlyTarget in schemeInfo.profile.buildTargets { @@ -366,6 +375,9 @@ extension Generator.CreateScheme { buildConfiguration: schemeInfo.test.xcodeConfiguration ?? defaultXcodeConfiguration, commandLineArguments: schemeInfo.test.commandLineArguments, + customLLDBInitFile: bazelLldbInitFile( + for: testables.first?.buildableReference + ), enableAddressSanitizer: schemeInfo.test.enableAddressSanitizer, enableThreadSanitizer: schemeInfo.test.enableThreadSanitizer, enableUBSanitizer: schemeInfo.test.enableUBSanitizer, @@ -387,6 +399,9 @@ extension Generator.CreateScheme { buildConfiguration: launchBuildConfiguration, commandLineArguments: launchRunnable == nil ? [] : schemeInfo.run.commandLineArguments, + customLLDBInitFile: bazelLldbInitFile( + for: launchBuildableReference + ), customWorkingDirectory: schemeInfo.run.customWorkingDirectory, enableAddressSanitizer: schemeInfo.run.enableAddressSanitizer, enableThreadSanitizer: schemeInfo.run.enableThreadSanitizer, @@ -409,6 +424,9 @@ extension Generator.CreateScheme { defaultXcodeConfiguration, commandLineArguments: profileRunnable == nil ? [] : schemeInfo.profile.commandLineArguments, + customLLDBInitFile: bazelLldbInitFile( + for: profileBuildableReference + ), customWorkingDirectory: schemeInfo.profile.customWorkingDirectory, environmentVariables: profileRunnable == nil ? [] : schemeInfo.profile.environmentVariables, @@ -437,6 +455,26 @@ extension Generator.CreateScheme { private typealias OrderedExecutionAction = (action: ExecutionAction, order: Int?) +private func bazelLldbInitFile( + for buildableReference: BuildableReference? +) -> String? { + let containerPrefix = "container:" + + guard + let referencedContainer = buildableReference?.referencedContainer, + referencedContainer.hasPrefix(containerPrefix) + else { + return nil + } + + let projectFilePath = String( + referencedContainer.dropFirst(containerPrefix.count) + ) + return ( + projectFilePath as NSString + ).appendingPathComponent("rules_xcodeproj/bazel.lldbinit") +} + private func compareExecutionActions( lhs: OrderedExecutionAction, rhs: OrderedExecutionAction diff --git a/tools/generators/xcschemes/test/CreateSchemeTests.swift b/tools/generators/xcschemes/test/CreateSchemeTests.swift new file mode 100644 index 0000000000..5a1850b9cf --- /dev/null +++ b/tools/generators/xcschemes/test/CreateSchemeTests.swift @@ -0,0 +1,262 @@ +import CustomDump +import PBXProj +import XCScheme +import XCTest + +@testable import xcschemes + +final class CreateSchemeTests: XCTestCase { + func test_testAction_usesFirstTestableForCustomLLDBInitFile() throws { + // Arrange + + let buildOnlyTarget = Target.mock( + key: "BuildOnly", + productType: .staticLibrary, + buildableReference: buildableReference( + name: "BuildOnly", + referencedContainer: "container:/tmp/BuildOnly.xcodeproj" + ) + ) + let testableTarget = Target.mock( + key: "Tests", + productType: .unitTestBundle, + buildableReference: buildableReference( + name: "Tests", + referencedContainer: "container:/tmp/Tests.xcodeproj" + ) + ) + let expectedTestAction = createExpectedTestAction( + buildableReference: testableTarget.buildableReference + ) + + // Act + + let scheme = try createSchemeWithDefaults( + schemeInfo: .mock( + name: "Scheme", + test: .mock( + buildTargets: [buildOnlyTarget], + testTargets: [.init(target: testableTarget, isEnabled: true)] + ) + ) + ) + + let testAction = try XCTUnwrap(extractTestAction(from: scheme)) + + // Assert + + XCTAssertNoDifference(testAction, expectedTestAction) + } + + func test_profileAction_usesProfileTargetForCustomLLDBInitFile() throws { + // Arrange + + let runTarget = Target.mock( + key: "Run", + productType: .application, + buildableReference: buildableReference( + name: "Run", + referencedContainer: "container:/tmp/Run.xcodeproj" + ) + ) + let profileTarget = Target.mock( + key: "Profile", + productType: .application, + buildableReference: buildableReference( + name: "Profile", + referencedContainer: "container:/tmp/Profile.xcodeproj" + ) + ) + let expectedProfileAction = createExpectedProfileAction( + buildableReference: profileTarget.buildableReference + ) + + // Act + + let scheme = try createSchemeWithDefaults( + schemeInfo: .mock( + name: "Scheme", + run: .mock( + launchTarget: .target( + primary: runTarget, + extensionHost: nil + ) + ), + profile: .mock( + launchTarget: .target( + primary: profileTarget, + extensionHost: nil + ) + ) + ) + ) + + let profileAction = try XCTUnwrap(extractProfileAction(from: scheme)) + + // Assert + + XCTAssertNoDifference(profileAction, expectedProfileAction) + } + + func test_launchAction_pathRunnableDoesNotUseBuildEntryLLDBInitFile() throws { + // Arrange + + let buildOnlyTarget = Target.mock( + key: "BuildOnly", + productType: .application, + buildableReference: buildableReference( + name: "BuildOnly", + referencedContainer: "container:/tmp/BuildOnly.xcodeproj" + ) + ) + let expectedLaunchAction = CreateLaunchAction.defaultCallable( + buildConfiguration: "Debug", + commandLineArguments: [], + customLLDBInitFile: nil, + customWorkingDirectory: nil, + enableAddressSanitizer: false, + enableThreadSanitizer: false, + enableUBSanitizer: false, + enableMainThreadChecker: false, + enableThreadPerformanceChecker: false, + environmentVariables: [], + postActions: [], + preActions: [], + runnable: .path(path: "/tmp/tool"), + storeKitConfiguration: nil + ) + + // Act + + let scheme = try createSchemeWithDefaults( + schemeInfo: .mock( + name: "Scheme", + run: .mock( + buildTargets: [buildOnlyTarget], + launchTarget: .path("/tmp/tool") + ) + ) + ) + + let launchAction = try XCTUnwrap(extractLaunchAction(from: scheme)) + + // Assert + + XCTAssertNoDifference(launchAction, expectedLaunchAction) + } +} + +private func createSchemeWithDefaults( + schemeInfo: SchemeInfo +) throws -> String { + try Generator.CreateScheme.defaultCallable( + defaultXcodeConfiguration: "Debug", + extensionPointIdentifiers: [:], + schemeInfo: schemeInfo, + createAnalyzeAction: CreateAnalyzeAction(), + createArchiveAction: CreateArchiveAction(), + createBuildAction: CreateBuildAction(), + createLaunchAction: CreateLaunchAction(), + createProfileAction: CreateProfileAction(), + createSchemeXML: XCScheme.CreateScheme(), + createTestAction: CreateTestAction() + ).scheme +} + +private func extractTestAction(from scheme: String) -> String? { + extractElement(named: "TestAction", from: scheme) +} + +private func extractProfileAction(from scheme: String) -> String? { + extractElement(named: "ProfileAction", from: scheme) +} + +private func extractLaunchAction(from scheme: String) -> String? { + extractElement(named: "LaunchAction", from: scheme) +} + +private func extractElement(named name: String, from scheme: String) -> String? { + guard + let start = scheme.range(of: " <\(name)"), + let end = scheme.range(of: "") + else { + return nil + } + + return String(scheme[start.lowerBound ..< end.upperBound]) +} + +private func buildableReference( + name: String, + referencedContainer: String +) -> BuildableReference { + return .init( + blueprintIdentifier: "\(name)_blueprintIdentifier", + buildableName: "\(name)_buildableName", + blueprintName: name, + referencedContainer: referencedContainer + ) +} + +private func createExpectedProfileAction( + buildableReference: BuildableReference +) -> String { + return CreateProfileAction.defaultCallable( + buildConfiguration: "Debug", + commandLineArguments: [], + customLLDBInitFile: "/tmp/Profile.xcodeproj/rules_xcodeproj/bazel.lldbinit", + customWorkingDirectory: nil, + environmentVariables: [], + postActions: [], + preActions: [updateLldbInitAndCopyDSYMsAction( + buildableReference: buildableReference + )], + useLaunchSchemeArgsEnv: true, + runnable: .plain(buildableReference: buildableReference) + ) +} + +private func createExpectedTestAction( + buildableReference: BuildableReference +) -> String { + return CreateTestAction.defaultCallable( + appLanguage: nil, + appRegion: nil, + codeCoverage: false, + buildConfiguration: "Debug", + commandLineArguments: [], + customLLDBInitFile: "/tmp/Tests.xcodeproj/rules_xcodeproj/bazel.lldbinit", + enableAddressSanitizer: false, + enableThreadSanitizer: false, + enableUBSanitizer: false, + enableMainThreadChecker: false, + enableThreadPerformanceChecker: false, + environmentVariables: [], + expandVariablesBasedOn: buildableReference, + postActions: [], + preActions: [updateLldbInitAndCopyDSYMsAction( + buildableReference: buildableReference + )], + testables: [ + .init( + buildableReference: buildableReference, + isSkipped: false + ), + ], + useLaunchSchemeArgsEnv: false + ) +} + +private func updateLldbInitAndCopyDSYMsAction( + buildableReference: BuildableReference +) -> ExecutionAction { + return .init( + title: "Update .lldbinit and copy dSYMs", + escapedScriptText: #""" +"$BAZEL_INTEGRATION_DIR/create_lldbinit.sh" +"$BAZEL_INTEGRATION_DIR/copy_dsyms.sh" + +"""#.schemeXmlEscaped, + expandVariablesBasedOn: buildableReference + ) +} diff --git a/xcodeproj/internal/bazel_integration_files/create_lldbinit.sh b/xcodeproj/internal/bazel_integration_files/create_lldbinit.sh index 18694f57aa..dcec4228a9 100755 --- a/xcodeproj/internal/bazel_integration_files/create_lldbinit.sh +++ b/xcodeproj/internal/bazel_integration_files/create_lldbinit.sh @@ -72,21 +72,3 @@ fi echo "command script import \"$OBJROOT/$CONFIGURATION/swift_debug_settings.py\"" } > "$BAZEL_LLDB_INIT" - -if [[ -f "$HOME/.lldbinit-Xcode" ]]; then - readonly lldbinit="$HOME/.lldbinit-Xcode" -elif [[ -f "$HOME/.lldbinit" ]]; then - readonly lldbinit="$HOME/.lldbinit" -else - readonly lldbinit="$HOME/.lldbinit-Xcode" -fi - -touch "$lldbinit" - -readonly required_source='command source ~/.lldbinit-rules_xcodeproj' -if ! grep -m 1 -q "^$required_source$" "$lldbinit"; then - # Add a newline if the file doesn't end with one - tail -c 1 "$lldbinit" | read || echo >> "$lldbinit" - # Update `$lldbinit to source `~/.lldbinit-rules_xcodeproj` - echo "$required_source" >> "$lldbinit" -fi