Skip to content

Commit cd3f8f3

Browse files
MaxDesiatovrauhul
andauthored
[5.9] Improve handling of tool build flags (#6709)
Cherry-pick of #6475. Refactors the various compilerArguments and linkerArgument functions slightly to ensure flags from a user's sdk and cli properly propagate to the expected subcommand invocations. Adds a fairly comprehensive test to cover the toolset and cli flag passing end result. --- Fixes a bug where clang targets didn't respect the `isCXX` override. Fixes a bug where cxxCompiler extraCLIFlags where not passed to clang when building cxx targets. Future work: #6491. cxxCompiler extraCLIFlags should also be passed to `swiftc` when compiling swift modules to ensure the clang importer has the same interpretation of the module as the initial compile. Fixes a bug where linker extraCLIFlags were not passed to `swiftc` prefixed by `-Xlinker`. The previous workaround to pass these flags in swiftCompiler extraCLIFlags is no longer necessary. Fixes a bug where a user could pass `-whole-module-optimization` or `-wmo` to swiftc when linking causing the driver to either attempt to compile the object files when using the legacy driver: rdar://27578292 or crash when using the new driver: rdar://108057797. Fixes a bug where cCompiler extraCLIFlags were not passed to `swiftc` prefixed by `-Xcc`. The previous workaround to pass these flags in swiftCompiler extraCLIFlags is no longer necessary. Fixes a bug where extraCLIFlags from an SDKs toolset.json files would be repeated multiple times in child process invocations. The repeated flags could cause issues with some downstream tools, such as repeated `-segaddr` flags to ld64 for the same segment. Fixes a bug where extra toolchain flags would be added to an xcode build parameters file without escaping. Fixes a bug where extra toolchain linker flags would not be added to an xcode build parameters file. (cherry picked from commit 151343e) # Conflicts: # Sources/Build/BuildPlan.swift # Tests/BuildTests/MockBuildTestHelper.swift --------- Co-authored-by: Rauhul Varma <[email protected]>
1 parent 6ed7215 commit cd3f8f3

File tree

10 files changed

+268
-76
lines changed

10 files changed

+268
-76
lines changed

Sources/Build/BuildDescription/ClangTargetBuildDescription.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,14 @@ public final class ClangTargetBuildDescription {
283283
args += ["-include", resourceAccessorHeaderFile.pathString]
284284
}
285285

286-
args += buildParameters.toolchain.extraFlags.cCompilerFlags
287-
// User arguments (from -Xcc and -Xcxx below) should follow generated arguments to allow user overrides
288-
args += buildParameters.flags.cCompilerFlags
286+
args += self.buildParameters.toolchain.extraFlags.cCompilerFlags
287+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
288+
args += self.buildParameters.flags.cCompilerFlags
289289

290290
// Add extra C++ flags if this target contains C++ files.
291-
if clangTarget.isCXX {
291+
if isCXX {
292+
args += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags
293+
// User arguments (from -Xcxx) should follow generated arguments to allow user overrides
292294
args += self.buildParameters.flags.cxxCompilerFlags
293295
}
294296
return args

Sources/Build/BuildDescription/ProductBuildDescription.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
151151
args += self.buildParameters.sanitizers.linkSwiftFlags()
152152
args += self.additionalFlags
153153

154+
// pass `-v` during verbose builds.
155+
if self.buildParameters.verboseOutput {
156+
args += ["-v"]
157+
}
158+
154159
// Pass `-g` during a *release* build so the Swift driver emits a dSYM file for the binary.
155160
if self.buildParameters.configuration == .release {
156161
if self.buildParameters.triple.isWindows() {
@@ -304,9 +309,12 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
304309
args += self.swiftASTs.flatMap { ["-Xlinker", "-add_ast_path", "-Xlinker", $0.pathString] }
305310

306311
args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
307-
// User arguments (from -Xlinker and -Xswiftc) should follow generated arguments to allow user overrides
308-
args += self.buildParameters.linkerFlags
309-
args += self.stripInvalidArguments(self.buildParameters.swiftCompilerFlags)
312+
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
313+
args += self.buildParameters.flags.swiftCompilerFlags
314+
315+
args += self.buildParameters.toolchain.extraFlags.linkerFlags.asSwiftcLinkerFlags()
316+
// User arguments (from -Xlinker) should follow generated arguments to allow user overrides
317+
args += self.buildParameters.flags.linkerFlags.asSwiftcLinkerFlags()
310318

311319
// Add toolchain's libdir at the very end (even after the user -Xlinker arguments).
312320
//
@@ -323,7 +331,7 @@ public final class ProductBuildDescription: SPMBuildCore.ProductBuildDescription
323331
}
324332
#endif
325333

326-
return args
334+
return self.stripInvalidArguments(args)
327335
}
328336

329337
/// Writes link filelist to the filesystem.

Sources/Build/BuildDescription/SwiftTargetBuildDescription.swift

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ public final class SwiftTargetBuildDescription {
414414
args += try self.buildParameters.targetTripleArgs(for: self.target)
415415
args += ["-swift-version", self.swiftVersion.rawValue]
416416

417+
// pass `-v` during verbose builds.
418+
if self.buildParameters.verboseOutput {
419+
args += ["-v"]
420+
}
421+
417422
// Enable batch mode in debug mode.
418423
//
419424
// Technically, it should be enabled whenever WMO is off but we
@@ -496,7 +501,17 @@ public final class SwiftTargetBuildDescription {
496501

497502
args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
498503
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
499-
args += self.buildParameters.swiftCompilerFlags
504+
args += self.buildParameters.flags.swiftCompilerFlags
505+
506+
args += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
507+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
508+
args += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
509+
510+
// TODO: Pass -Xcxx flags to swiftc (#6491)
511+
// Uncomment when downstream support arrives.
512+
// args += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
513+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
514+
// args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
500515

501516
// suppress warnings if the package is remote
502517
if self.package.isRemote {
@@ -611,6 +626,11 @@ public final class SwiftTargetBuildDescription {
611626
var result: [String] = []
612627
result.append(self.buildParameters.toolchain.swiftCompilerPath.pathString)
613628

629+
// pass `-v` during verbose builds.
630+
if self.buildParameters.verboseOutput {
631+
result += ["-v"]
632+
}
633+
614634
result.append("-module-name")
615635
result.append(self.target.c99name)
616636
result.append(contentsOf: packageNameArgumentIfSupported(with: self.package, packageAccess: self.target.packageAccess))
@@ -646,8 +666,21 @@ public final class SwiftTargetBuildDescription {
646666
result += self.buildParameters.sanitizers.compileSwiftFlags()
647667
result += ["-parseable-output"]
648668
result += try self.buildSettingsFlags()
669+
649670
result += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
650-
result += self.buildParameters.swiftCompilerFlags
671+
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
672+
result += self.buildParameters.flags.swiftCompilerFlags
673+
674+
result += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
675+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
676+
result += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
677+
678+
// TODO: Pass -Xcxx flags to swiftc (#6491)
679+
// Uncomment when downstream support arrives.
680+
// result += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
681+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
682+
// result += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
683+
651684
result += try self.macroArguments()
652685
return result
653686
}

Sources/Build/BuildPlan.swift

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,30 @@ extension AbsolutePath {
4242
}
4343
}
4444

45-
extension BuildParameters {
46-
/// Returns the directory to be used for module cache.
47-
public var moduleCache: AbsolutePath {
48-
get throws {
49-
// FIXME: We use this hack to let swiftpm's functional test use shared
50-
// cache so it doesn't become painfully slow.
51-
if let path = ProcessEnv.vars["SWIFTPM_TESTS_MODULECACHE"] {
52-
return try AbsolutePath(validating: path)
53-
}
54-
return buildPath.appending("ModuleCache")
55-
}
45+
extension Array where Element == String {
46+
/// Converts a set of C compiler flags into an equivalent set to be
47+
/// indirected through the Swift compiler instead.
48+
func asSwiftcCCompilerFlags() -> Self {
49+
self.flatMap { ["-Xcc", $0] }
5650
}
5751

58-
/// Extra flags to pass to Swift compiler.
59-
public var swiftCompilerFlags: [String] {
60-
var flags = self.flags.cCompilerFlags.flatMap({ ["-Xcc", $0] })
61-
flags += self.flags.swiftCompilerFlags
62-
if self.verboseOutput {
63-
flags.append("-v")
64-
}
65-
return flags
52+
/// Converts a set of C++ compiler flags into an equivalent set to be
53+
/// indirected through the Swift compiler instead.
54+
func asSwiftcCXXCompilerFlags() -> Self {
55+
_ = self.flatMap { ["-Xcxx", $0] }
56+
// TODO: Pass -Xcxx flags to swiftc (#6491)
57+
// Remove fatal error when downstream support arrives.
58+
fatalError("swiftc does support -Xcxx flags yet.")
6659
}
6760

68-
/// Extra flags to pass to linker.
69-
public var linkerFlags: [String] {
61+
/// Converts a set of linker flags into an equivalent set to be indirected
62+
/// through the Swift compiler instead.
63+
///
64+
/// Some arguments can be passed directly to the Swift compiler. We omit
65+
/// prefixing these arguments (in both the "-option value" and
66+
/// "-option[=]value" forms) with "-Xlinker". All other arguments are
67+
/// prefixed with "-Xlinker".
68+
func asSwiftcLinkerFlags() -> Self {
7069
// Arguments that can be passed directly to the Swift compiler and
7170
// doesn't require -Xlinker prefix.
7271
//
@@ -75,10 +74,11 @@ extension BuildParameters {
7574
let directSwiftLinkerArgs = ["-L"]
7675

7776
var flags: [String] = []
78-
var it = self.flags.linkerFlags.makeIterator()
77+
var it = self.makeIterator()
7978
while let flag = it.next() {
8079
if directSwiftLinkerArgs.contains(flag) {
8180
// `-L <value>` variant.
81+
// `<option> <value>` variant.
8282
flags.append(flag)
8383
guard let nextFlag = it.next() else {
8484
// We expected a flag but don't have one.
@@ -87,13 +87,28 @@ extension BuildParameters {
8787
flags.append(nextFlag)
8888
} else if directSwiftLinkerArgs.contains(where: { flag.hasPrefix($0) }) {
8989
// `-L<value>` variant.
90+
// `<option>[=]<value>` variant.
9091
flags.append(flag)
9192
} else {
9293
flags += ["-Xlinker", flag]
9394
}
9495
}
9596
return flags
9697
}
98+
}
99+
100+
extension BuildParameters {
101+
/// Returns the directory to be used for module cache.
102+
public var moduleCache: AbsolutePath {
103+
get throws {
104+
// FIXME: We use this hack to let swiftpm's functional test use shared
105+
// cache so it doesn't become painfully slow.
106+
if let path = ProcessEnv.vars["SWIFTPM_TESTS_MODULECACHE"] {
107+
return try AbsolutePath(validating: path)
108+
}
109+
return buildPath.appending("ModuleCache")
110+
}
111+
}
97112

98113
/// Returns the compiler arguments for the index store, if enabled.
99114
func indexStoreArguments(for target: ResolvedTarget) -> [String] {
@@ -147,7 +162,7 @@ extension BuildParameters {
147162
else {
148163
return nil
149164
}
150-
return args.flatMap { ["-Xlinker", $0] }
165+
return args.asSwiftcLinkerFlags()
151166
}
152167

153168
/// Returns the scoped view of build settings for a given target.

Sources/CoreCommands/SwiftTool.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,15 +680,13 @@ public final class SwiftTool {
680680
let dataPath = self.scratchDirectory.appending(
681681
component: destinationTriple.platformBuildPathComponent(buildSystem: options.build.buildSystem)
682682
)
683-
var buildFlags = options.build.buildFlags
684-
buildFlags.append(destinationToolchain.extraFlags)
685683

686684
return try BuildParameters(
687685
dataPath: dataPath,
688686
configuration: options.build.configuration,
689687
toolchain: destinationToolchain,
690688
destinationTriple: destinationTriple,
691-
flags: buildFlags,
689+
flags: options.build.buildFlags,
692690
pkgConfigDirectories: options.locations.pkgConfigDirectories,
693691
architectures: options.build.architectures,
694692
workers: options.build.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount),

Sources/PackageModel/BuildFlags.swift

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,4 @@ public struct BuildFlags: Equatable, Encodable {
4040
self.linkerFlags = linkerFlags
4141
self.xcbuildFlags = xcbuildFlags
4242
}
43-
44-
/// Appends corresponding properties of a different `BuildFlags` value into `self`.
45-
/// - Parameter buildFlags: a `BuildFlags` value to merge flags from.
46-
public mutating func append(_ buildFlags: BuildFlags) {
47-
cCompilerFlags += buildFlags.cCompilerFlags
48-
cxxCompilerFlags += buildFlags.cxxCompilerFlags
49-
swiftCompilerFlags += buildFlags.swiftCompilerFlags
50-
linkerFlags += buildFlags.linkerFlags
51-
52-
if var xcbuildFlags, let newXcbuildFlags = buildFlags.xcbuildFlags {
53-
xcbuildFlags += newXcbuildFlags
54-
self.xcbuildFlags = xcbuildFlags
55-
} else if let xcbuildFlags = buildFlags.xcbuildFlags {
56-
self.xcbuildFlags = xcbuildFlags
57-
}
58-
}
5943
}

Sources/PackageModel/UserToolchain.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,15 @@ public final class UserToolchain: Toolchain {
481481
}
482482

483483
self.triple = triple
484-
self.extraFlags = BuildFlags()
485-
486-
self.extraFlags.swiftCompilerFlags = try Self.deriveSwiftCFlags(
487-
triple: triple,
488-
destination: destination,
489-
environment: environment
490-
)
484+
self.extraFlags = BuildFlags(
485+
cCompilerFlags: destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [],
486+
cxxCompilerFlags: destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [],
487+
swiftCompilerFlags: try Self.deriveSwiftCFlags(
488+
triple: triple,
489+
destination: destination,
490+
environment: environment),
491+
linkerFlags: destination.toolset.knownTools[.linker]?.extraCLIOptions ?? [],
492+
xcbuildFlags: destination.toolset.knownTools[.xcbuild]?.extraCLIOptions ?? [])
491493

492494
self.librarianPath = try UserToolchain.determineLibrarian(
493495
triple: triple,
@@ -499,14 +501,8 @@ public final class UserToolchain: Toolchain {
499501
)
500502

501503
if let sdkDir = destination.pathsConfiguration.sdkRootPath {
502-
self.extraFlags.cCompilerFlags = [
503-
triple.isDarwin() ? "-isysroot" : "--sysroot", sdkDir.pathString,
504-
] + (destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [])
505-
506-
self.extraFlags.cxxCompilerFlags = destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? []
507-
} else {
508-
self.extraFlags.cCompilerFlags = (destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [])
509-
self.extraFlags.cxxCompilerFlags = (destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [])
504+
let sysrootFlags = [triple.isDarwin() ? "-isysroot" : "--sysroot", sdkDir.pathString]
505+
self.extraFlags.cCompilerFlags.insert(contentsOf: sysrootFlags, at: 0)
510506
}
511507

512508
if triple.isWindows() {

Sources/XCBuildSupport/XcodeBuildSystem.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,21 +195,22 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem {
195195
settings["LIBRARY_SEARCH_PATHS"] = "$(inherited) \(try buildParameters.toolchain.toolchainLibDir.pathString)"
196196
settings["OTHER_CFLAGS"] = (
197197
["$(inherited)"]
198-
+ buildParameters.toolchain.extraFlags.cCompilerFlags
198+
+ buildParameters.toolchain.extraFlags.cCompilerFlags.map { $0.spm_shellEscaped() }
199199
+ buildParameters.flags.cCompilerFlags.map { $0.spm_shellEscaped() }
200200
).joined(separator: " ")
201201
settings["OTHER_CPLUSPLUSFLAGS"] = (
202202
["$(inherited)"]
203-
+ buildParameters.toolchain.extraFlags.cxxCompilerFlags
203+
+ buildParameters.toolchain.extraFlags.cxxCompilerFlags.map { $0.spm_shellEscaped() }
204204
+ buildParameters.flags.cxxCompilerFlags.map { $0.spm_shellEscaped() }
205205
).joined(separator: " ")
206206
settings["OTHER_SWIFT_FLAGS"] = (
207207
["$(inherited)"]
208-
+ buildParameters.toolchain.extraFlags.swiftCompilerFlags
208+
+ buildParameters.toolchain.extraFlags.swiftCompilerFlags.map { $0.spm_shellEscaped() }
209209
+ buildParameters.flags.swiftCompilerFlags.map { $0.spm_shellEscaped() }
210210
).joined(separator: " ")
211211
settings["OTHER_LDFLAGS"] = (
212212
["$(inherited)"]
213+
+ buildParameters.toolchain.extraFlags.linkerFlags.map { $0.spm_shellEscaped() }
213214
+ buildParameters.flags.linkerFlags.map { $0.spm_shellEscaped() }
214215
).joined(separator: " ")
215216

0 commit comments

Comments
 (0)