Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for --arch flag and add new OS versions to PackageDescription #2786

Merged
merged 2 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 31 additions & 0 deletions IntegrationTests/Tests/IntegrationTests/SwiftPMTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,36 @@ final class SwiftPMTests: XCTestCase {
}
}
}

func testArchCustomization() throws {
try withTemporaryDirectory { tmpDir in
let foo = tmpDir.appending(component: "foo")
try localFileSystem.createDirectory(foo)
try sh(swiftPackage, "--package-path", foo, "init", "--type", "executable")

try localFileSystem.removeFileTree(foo.appending(RelativePath("Sources/foo/main.swift")))
try localFileSystem.writeFileContents(foo.appending(RelativePath("Sources/foo/main.m"))) {
$0 <<< "int main() {}"
}
let archs = ["x86_64", "x86_64h"]

for arch in archs {
try sh(swiftBuild, "--package-path", foo, "--arch", arch)
let fooPath = foo.appending(RelativePath(".build/\(arch)-apple-macosx/debug/foo"))
XCTAssertFileExists(fooPath)
}

let args = [swiftBuild.pathString, "--package-path", foo.pathString] + archs.flatMap{ ["--arch", $0] }
try _sh(args)

let fooPath = foo.appending(RelativePath(".build/apple/Products/Debug/foo"))
XCTAssertFileExists(fooPath)

let objectsDir = foo.appending(RelativePath(".build/apple/Intermediates.noindex/foo.build/Debug/foo.build/Objects-normal"))
for arch in archs {
XCTAssertDirectoryExists(objectsDir.appending(component: arch))
}
}
}
#endif
}
10 changes: 9 additions & 1 deletion Sources/Commands/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public class ToolOptions {
/// Path to the compilation destination’s toolchain.
public var customCompileToolchain: AbsolutePath?

/// The architectures to compile for.
public var archs: [String] = []

/// If should link the Swift stdlib statically.
public var shouldLinkStaticSwiftStdlib = false

Expand Down Expand Up @@ -94,7 +97,12 @@ public class ToolOptions {
public var emitSwiftModuleSeparately: Bool = false

/// The build system to use.
public var buildSystem: BuildSystemKind = .native
public var buildSystem: BuildSystemKind {
// Force the Xcode build system if we want to build more than one arch.
archs.count > 1 ? .xcode : _buildSystem
}

public var _buildSystem: BuildSystemKind = .native

/// Extra arguments to pass when using xcbuild.
public var xcbuildFlags: [String] = []
Expand Down
18 changes: 15 additions & 3 deletions Sources/Commands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,12 @@ public class SwiftTool<Options: ToolOptions> {
option: parser.add(option: "--toolchain", kind: PathArgument.self),
to: { $0.customCompileToolchain = $1.path })

binder.bind(
option: parser.add(
option: "--arch", kind: [String].self, strategy: .oneByOne,
usage: "Build the package for the these architectures"),
to: { $0.archs = $1 })

// FIXME: We need to allow -vv type options for this.
binder.bind(
option: parser.add(option: "--verbose", shortName: "-v", kind: Bool.self,
Expand Down Expand Up @@ -452,7 +458,7 @@ public class SwiftTool<Options: ToolOptions> {

binder.bind(
option: parser.add(option: "--build-system", kind: BuildSystemKind.self, usage: nil),
to: { $0.buildSystem = $1 })
to: { $0._buildSystem = $1 })

// Let subclasses bind arguments.
type(of: self).defineArguments(parser: parser, binder: binder)
Expand All @@ -474,7 +480,7 @@ public class SwiftTool<Options: ToolOptions> {

// Force building with the native build system on other platforms than macOS.
#if !os(macOS)
options.buildSystem = .native
options._buildSystem = .native
#endif

let processSet = ProcessSet()
Expand Down Expand Up @@ -534,6 +540,10 @@ public class SwiftTool<Options: ToolOptions> {
if result.exists(arg: "--multiroot-data-file") {
diagnostics.emit(.unsupportedFlag("--multiroot-data-file"))
}

if result.exists(arg: "--arch") && result.exists(arg: "--triple") {
diagnostics.emit(.mutuallyExclusiveArgumentsError(arguments: ["--arch", "--triple"]))
}
}

class func defineArguments(parser: ArgumentParser, binder: ArgumentBinder<Options>) {
Expand Down Expand Up @@ -779,6 +789,7 @@ public class SwiftTool<Options: ToolOptions> {
configuration: options.configuration,
toolchain: toolchain,
destinationTriple: triple,
archs: options.archs,
flags: options.buildFlags,
xcbuildFlags: options.xcbuildFlags,
jobs: options.jobs ?? UInt32(ProcessInfo.processInfo.activeProcessorCount),
Expand Down Expand Up @@ -812,14 +823,15 @@ public class SwiftTool<Options: ToolOptions> {
}
// Apply any manual overrides.
if let triple = self.options.customCompileTriple {
destination.target = triple
destination.target = triple
}
if let binDir = self.options.customCompileToolchain {
destination.binDir = binDir.appending(components: "usr", "bin")
}
if let sdk = self.options.customCompileSDK {
destination.sdk = sdk
}
destination.archs = options.archs

// Check if we ended up with the host toolchain.
if hostDestination == destination {
Expand Down
33 changes: 32 additions & 1 deletion Sources/PackageDescription/SupportedPlatforms.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2018 Apple Inc. and the Swift project authors
Copyright (c) 2018-2020 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See http://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -208,6 +208,19 @@ extension SupportedPlatform {
/// - Since: First available in PackageDescription 5.1
@available(_PackageDescription, introduced: 5.1)
public static let v10_15: MacOSVersion = .init(string: "10.15")

/// The value that represents macOS 10.16, which is treated
/// as an alias for macOS 11.0.
///
/// - Since: First available in PackageDescription 5.3
@available(_PackageDescription, introduced: 5.3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we mark this deprecated + renamed so that developers get a fixit?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's what we want to do but as a separate commit/PR.

public static let v10_16: MacOSVersion = .init(string: "11.0")

/// The value that represents macOS 11.0.
///
/// - Since: First available in PackageDescription 5.3
@available(_PackageDescription, introduced: 5.3)
public static let v11: MacOSVersion = .init(string: "11.0")
}

/// The supported tvOS version.
Expand Down Expand Up @@ -247,6 +260,12 @@ extension SupportedPlatform {
/// - Since: First available in PackageDescription 5.1
@available(_PackageDescription, introduced: 5.1)
public static let v13: TVOSVersion = .init(string: "13.0")

/// The value that represents tvOS 14.0.
///
/// - Since: First available in PackageDescription 5.3
@available(_PackageDescription, introduced: 5.3)
public static let v14: TVOSVersion = .init(string: "14.0")
}

/// The supported iOS version.
Expand Down Expand Up @@ -291,6 +310,12 @@ extension SupportedPlatform {
/// - Since: First available in PackageDescription 5.1
@available(_PackageDescription, introduced: 5.1)
public static let v13: IOSVersion = .init(string: "13.0")

/// The value that represents iOS 14.0.
///
/// - Since: First available in PackageDescription 5.3
@available(_PackageDescription, introduced: 5.3)
public static let v14: IOSVersion = .init(string: "14.0")
}

/// The supported watchOS version.
Expand Down Expand Up @@ -330,6 +355,12 @@ extension SupportedPlatform {
/// - Since: First available in PackageDescription 5.1
@available(_PackageDescription, introduced: 5.1)
public static let v6: WatchOSVersion = .init(string: "6.0")

/// The value that represents watchOS 7.0.
///
/// - Since: First available in PackageDescription 5.3
@available(_PackageDescription, introduced: 5.3)
public static let v7: WatchOSVersion = .init(string: "7.0")
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/PackageModel/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public struct Platform: Equatable, Hashable {
}

public static let macOS: Platform = Platform(name: "macos", oldestSupportedVersion: "10.10")
public static let iOS: Platform = Platform(name: "ios", oldestSupportedVersion: "8.0")
public static let iOS: Platform = Platform(name: "ios", oldestSupportedVersion: "9.0")
public static let tvOS: Platform = Platform(name: "tvos", oldestSupportedVersion: "9.0")
public static let watchOS: Platform = Platform(name: "watchos", oldestSupportedVersion: "2.0")
public static let linux: Platform = Platform(name: "linux", oldestSupportedVersion: .unknown)
Expand Down
5 changes: 5 additions & 0 deletions Sources/SPMBuildCore/BuildParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public struct BuildParameters: Encodable {
/// Destination triple.
public var triple: Triple

/// The architectures to build for.
public var archs: [String]

/// Extra build flags.
public var flags: BuildFlags

Expand Down Expand Up @@ -117,6 +120,7 @@ public struct BuildParameters: Encodable {
configuration: BuildConfiguration,
toolchain: Toolchain,
destinationTriple: Triple? = nil,
archs: [String] = [],
flags: BuildFlags,
xcbuildFlags: [String] = [],
toolsVersion: ToolsVersion = ToolsVersion.currentToolsVersion,
Expand All @@ -136,6 +140,7 @@ public struct BuildParameters: Encodable {
self.configuration = configuration
self._toolchain = _Toolchain(toolchain: toolchain)
self.triple = destinationTriple ?? .getHostTriple(usingSwiftCompiler: toolchain.swiftCompiler)
self.archs = archs
self.flags = flags
self.xcbuildFlags = xcbuildFlags
self.toolsVersion = toolsVersion
Expand Down
3 changes: 3 additions & 0 deletions Sources/SPMBuildCore/Triple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ public struct Triple: Encodable, Equatable {

public enum Arch: String, Encodable {
case x86_64
case x86_64h
case i686
case powerpc64le
case s390x
case aarch64
case armv7
case arm
case arm64
case arm64e
case wasm32
}

Expand Down
3 changes: 3 additions & 0 deletions Sources/Workspace/Destination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public struct Destination: Encodable, Equatable {
/// for more information see //https://clang.llvm.org/docs/CrossCompilation.html
public var target: Triple?

/// The architectures to build for. We build for host architecture if this is empty.
public var archs: [String] = []

/// The SDK used to compile for the destination.
public var sdk: AbsolutePath

Expand Down
14 changes: 13 additions & 1 deletion Sources/Workspace/UserToolchain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ public final class UserToolchain: Toolchain {
/// The target triple that should be used for compilation.
public let triple: Triple

/// The list of archs to build for.
public let archs: [String]

/// Search paths from the PATH environment variable.
let envSearchPaths: [AbsolutePath]

Expand Down Expand Up @@ -254,8 +257,17 @@ public final class UserToolchain: Toolchain {
self.xctest = nil
#endif

self.archs = destination.archs
// Use the triple from destination or compute the host triple using swiftc.
let triple = destination.target ?? Triple.getHostTriple(usingSwiftCompiler: swiftCompilers.compile)
var triple = destination.target ?? Triple.getHostTriple(usingSwiftCompiler: swiftCompilers.compile)

// Change the triple to the specified arch if there's exactly one of them.
// The Triple property is only looked at by the native build system currently.
if archs.count == 1 {
let components = triple.tripleString.drop(while: { $0 != "-" })
triple = try Triple(archs[0] + components)
}

self.triple = triple
self.extraSwiftCFlags = UserToolchain.deriveSwiftCFlags(triple: triple, destination: destination)

Expand Down
72 changes: 70 additions & 2 deletions Sources/XCBuildSupport/XcodeBuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ See http://swift.org/LICENSE.txt for license information
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import class Foundation.JSONEncoder

import TSCBasic
import TSCUtility
import PackageModel
Expand Down Expand Up @@ -78,7 +80,7 @@ public final class XcodeBuildSystem: BuildSystem {
let pif = try pifBuilder.generatePIF()
try localFileSystem.writeIfChanged(path: buildParameters.pifManifest, bytes: ByteString(encodingAsUTF8: pif))

let arguments = [
var arguments = [
xcbuildPath.pathString,
"build",
buildParameters.pifManifest.pathString,
Expand All @@ -88,7 +90,14 @@ public final class XcodeBuildSystem: BuildSystem {
buildParameters.dataPath.pathString,
"--target",
subset.pifTargetName
] + buildParameters.xcbuildFlags
]

let buildParamsFile = try createBuildParametersFile()
if let buildParamsFile = buildParamsFile {
arguments += ["--buildParametersFile", buildParamsFile.pathString]
}

arguments += buildParameters.xcbuildFlags

let delegate = createBuildDelegate()
let redirection: Process.OutputRedirection = .stream(stdout: delegate.parse(bytes:), stderr: { bytes in
Expand All @@ -99,11 +108,47 @@ public final class XcodeBuildSystem: BuildSystem {
try process.launch()
let result = try process.waitUntilExit()

if let buildParamsFile = buildParamsFile {
try? localFileSystem.removeFileTree(buildParamsFile)
}

guard result.exitStatus == .terminated(code: 0) else {
throw Diagnostics.fatalError
}
}

func createBuildParametersFile() throws -> AbsolutePath? {
// We only generate the build parameters file if it's required.
guard !buildParameters.archs.isEmpty else { return nil }

let runDestination = XCBBuildParameters.RunDestination(
platform: "macosx",
sdk: "macosx",
sdkVariant: nil,
targetArchitecture: "x86_64",
supportedArchitectures: [],
disableOnlyActiveArch: true
)
let params = XCBBuildParameters(
configurationName: buildParameters.configuration.xcbuildName,
overrides: .init(commandLine: .init(table: [
"ARCHS": "\(buildParameters.archs.joined(separator: " "))",
])),
activeRunDestination: runDestination
)

let encoder = JSONEncoder()
if #available(macOS 10.13, *) {
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
}

let data = try encoder.encode(params)
let file = try withTemporaryFile(deleteOnClose: false) { $0.path }
try localFileSystem.writeFileContents(file, bytes: ByteString(data))

return file
}

public func cancel() {
}

Expand Down Expand Up @@ -138,6 +183,29 @@ public final class XcodeBuildSystem: BuildSystem {
}
}

struct XCBBuildParameters: Encodable {
struct RunDestination: Encodable {
var platform: String
var sdk: String
var sdkVariant: String?
var targetArchitecture: String
var supportedArchitectures: [String]
var disableOnlyActiveArch: Bool
}

struct XCBSettingsTable: Encodable {
var table: [String: String]
}

struct SettingsOverride: Encodable {
var commandLine: XCBSettingsTable? = nil
}

var configurationName: String
var overrides: SettingsOverride
var activeRunDestination: RunDestination
}

extension BuildConfiguration {
public var xcbuildName: String {
switch self {
Expand Down