diff --git a/Sources/SWBBuildService/Messages.swift b/Sources/SWBBuildService/Messages.swift index 3632e7f36..0a09ebc57 100644 --- a/Sources/SWBBuildService/Messages.swift +++ b/Sources/SWBBuildService/Messages.swift @@ -312,7 +312,8 @@ private struct SetSessionUserPreferencesMsg: MessageHandler { enableBuildSystemCaching: message.enableBuildSystemCaching, activityTextShorteningLevel: message.activityTextShorteningLevel, usePerConfigurationBuildLocations: message.usePerConfigurationBuildLocations, - allowsExternalToolExecution: message.allowsExternalToolExecution ?? UserPreferences.allowsExternalToolExecutionDefaultValue) + allowsExternalToolExecution: message.allowsExternalToolExecution ?? UserPreferences.allowsExternalToolExecutionDefaultValue, + emitFrontendCommandLines: message.emitFrontendCommandLines ?? false) ) return VoidResponse() diff --git a/Sources/SWBCore/WorkspaceContext.swift b/Sources/SWBCore/WorkspaceContext.swift index 48c0ddb3b..4b8ad704b 100644 --- a/Sources/SWBCore/WorkspaceContext.swift +++ b/Sources/SWBCore/WorkspaceContext.swift @@ -109,6 +109,9 @@ public struct UserPreferences: Sendable { /// Whether dynamic tasks are allowed to request processes be spawned as external tools. public let allowsExternalToolExecution: Bool + /// Whether the frontend command lines for compiler invocations should be emitted to the build log. + public let emitFrontendCommandLines: Bool + public static var allowsExternalToolExecutionDefaultValue: Bool { #if RC_PLAYGROUNDS return true @@ -123,7 +126,8 @@ public struct UserPreferences: Sendable { enableBuildSystemCaching: UserDefaults.enableBuildSystemCaching, activityTextShorteningLevel: UserDefaults.activityTextShorteningLevel, usePerConfigurationBuildLocations: UserDefaults.usePerConfigurationBuildLocations, - allowsExternalToolExecution: UserDefaults.allowsExternalToolExecution + allowsExternalToolExecution: UserDefaults.allowsExternalToolExecution, + emitFrontendCommandLines: UserDefaults.emitFrontendCommandLines ) public init( @@ -132,7 +136,8 @@ public struct UserPreferences: Sendable { enableBuildSystemCaching: Bool, activityTextShorteningLevel: ActivityTextShorteningLevel, usePerConfigurationBuildLocations: Bool?, - allowsExternalToolExecution: Bool + allowsExternalToolExecution: Bool, + emitFrontendCommandLines: Bool ) { self.enableDebugActivityLogs = enableDebugActivityLogs self.enableBuildDebugging = enableBuildDebugging @@ -140,6 +145,7 @@ public struct UserPreferences: Sendable { self.activityTextShorteningLevel = activityTextShorteningLevel self.usePerConfigurationBuildLocations = usePerConfigurationBuildLocations self.allowsExternalToolExecution = allowsExternalToolExecution + self.emitFrontendCommandLines = emitFrontendCommandLines } } diff --git a/Sources/SWBProtocol/Message.swift b/Sources/SWBProtocol/Message.swift index 50fde356e..c0f157d7d 100644 --- a/Sources/SWBProtocol/Message.swift +++ b/Sources/SWBProtocol/Message.swift @@ -656,6 +656,7 @@ public struct SetSessionUserPreferencesRequest: SessionMessage, RequestMessage, public let activityTextShorteningLevel: ActivityTextShorteningLevel public let usePerConfigurationBuildLocations: Bool? public let allowsExternalToolExecution: Bool? + public let emitFrontendCommandLines: Bool? public init(sessionHandle: String, enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: ActivityTextShorteningLevel, usePerConfigurationBuildLocations: Bool?) { self.sessionHandle = sessionHandle @@ -665,9 +666,10 @@ public struct SetSessionUserPreferencesRequest: SessionMessage, RequestMessage, self.activityTextShorteningLevel = activityTextShorteningLevel self.usePerConfigurationBuildLocations = usePerConfigurationBuildLocations self.allowsExternalToolExecution = nil + self.emitFrontendCommandLines = nil } - public init(sessionHandle: String, enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: ActivityTextShorteningLevel, usePerConfigurationBuildLocations: Bool?, allowsExternalToolExecution: Bool) { + public init(sessionHandle: String, enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: ActivityTextShorteningLevel, usePerConfigurationBuildLocations: Bool?, allowsExternalToolExecution: Bool, emitFrontendCommandLines: Bool? = nil) { self.sessionHandle = sessionHandle self.enableDebugActivityLogs = enableDebugActivityLogs self.enableBuildDebugging = enableBuildDebugging @@ -675,6 +677,7 @@ public struct SetSessionUserPreferencesRequest: SessionMessage, RequestMessage, self.activityTextShorteningLevel = activityTextShorteningLevel self.usePerConfigurationBuildLocations = usePerConfigurationBuildLocations self.allowsExternalToolExecution = allowsExternalToolExecution + self.emitFrontendCommandLines = emitFrontendCommandLines } } diff --git a/Sources/SWBTaskConstruction/ProductPlanning/BuildPlan.swift b/Sources/SWBTaskConstruction/ProductPlanning/BuildPlan.swift index 6b1242c12..7fcb72d6e 100644 --- a/Sources/SWBTaskConstruction/ProductPlanning/BuildPlan.swift +++ b/Sources/SWBTaskConstruction/ProductPlanning/BuildPlan.swift @@ -287,7 +287,7 @@ package final class BuildPlan: StaleFileRemovalContext { self.invalidationPaths = Array(invalidationPaths.sorted(by: \.str)) self.recursiveSearchPathResults = globalProductPlan.recursiveSearchPathResolver.allResults self.copiedPathMap = copiedPathMap - self.emitFrontendCommandLines = productPlanResultContexts.map { $0.productPlan.taskProducerContext.emitFrontendCommandLines }.reduce(false, { $0 || $1 }) + self.emitFrontendCommandLines = planRequest.workspaceContext.userPreferences.emitFrontendCommandLines || productPlanResultContexts.map { $0.productPlan.taskProducerContext.emitFrontendCommandLines }.reduce(false, { $0 || $1 }) } static func unexpectedDuplicateTasksWithIdentifier(_ tasks: [any PlannedTask], _ workspace: Workspace, _ delegate: any TaskPlanningDelegate) { diff --git a/Sources/SWBTestSupport/TestWorkspaces.swift b/Sources/SWBTestSupport/TestWorkspaces.swift index 9d550ea45..e1f9d2b13 100644 --- a/Sources/SWBTestSupport/TestWorkspaces.swift +++ b/Sources/SWBTestSupport/TestWorkspaces.swift @@ -1599,7 +1599,8 @@ extension UserPreferences { enableBuildSystemCaching: true, activityTextShorteningLevel: .default, usePerConfigurationBuildLocations: nil, - allowsExternalToolExecution: false) + allowsExternalToolExecution: false, + emitFrontendCommandLines: false) package func with( enableDebugActivityLogs: Bool? = nil, @@ -1607,7 +1608,8 @@ extension UserPreferences { enableBuildSystemCaching: Bool? = nil, activityTextShorteningLevel: ActivityTextShorteningLevel? = nil, usePerConfigurationBuildLocations: Bool?? = .none, - allowsExternalToolExecution: Bool? = nil + allowsExternalToolExecution: Bool? = nil, + emitFrontendCommandLines: Bool? = nil ) -> UserPreferences { let usePerConfigurationBuildLocationsValue: Bool? switch usePerConfigurationBuildLocations { @@ -1625,7 +1627,8 @@ extension UserPreferences { enableBuildSystemCaching: enableBuildSystemCaching ?? self.enableBuildSystemCaching, activityTextShorteningLevel: activityTextShorteningLevel ?? self.activityTextShorteningLevel, usePerConfigurationBuildLocations: usePerConfigurationBuildLocationsValue, - allowsExternalToolExecution: allowsExternalToolExecution ?? self.allowsExternalToolExecution + allowsExternalToolExecution: allowsExternalToolExecution ?? self.allowsExternalToolExecution, + emitFrontendCommandLines: emitFrontendCommandLines ?? self.emitFrontendCommandLines ) } } diff --git a/Sources/SWBUtil/UserDefaults.swift b/Sources/SWBUtil/UserDefaults.swift index b9a56af30..4a7013171 100644 --- a/Sources/SWBUtil/UserDefaults.swift +++ b/Sources/SWBUtil/UserDefaults.swift @@ -253,6 +253,11 @@ public enum UserDefaults: Sendable { return string(forKey: "CompilationCachingDiskSizeLimit") } + /// Whether the frontend command lines for compiler invocations should be emitted to the build log. + public static var emitFrontendCommandLines: Bool { + return bool(forKey: "EmitFrontendCommandLines") + } + /// Provides the default level of QoS support within Swift Build for global queues that are not tied to specific build requests. public static var undeterminedQoS: SWBQoS { // With 'unspecified' the QoS of the caller is influencing the QoS to be used for the enqueued work item. diff --git a/Sources/SwiftBuild/SWBBuildServiceSession.swift b/Sources/SwiftBuild/SWBBuildServiceSession.swift index 43ffd5214..66a40a8f4 100644 --- a/Sources/SwiftBuild/SWBBuildServiceSession.swift +++ b/Sources/SwiftBuild/SWBBuildServiceSession.swift @@ -662,10 +662,15 @@ public final class SWBBuildServiceSession: Sendable { _ = try await service.send(request: SetSessionUserPreferencesRequest(sessionHandle: self.uid, enableDebugActivityLogs: enableDebugActivityLogs, enableBuildDebugging: enableBuildDebugging, enableBuildSystemCaching: enableBuildSystemCaching, activityTextShorteningLevel: ActivityTextShorteningLevel(rawValue: activityTextShorteningLevel) ?? .default, usePerConfigurationBuildLocations: usePerConfigurationBuildLocations)) } + @available(*, deprecated, renamed: "setUserPreferences(enableDebugActivityLogs:enableBuildDebugging:enableBuildSystemCaching:activityTextShorteningLevel:usePerConfigurationBuildLocations:allowsExternalToolExecution:emitFrontendCommandLines:)") public func setUserPreferences(enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: Int, usePerConfigurationBuildLocations: Bool?, allowsExternalToolExecution: Bool) async throws { _ = try await service.send(request: SetSessionUserPreferencesRequest(sessionHandle: self.uid, enableDebugActivityLogs: enableDebugActivityLogs, enableBuildDebugging: enableBuildDebugging, enableBuildSystemCaching: enableBuildSystemCaching, activityTextShorteningLevel: ActivityTextShorteningLevel(rawValue: activityTextShorteningLevel) ?? .default, usePerConfigurationBuildLocations: usePerConfigurationBuildLocations, allowsExternalToolExecution: allowsExternalToolExecution)) } + public func setUserPreferences(enableDebugActivityLogs: Bool, enableBuildDebugging: Bool, enableBuildSystemCaching: Bool, activityTextShorteningLevel: Int, usePerConfigurationBuildLocations: Bool?, allowsExternalToolExecution: Bool, emitFrontendCommandLines: Bool) async throws { + _ = try await service.send(request: SetSessionUserPreferencesRequest(sessionHandle: self.uid, enableDebugActivityLogs: enableDebugActivityLogs, enableBuildDebugging: enableBuildDebugging, enableBuildSystemCaching: enableBuildSystemCaching, activityTextShorteningLevel: ActivityTextShorteningLevel(rawValue: activityTextShorteningLevel) ?? .default, usePerConfigurationBuildLocations: usePerConfigurationBuildLocations, allowsExternalToolExecution: allowsExternalToolExecution, emitFrontendCommandLines: emitFrontendCommandLines)) + } + public func lookupToolchain(at path: String) async throws -> SWBToolchainIdentifier? { return try await service.send(request: LookupToolchainRequest(sessionHandle: self.uid, path: Path(path))).toolchainIdentifier.map { SWBToolchainIdentifier(rawValue: $0) } } diff --git a/Sources/SwiftBuildTestSupport/TestUtilities.swift b/Sources/SwiftBuildTestSupport/TestUtilities.swift index f644a308a..1987e4a9b 100644 --- a/Sources/SwiftBuildTestSupport/TestUtilities.swift +++ b/Sources/SwiftBuildTestSupport/TestUtilities.swift @@ -216,7 +216,8 @@ extension SWBBuildServiceSession { enableBuildSystemCaching: userPreferences.enableBuildSystemCaching, activityTextShorteningLevel: userPreferences.activityTextShorteningLevel.rawValue, usePerConfigurationBuildLocations: userPreferences.usePerConfigurationBuildLocations, - allowsExternalToolExecution: userPreferences.allowsExternalToolExecution) + allowsExternalToolExecution: userPreferences.allowsExternalToolExecution, + emitFrontendCommandLines: userPreferences.emitFrontendCommandLines) } package func generateIndexingFileSettings(for request: SWBBuildRequest, targetID: String, delegate: any SWBIndexingDelegate) async throws -> SWBIndexingFileSettings { diff --git a/SwiftBuild.docc/Development/build-debugging.md b/SwiftBuild.docc/Development/build-debugging.md index 42b869e4f..b5f26ff78 100644 --- a/SwiftBuild.docc/Development/build-debugging.md +++ b/SwiftBuild.docc/Development/build-debugging.md @@ -15,6 +15,14 @@ defaults write org.swift.swift-build EnableDebugActivityLogs -bool YES This will cause Swift Build to emit more detailed note diagnostics to the build log which is deemed to verbose for normal usage. +### Frontend command lines + +``` +defaults write org.swift.swift-build EmitFrontendCommandLines -bool YES +``` + +This will cause Swift Build to emit the frontend command lines for compiler invocations to the build log. It is a lighter-weight subset of `EnableDebugActivityLogs` equivalent to setting the `EMIT_FRONTEND_COMMAND_LINES` build setting persistently. + ### Incremental build debugging ``` diff --git a/Tests/SWBBuildSystemTests/BuildOperationTests.swift b/Tests/SWBBuildSystemTests/BuildOperationTests.swift index fecb164f1..c24f69a83 100644 --- a/Tests/SWBBuildSystemTests/BuildOperationTests.swift +++ b/Tests/SWBBuildSystemTests/BuildOperationTests.swift @@ -8120,6 +8120,40 @@ That command depends on command in Target 'agg2' (project \'aProject\'): script } } + @Test(.requireSDKs(.macOS), arguments: [true, false]) + func emitFrontendCommandLines(preference: Bool) async throws { + // Each parameterized invocation is independent, giving the BuildDescriptionManager + // a fresh workspace so it plans with the correct emitFrontendCommandLines value. + try await withTemporaryDirectory { tmpDirPath in + let testWorkspace = try await TestWorkspace( + "Test", + sourceRoot: tmpDirPath.join("Test"), + projects: [ + TestProject( + "aProject", + groupTree: TestGroup("Sources", path: "Sources", children: [TestFile("Source.swift")]), + buildConfigurations: [TestBuildConfiguration("Debug", buildSettings: [ + "PRODUCT_NAME": "$(TARGET_NAME)", + "SWIFT_VERSION": swiftVersion, + "SWIFT_USE_INTEGRATED_DRIVER": "YES", + ])], + targets: [TestStandardTarget("TargetA", type: .framework, buildPhases: [TestSourcesBuildPhase(["Source.swift"])])]) + ]) + let tester = try await BuildOperationTester(getCore(), testWorkspace, simulated: false) + let SRCROOT = testWorkspace.sourceRoot.join("aProject") + try await tester.fs.writeFileContents(SRCROOT.join("Sources/Source.swift")) { $0 <<< "struct A {}\n" } + tester.userPreferences = .defaultForTesting.with(emitFrontendCommandLines: preference) + try await tester.checkBuild(runDestination: .macOS, persistent: true) { results in + results.checkNoErrors() + results.checkTask(.matchRuleType("SwiftCompile")) { task in + results.checkTaskOutput(task) { output in + #expect(output.stringValue?.contains("swift-frontend") == preference) + } + } + } + } + } + @Test(.requireSDKs(.host)) func swiftSDKToolsets() async throws { try await withTemporaryDirectory { tmpDirPath async throws -> Void in diff --git a/Tests/SWBCoreTests/SettingsTests.swift b/Tests/SWBCoreTests/SettingsTests.swift index d4a95ced2..333f537c1 100644 --- a/Tests/SWBCoreTests/SettingsTests.swift +++ b/Tests/SWBCoreTests/SettingsTests.swift @@ -5715,4 +5715,5 @@ import SWBTestSupport } } } + } diff --git a/Tests/SWBProtocolTests/MessageSerializationTests.swift b/Tests/SWBProtocolTests/MessageSerializationTests.swift index eefbfe18d..87739e0cf 100644 --- a/Tests/SWBProtocolTests/MessageSerializationTests.swift +++ b/Tests/SWBProtocolTests/MessageSerializationTests.swift @@ -77,6 +77,8 @@ import Testing assertMsgPackMessageRoundTrip(SetSessionSystemInfoRequest(sessionHandle: "theSession", operatingSystemVersion: Version(11, 1, 3), productBuildVersion: "25A573", nativeArchitecture: "arm64")) assertMsgPackMessageRoundTrip(SetSessionUserInfoRequest(sessionHandle: "theSession", user: "mobile", group: "mobile", uid: 501, gid: 99, home: "/root", processEnvironment: ["HOME": "/root"], buildSystemEnvironment: ["SRCROOT": "/"])) assertMsgPackMessageRoundTrip(SetSessionUserPreferencesRequest(sessionHandle: "theSession", enableDebugActivityLogs: true, enableBuildDebugging: true, enableBuildSystemCaching: true, activityTextShorteningLevel: .default, usePerConfigurationBuildLocations: nil)) + assertMsgPackMessageRoundTrip(SetSessionUserPreferencesRequest(sessionHandle: "theSession", enableDebugActivityLogs: true, enableBuildDebugging: true, enableBuildSystemCaching: true, activityTextShorteningLevel: .default, usePerConfigurationBuildLocations: nil, allowsExternalToolExecution: true)) + assertMsgPackMessageRoundTrip(SetSessionUserPreferencesRequest(sessionHandle: "theSession", enableDebugActivityLogs: true, enableBuildDebugging: true, enableBuildSystemCaching: true, activityTextShorteningLevel: .default, usePerConfigurationBuildLocations: nil, allowsExternalToolExecution: true, emitFrontendCommandLines: true)) assertMsgPackMessageRoundTrip(ListSessionsRequest()) assertMsgPackMessageRoundTrip(ListSessionsResponse(sessions: ["theSession": .init(name: "itsGreat", activeBuildCount: 0, activeNormalBuildCount: 0, activeIndexBuildCount: 0)])) assertMsgPackMessageRoundTrip(DeleteSessionRequest(sessionHandle: "theSession"))