Skip to content

Commit e44c050

Browse files
committed
Improve handling of tool build flags
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 639f9d1 commit e44c050

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
@@ -426,6 +426,11 @@ public final class SwiftTargetBuildDescription {
426426
args += try self.buildParameters.targetTripleArgs(for: self.target)
427427
args += ["-swift-version", self.swiftVersion.rawValue]
428428

429+
// pass `-v` during verbose builds.
430+
if self.buildParameters.verboseOutput {
431+
args += ["-v"]
432+
}
433+
429434
// Enable batch mode in debug mode.
430435
//
431436
// Technically, it should be enabled whenever WMO is off but we
@@ -508,7 +513,17 @@ public final class SwiftTargetBuildDescription {
508513

509514
args += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
510515
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
511-
args += self.buildParameters.swiftCompilerFlags
516+
args += self.buildParameters.flags.swiftCompilerFlags
517+
518+
args += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
519+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
520+
args += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
521+
522+
// TODO: Pass -Xcxx flags to swiftc (#6491)
523+
// Uncomment when downstream support arrives.
524+
// args += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
525+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
526+
// args += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
512527

513528
// suppress warnings if the package is remote
514529
if self.package.isRemote {
@@ -623,6 +638,11 @@ public final class SwiftTargetBuildDescription {
623638
var result: [String] = []
624639
result.append(self.buildParameters.toolchain.swiftCompilerPath.pathString)
625640

641+
// pass `-v` during verbose builds.
642+
if self.buildParameters.verboseOutput {
643+
result += ["-v"]
644+
}
645+
626646
result.append("-module-name")
627647
result.append(self.target.c99name)
628648
result.append(contentsOf: packageNameArgumentIfSupported(with: self.package, packageAccess: self.target.packageAccess))
@@ -658,8 +678,21 @@ public final class SwiftTargetBuildDescription {
658678
result += self.buildParameters.sanitizers.compileSwiftFlags()
659679
result += ["-parseable-output"]
660680
result += try self.buildSettingsFlags()
681+
661682
result += self.buildParameters.toolchain.extraFlags.swiftCompilerFlags
662-
result += self.buildParameters.swiftCompilerFlags
683+
// User arguments (from -Xswiftc) should follow generated arguments to allow user overrides
684+
result += self.buildParameters.flags.swiftCompilerFlags
685+
686+
result += self.buildParameters.toolchain.extraFlags.cCompilerFlags.asSwiftcCCompilerFlags()
687+
// User arguments (from -Xcc) should follow generated arguments to allow user overrides
688+
result += self.buildParameters.flags.cCompilerFlags.asSwiftcCCompilerFlags()
689+
690+
// TODO: Pass -Xcxx flags to swiftc (#6491)
691+
// Uncomment when downstream support arrives.
692+
// result += self.buildParameters.toolchain.extraFlags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
693+
// // User arguments (from -Xcxx) should follow generated arguments to allow user overrides
694+
// result += self.buildParameters.flags.cxxCompilerFlags.asSwiftcCXXCompilerFlags()
695+
663696
result += try self.macroArguments()
664697
return result
665698
}

Sources/Build/BuildPlan.swift

Lines changed: 38 additions & 25 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,25 +74,39 @@ 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) {
81-
// `-L <value>` variant.
80+
// `<option> <value>` variant.
8281
flags.append(flag)
8382
guard let nextFlag = it.next() else {
8483
// We expected a flag but don't have one.
8584
continue
8685
}
8786
flags.append(nextFlag)
8887
} else if directSwiftLinkerArgs.contains(where: { flag.hasPrefix($0) }) {
89-
// `-L<value>` variant.
88+
// `<option>[=]<value>` variant.
9089
flags.append(flag)
9190
} else {
9291
flags += ["-Xlinker", flag]
9392
}
9493
}
9594
return flags
9695
}
96+
}
97+
98+
extension BuildParameters {
99+
/// Returns the directory to be used for module cache.
100+
public var moduleCache: AbsolutePath {
101+
get throws {
102+
// FIXME: We use this hack to let swiftpm's functional test use shared
103+
// cache so it doesn't become painfully slow.
104+
if let path = ProcessEnv.vars["SWIFTPM_TESTS_MODULECACHE"] {
105+
return try AbsolutePath(validating: path)
106+
}
107+
return buildPath.appending("ModuleCache")
108+
}
109+
}
97110

98111
/// Returns the compiler arguments for the index store, if enabled.
99112
func indexStoreArguments(for target: ResolvedTarget) -> [String] {
@@ -147,7 +160,7 @@ extension BuildParameters {
147160
else {
148161
return nil
149162
}
150-
return args.flatMap { ["-Xlinker", $0] }
163+
return args.asSwiftcLinkerFlags()
151164
}
152165

153166
/// 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)