Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 3 additions & 16 deletions Sources/PackageGraph/ModulesGraph+Loading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -728,23 +728,10 @@ private func createResolvedPackages(
moduleBuilder.dependencies += implicitSystemLibraryDeps.map { .module($0, conditions: []) }

// Establish product dependencies.
for case .product(let productRef, let conditions) in moduleBuilder.module.dependencies {
for case .product(let productRef, var conditions) in moduleBuilder.module.dependencies {
if let package = productRef.package, prebuilts[.plain(package)]?[productRef.name] != nil {
// See if we're using a prebuilt instead
if moduleBuilder.module.type == .macro {
continue
} else if moduleBuilder.module.type == .test {
// use prebuilt if this is a test that depends a macro target
// these are guaranteed built for host
if moduleBuilder.module.dependencies.contains(where: { dep in
guard let module = dep.module else {
return false
}
return module.type == .macro
}) {
continue
}
}
// Mark the dependency as not host. We'll add host build settings for the prebuilts later.
conditions.append(.isHost(.init(isHost: false)))
}

// Find the product in this package's dependency products.
Expand Down
57 changes: 28 additions & 29 deletions Sources/PackageLoading/PackageBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1407,40 +1407,39 @@ public final class PackageBuilder {
table.add(assignment, for: .SWIFT_ACTIVE_COMPILATION_CONDITIONS)
}

// Add in flags for prebuilts if the target is a macro or a macro test.
// Currently we only support prebuilts for macros.
if target.type == .macro || target.isMacroTest(in: manifest) {
let prebuiltLibraries: [String: PrebuiltLibrary] = target.dependencies.reduce(into: .init()) {
guard case let .product(name: name, package: package, moduleAliases: _, condition: _) = $1,
let package = package,
let prebuilt = prebuilts[.plain(package)]?[name]
else {
return
}

$0[prebuilt.libraryName] = prebuilt
// Add in flags for prebuilts for host
let prebuiltLibraries: [String: PrebuiltLibrary] = target.dependencies.reduce(into: .init()) {
guard case let .product(name: name, package: package, moduleAliases: _, condition: _) = $1,
let package = package,
let prebuilt = prebuilts[.plain(package)]?[name]
else {
return
}

for prebuilt in prebuiltLibraries.values {
let lib = prebuilt.path.appending(components: ["lib", "lib\(prebuilt.libraryName).a"]).pathString
var ldFlagsAssignment = BuildSettings.Assignment()
ldFlagsAssignment.values = [lib]
table.add(ldFlagsAssignment, for: .OTHER_LDFLAGS)
$0[prebuilt.libraryName] = prebuilt
}

var includeDirs: [AbsolutePath] = [prebuilt.path.appending(component: "Modules")]
if let checkoutPath = prebuilt.checkoutPath, let includePath = prebuilt.includePath {
for includeDir in includePath {
includeDirs.append(checkoutPath.appending(includeDir))
}
} else {
for cModule in prebuilt.cModules {
includeDirs.append(prebuilt.path.appending(components: "include", cModule))
}
for prebuilt in prebuiltLibraries.values {
let lib = prebuilt.path.appending(components: ["lib", "lib\(prebuilt.libraryName).a"]).pathString
var ldFlagsAssignment = BuildSettings.Assignment()
ldFlagsAssignment.values = [lib]
ldFlagsAssignment.conditions = [.isHost(.init(isHost: true))]
table.add(ldFlagsAssignment, for: .OTHER_LDFLAGS)

var includeDirs: [AbsolutePath] = [prebuilt.path.appending(component: "Modules")]
if let checkoutPath = prebuilt.checkoutPath, let includePath = prebuilt.includePath {
for includeDir in includePath {
includeDirs.append(checkoutPath.appending(includeDir))
}
} else {
for cModule in prebuilt.cModules {
includeDirs.append(prebuilt.path.appending(components: "include", cModule))
}
var includeAssignment = BuildSettings.Assignment()
includeAssignment.values = includeDirs.map({ "-I\($0.pathString)" })
table.add(includeAssignment, for: .OTHER_SWIFT_FLAGS)
}
var includeAssignment = BuildSettings.Assignment()
includeAssignment.values = includeDirs.map({ "-I\($0.pathString)" })
includeAssignment.conditions = [.isHost(.init(isHost: true))]
table.add(includeAssignment, for: .OTHER_SWIFT_FLAGS)
}

return table
Expand Down
4 changes: 3 additions & 1 deletion Sources/PackageModel/BuildEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
/// A build environment with which to evaluate conditions.
public struct BuildEnvironment {
public let platform: Platform
public let isHost: Bool
public let configuration: BuildConfiguration?

public init(platform: Platform, configuration: BuildConfiguration? = nil) {
public init(platform: Platform, isHost: Bool, configuration: BuildConfiguration? = nil) {
self.platform = platform
self.isHost = isHost
self.configuration = configuration
}
}
33 changes: 30 additions & 3 deletions Sources/PackageModel/Manifest/PackageConditionDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public struct PackageConditionDescription: Codable, Hashable, Sendable {
/// build configurations.
public enum PackageCondition: Hashable, Sendable {
case platforms(PlatformsCondition)
case isHost(HostCondition)
case configuration(ConfigurationCondition)
case traits(TraitCondition)

Expand All @@ -37,6 +38,8 @@ public enum PackageCondition: Hashable, Sendable {
return configuration.satisfies(environment)
case .platforms(let platforms):
return platforms.satisfies(environment)
case .isHost(let hostCondition):
return hostCondition.satisfies(environment)
case .traits(let traits):
return traits.satisfies(environment)
}
Expand Down Expand Up @@ -66,13 +69,25 @@ public enum PackageCondition: Hashable, Sendable {
return traitCondition
}

public var hostCondition: HostCondition? {
guard case let .isHost(hostCondition) = self else {
return nil
}

return hostCondition
}

public init(platforms: [Platform]) {
self = .platforms(.init(platforms: platforms))
}

public init(configuration: BuildConfiguration) {
self = .configuration(.init(configuration: configuration))
}

public init(isHost: Bool) {
self = .isHost(.init(isHost: isHost))
}
}

/// Platforms condition implies that an assignment is valid on these platforms.
Expand Down Expand Up @@ -107,9 +122,8 @@ public struct ConfigurationCondition: Hashable, Sendable {
}
}


/// A configuration condition implies that an assignment is valid on
/// a particular build configuration.
/// By the time we get to evaluating the condition, the package loader would have filtered out
/// disabled traits. As such, this should always evaluate to true.
Copy link
Contributor

Choose a reason for hiding this comment

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

praise: thank you for updating this description!

public struct TraitCondition: Hashable, Sendable {
public let traits: Set<String>

Expand All @@ -122,3 +136,16 @@ public struct TraitCondition: Hashable, Sendable {
}
}

/// A hidden condition that is true if the target is building for the host platform.
/// Currently only used for prebuilts.
public struct HostCondition: Hashable, Sendable {
public let isHost: Bool

public init(isHost: Bool) {
self.isHost = isHost
}

public func satisfies(_ environment: BuildEnvironment) -> Bool {
environment.isHost == isHost
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public struct BuildParameters: Encodable {

/// The current build environment.
public var buildEnvironment: BuildEnvironment {
BuildEnvironment(platform: currentPlatform, configuration: configuration)
BuildEnvironment(platform: currentPlatform, isHost: destination == .host, configuration: configuration)
}

/// The current platform we're building for.
Expand Down
71 changes: 33 additions & 38 deletions Sources/SwiftBuildSupport/PackagePIFBuilder+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import class PackageModel.SwiftModule
import class PackageModel.SystemLibraryModule
import struct PackageModel.ToolsVersion
import struct PackageModel.TraitCondition
import struct PackageModel.HostCondition

import struct PackageGraph.ResolvedModule
import struct PackageGraph.ResolvedPackage
Expand Down Expand Up @@ -246,42 +247,6 @@ extension Sequence<PackageModel.PackageCondition> {
}
return Set(pifPlatforms.flatMap { $0.toPlatformFilter() })
}

var splitIntoConcreteConditions: (
[PackageModel.Platform?],
[PackageModel.BuildConfiguration],
[PackageModel.TraitCondition]
) {
var platformConditions: [PackageModel.PlatformsCondition] = []
var configurationConditions: [PackageModel.ConfigurationCondition] = []
var traitConditions: [PackageModel.TraitCondition] = []

for packageCondition in self {
switch packageCondition {
case .platforms(let condition): platformConditions.append(condition)
case .configuration(let condition): configurationConditions.append(condition)
case .traits(let condition): traitConditions.append(condition)
}
}

// Determine the *platform* conditions, if any.
// An empty set means that there are no platform restrictions.
let platforms: [PackageModel.Platform?] = if platformConditions.isEmpty {
[nil]
} else {
platformConditions.flatMap(\.platforms)
}

// Determine the *configuration* conditions, if any.
// If there are none, we apply the setting to both debug and release builds (ie, `allCases`).
let configurations: [BuildConfiguration] = if configurationConditions.isEmpty {
BuildConfiguration.allCases
} else {
configurationConditions.map(\.configuration)
}

return (platforms, configurations, traitConditions)
}
}

extension PackageModel.BuildSettings.Declaration {
Expand Down Expand Up @@ -646,8 +611,38 @@ extension PackageGraph.ResolvedModule {
values = settingAssignment.values
}

// TODO: We are currently ignoring package traits (see rdar://138149810).
let (platforms, configurations, _) = settingAssignment.conditions.splitIntoConcreteConditions
var platformConditions: [PackageModel.PlatformsCondition] = []
var configurationConditions: [PackageModel.ConfigurationCondition] = []

// Traits always evaluate to true at this point.
// TODO: Platforms aren't currently sufficient to describe building for host
// especially Linux. We could have different Linux for host versus target.
// Native build has host versus target explicitly modeled with
// BuildParameters.Destination.
for packageCondition in settingAssignment.conditions {
switch packageCondition {
case .platforms(let condition): platformConditions.append(condition)
case .configuration(let condition): configurationConditions.append(condition)
case .traits(_): break
case .isHost(_): break
}
}

// Determine the *platform* conditions, if any.
// An empty set means that there are no platform restrictions.
let platforms: [PackageModel.Platform?] = if platformConditions.isEmpty {
[nil]
} else {
platformConditions.flatMap(\.platforms)
}

// Determine the *configuration* conditions, if any.
// If there are none, we apply the setting to both debug and release builds (ie, `allCases`).
let configurations: [BuildConfiguration] = if configurationConditions.isEmpty {
BuildConfiguration.allCases
} else {
configurationConditions.map(\.configuration)
}

for platform in platforms {
let pifPlatform: ProjectModel.BuildSettings.Platform?
Expand Down
Loading
Loading