Skip to content

Commit 151343e

Browse files
authored
Improve handling of tool build flags (#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.
1 parent 2cb0f2f commit 151343e

File tree

10 files changed

+269
-79
lines changed

10 files changed

+269
-79
lines changed

Sources/Build/BuildDescription/ClangTargetBuildDescription.swift

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

238-
args += buildParameters.toolchain.extraFlags.cCompilerFlags
239-
// User arguments (from -Xcc and -Xcxx below) should follow generated arguments to allow user overrides
240-
args += buildParameters.flags.cCompilerFlags
238+
args += self.buildParameters.toolchain.extraFlags.cCompilerFlags
239+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
240+
args += self.buildParameters.flags.cCompilerFlags
241241

242242
// Add extra C++ flags if this target contains C++ files.
243-
if clangTarget.isCXX {
243+
if isCXX {
244+
args += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags
245+
// User arguments (from -Xcxx) should follow generated arguments to allow user overrides
244246
args += self.buildParameters.flags.cxxCompilerFlags
245247
}
246248
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
@@ -422,6 +422,11 @@ public final class SwiftTargetBuildDescription {
422422
args += try self.buildParameters.targetTripleArgs(for: self.target)
423423
args += ["-swift-version", self.swiftVersion.rawValue]
424424

425+
// pass `-v` during verbose builds.
426+
if self.buildParameters.verboseOutput {
427+
args += ["-v"]
428+
}
429+
425430
// Enable batch mode in debug mode.
426431
//
427432
// Technically, it should be enabled whenever WMO is off but we
@@ -504,7 +509,17 @@ public final class SwiftTargetBuildDescription {
504509

505510
args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
506511
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
507-
args += self.buildParameters.swiftCompilerFlags
512+
args += self.buildParameters.flags.swiftCompilerFlags
513+
514+
args += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
515+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
516+
args += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
517+
518+
// TODO: Pass -Xcxx flags to swiftc (#6491)
519+
// Uncomment when downstream support arrives.
520+
// args += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
521+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
522+
// args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
508523

509524
// suppress warnings if the package is remote
510525
if self.package.isRemote {
@@ -619,6 +634,11 @@ public final class SwiftTargetBuildDescription {
619634
var result: [String] = []
620635
result.append(self.buildParameters.toolchain.swiftCompilerPath.pathString)
621636

637+
// pass `-v` during verbose builds.
638+
if self.buildParameters.verboseOutput {
639+
result += ["-v"]
640+
}
641+
622642
result.append("-module-name")
623643
result.append(self.target.c99name)
624644
result.append(contentsOf: packageNameArgumentIfSupported(with: self.package, packageAccess: self.target.packageAccess))
@@ -654,8 +674,21 @@ public final class SwiftTargetBuildDescription {
654674
result += self.buildParameters.sanitizers.compileSwiftFlags()
655675
result += ["-parseable-output"]
656676
result += try self.buildSettingsFlags()
677+
657678
result += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
658-
result += self.buildParameters.swiftCompilerFlags
679+
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
680+
result += self.buildParameters.flags.swiftCompilerFlags
681+
682+
result += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
683+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
684+
result += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
685+
686+
// TODO: Pass -Xcxx flags to swiftc (#6491)
687+
// Uncomment when downstream support arrives.
688+
// result += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
689+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
690+
// result += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
691+
659692
result += try self.macroArguments()
660693
return result
661694
}

Sources/Build/BuildPlan.swift

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,31 +30,30 @@ extension String {
3030
}
3131
}
3232

33-
extension BuildParameters {
34-
/// Returns the directory to be used for module cache.
35-
public var moduleCache: AbsolutePath {
36-
get throws {
37-
// FIXME: We use this hack to let swiftpm's functional test use shared
38-
// cache so it doesn't become painfully slow.
39-
if let path = ProcessEnv.vars["SWIFTPM_TESTS_MODULECACHE"] {
40-
return try AbsolutePath(validating: path)
41-
}
42-
return buildPath.appending("ModuleCache")
43-
}
33+
extension Array where Element == String {
34+
/// Converts a set of C compiler flags into an equivalent set to be
35+
/// indirected through the Swift compiler instead.
36+
func asSwiftcCCompilerFlags() -> Self {
37+
self.flatMap { ["-Xcc", $0] }
4438
}
4539

46-
/// Extra flags to pass to Swift compiler.
47-
public var swiftCompilerFlags: [String] {
48-
var flags = self.flags.cCompilerFlags.flatMap({ ["-Xcc", $0] })
49-
flags += self.flags.swiftCompilerFlags
50-
if self.verboseOutput {
51-
flags.append("-v")
52-
}
53-
return flags
40+
/// Converts a set of C++ compiler flags into an equivalent set to be
41+
/// indirected through the Swift compiler instead.
42+
func asSwiftcCXXCompilerFlags() -> Self {
43+
_ = self.flatMap { ["-Xcxx", $0] }
44+
// TODO: Pass -Xcxx flags to swiftc (#6491)
45+
// Remove fatal error when downstream support arrives.
46+
fatalError("swiftc does support -Xcxx flags yet.")
5447
}
5548

56-
/// Extra flags to pass to linker.
57-
public var linkerFlags: [String] {
49+
/// Converts a set of linker flags into an equivalent set to be indirected
50+
/// through the Swift compiler instead.
51+
///
52+
/// Some arguments can be passed directly to the Swift compiler. We omit
53+
/// prefixing these arguments (in both the "-option value" and
54+
/// "-option[=]value" forms) with "-Xlinker". All other arguments are
55+
/// prefixed with "-Xlinker".
56+
func asSwiftcLinkerFlags() -> Self {
5857
// Arguments that can be passed directly to the Swift compiler and
5958
// doesn't require -Xlinker prefix.
6059
//
@@ -63,25 +62,39 @@ extension BuildParameters {
6362
let directSwiftLinkerArgs = ["-L"]
6463

6564
var flags: [String] = []
66-
var it = self.flags.linkerFlags.makeIterator()
65+
var it = self.makeIterator()
6766
while let flag = it.next() {
6867
if directSwiftLinkerArgs.contains(flag) {
69-
// `-L <value>` variant.
68+
// `<option> <value>` variant.
7069
flags.append(flag)
7170
guard let nextFlag = it.next() else {
7271
// We expected a flag but don't have one.
7372
continue
7473
}
7574
flags.append(nextFlag)
7675
} else if directSwiftLinkerArgs.contains(where: { flag.hasPrefix($0) }) {
77-
// `-L<value>` variant.
76+
// `<option>[=]<value>` variant.
7877
flags.append(flag)
7978
} else {
8079
flags += ["-Xlinker", flag]
8180
}
8281
}
8382
return flags
8483
}
84+
}
85+
86+
extension BuildParameters {
87+
/// Returns the directory to be used for module cache.
88+
public var moduleCache: AbsolutePath {
89+
get throws {
90+
// FIXME: We use this hack to let swiftpm's functional test use shared
91+
// cache so it doesn't become painfully slow.
92+
if let path = ProcessEnv.vars["SWIFTPM_TESTS_MODULECACHE"] {
93+
return try AbsolutePath(validating: path)
94+
}
95+
return buildPath.appending("ModuleCache")
96+
}
97+
}
8598

8699
/// Returns the compiler arguments for the index store, if enabled.
87100
func indexStoreArguments(for target: ResolvedTarget) -> [String] {
@@ -135,7 +148,7 @@ extension BuildParameters {
135148
else {
136149
return nil
137150
}
138-
return args.flatMap { ["-Xlinker", $0] }
151+
return args.asSwiftcLinkerFlags()
139152
}
140153

141154
/// 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
@@ -463,13 +463,15 @@ public final class UserToolchain: Toolchain {
463463
}
464464

465465
self.triple = triple
466-
self.extraFlags = BuildFlags()
467-
468-
self.extraFlags.swiftCompilerFlags = try Self.deriveSwiftCFlags(
469-
triple: triple,
470-
destination: destination,
471-
environment: environment
472-
)
466+
self.extraFlags = BuildFlags(
467+
cCompilerFlags: destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [],
468+
cxxCompilerFlags: destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [],
469+
swiftCompilerFlags: try Self.deriveSwiftCFlags(
470+
triple: triple,
471+
destination: destination,
472+
environment: environment),
473+
linkerFlags: destination.toolset.knownTools[.linker]?.extraCLIOptions ?? [],
474+
xcbuildFlags: destination.toolset.knownTools[.xcbuild]?.extraCLIOptions ?? [])
473475

474476
self.librarianPath = try UserToolchain.determineLibrarian(
475477
triple: triple,
@@ -481,14 +483,8 @@ public final class UserToolchain: Toolchain {
481483
)
482484

483485
if let sdkDir = destination.pathsConfiguration.sdkRootPath {
484-
self.extraFlags.cCompilerFlags = [
485-
triple.isDarwin() ? "-isysroot" : "--sysroot", sdkDir.pathString,
486-
] + (destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [])
487-
488-
self.extraFlags.cxxCompilerFlags = destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? []
489-
} else {
490-
self.extraFlags.cCompilerFlags = (destination.toolset.knownTools[.cCompiler]?.extraCLIOptions ?? [])
491-
self.extraFlags.cxxCompilerFlags = (destination.toolset.knownTools[.cxxCompiler]?.extraCLIOptions ?? [])
486+
let sysrootFlags = [triple.isDarwin() ? "-isysroot" : "--sysroot", sdkDir.pathString]
487+
self.extraFlags.cCompilerFlags.insert(contentsOf: sysrootFlags, at: 0)
492488
}
493489

494490
if triple.isWindows() {

Sources/XCBuildSupport/XcodeBuildSystem.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,22 @@ public final class XcodeBuildSystem: SPMBuildCore.BuildSystem {
193193
settings["LIBRARY_SEARCH_PATHS"] = "$(inherited) \(try buildParameters.toolchain.toolchainLibDir.pathString)"
194194
settings["OTHER_CFLAGS"] = (
195195
["$(inherited)"]
196-
+ buildParameters.toolchain.extraFlags.cCompilerFlags
196+
+ buildParameters.toolchain.extraFlags.cCompilerFlags.map { $0.spm_shellEscaped() }
197197
+ buildParameters.flags.cCompilerFlags.map { $0.spm_shellEscaped() }
198198
).joined(separator: " ")
199199
settings["OTHER_CPLUSPLUSFLAGS"] = (
200200
["$(inherited)"]
201-
+ buildParameters.toolchain.extraFlags.cxxCompilerFlags
201+
+ buildParameters.toolchain.extraFlags.cxxCompilerFlags.map { $0.spm_shellEscaped() }
202202
+ buildParameters.flags.cxxCompilerFlags.map { $0.spm_shellEscaped() }
203203
).joined(separator: " ")
204204
settings["OTHER_SWIFT_FLAGS"] = (
205205
["$(inherited)"]
206-
+ buildParameters.toolchain.extraFlags.swiftCompilerFlags
206+
+ buildParameters.toolchain.extraFlags.swiftCompilerFlags.map { $0.spm_shellEscaped() }
207207
+ buildParameters.flags.swiftCompilerFlags.map { $0.spm_shellEscaped() }
208208
).joined(separator: " ")
209209
settings["OTHER_LDFLAGS"] = (
210210
["$(inherited)"]
211+
+ buildParameters.toolchain.extraFlags.linkerFlags.map { $0.spm_shellEscaped() }
211212
+ buildParameters.flags.linkerFlags.map { $0.spm_shellEscaped() }
212213
).joined(separator: " ")
213214

0 commit comments

Comments
 (0)