Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// swift-tools-version:999.0
import PackageDescription

let package = Package(
name: "AppPkg",
platforms: [
.macOS(.v10_12),
.iOS(.v10),
.tvOS(.v11),
.watchOS(.v5)
],
dependencies: [
.package(url: "../GamePkg", from: "1.0.0"),
],
targets: [
.executableTarget(
name: "App",
dependencies: [
"Utils",
.product(name: "Utils",
package: "GamePkg",
moduleAliases: ["Utils": "GameUtils"])
],
path: "./Sources/App"),
.target(
name: "Utils",
dependencies: [],
path: "./Sources/Utils"
)
]
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2017 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
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Utils
import GameUtils

Utils.echoModule()

let level = LevelDetector.detect(for: "TestUser")
print(level)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2017 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
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

public func echoModule() {
print("Utils")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// swift-tools-version:5.5
import PackageDescription

let package = Package(
name: "GamePkg",
products: [
.library(name: "Game", targets: ["Game"]),
.library(name: "Utils", targets: ["Utils"]),
],
targets: [
.target(name: "Game", dependencies: ["Utils"]),
.target(name: "Utils", dependencies: []),
]
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2017 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
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

import Utils

public struct Game: Equatable {
public var levels: [LevelDetector]

public static func startGame(for user: String) -> Int {
if user.isEmpty {
return -1
}
return LevelDetector.detect(for: user)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2014 - 2017 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
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

public struct LevelDetector: Equatable {
public static func detect(for user: String) -> Int {
return user.count
}
}
1 change: 1 addition & 0 deletions Sources/Build/LLBuildManifestBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ extension LLBuildManifestBuilder {
outputs: cmdOutputs,
executable: buildParameters.toolchain.swiftCompiler,
moduleName: target.target.c99name,
moduleAliases: target.target.moduleAliases,
moduleOutputPath: target.moduleOutputPath,
importPath: buildParameters.buildPath,
tempsPath: target.tempsPath,
Expand Down
2 changes: 2 additions & 0 deletions Sources/LLBuildManifest/BuildManifest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ public struct BuildManifest {
outputs: [Node],
executable: AbsolutePath,
moduleName: String,
moduleAliases: [String: String]?,
moduleOutputPath: AbsolutePath,
importPath: AbsolutePath,
tempsPath: AbsolutePath,
Expand All @@ -178,6 +179,7 @@ public struct BuildManifest {
outputs: outputs,
executable: executable,
moduleName: moduleName,
moduleAliases: moduleAliases,
moduleOutputPath: moduleOutputPath,
importPath: importPath,
tempsPath: tempsPath,
Expand Down
6 changes: 6 additions & 0 deletions Sources/LLBuildManifest/Tools.swift
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ public struct SwiftCompilerTool: ToolProtocol {

public var executable: AbsolutePath
public var moduleName: String
public var moduleAliases: [String: String]?
public var moduleOutputPath: AbsolutePath
public var importPath: AbsolutePath
public var tempsPath: AbsolutePath
Expand All @@ -235,6 +236,7 @@ public struct SwiftCompilerTool: ToolProtocol {
outputs: [Node],
executable: AbsolutePath,
moduleName: String,
moduleAliases: [String: String]?,
moduleOutputPath: AbsolutePath,
importPath: AbsolutePath,
tempsPath: AbsolutePath,
Expand All @@ -248,6 +250,7 @@ public struct SwiftCompilerTool: ToolProtocol {
self.outputs = outputs
self.executable = executable
self.moduleName = moduleName
self.moduleAliases = moduleAliases
self.moduleOutputPath = moduleOutputPath
self.importPath = importPath
self.tempsPath = tempsPath
Expand All @@ -261,6 +264,9 @@ public struct SwiftCompilerTool: ToolProtocol {
public func write(to stream: ManifestToolStream) {
stream["executable"] = executable
stream["module-name"] = moduleName
if let moduleAliases = moduleAliases {
stream["module-alias"] = moduleAliases
}
stream["module-output-path"] = moduleOutputPath
stream["import-paths"] = [importPath]
stream["temps-path"] = tempsPath
Expand Down
5 changes: 5 additions & 0 deletions Sources/PackageDescription/PackageDependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ extension Package {
}
}

/// Module aliases for targets in this dependency. The key is an original target name and
/// the value is a new unique name mapped to the name of the .swiftmodule binary.
@available(_PackageDescription, introduced: 999.0)
public var moduleAliases: [String: String]?

/// The requirement of the dependency.
@available(_PackageDescription, deprecated: 5.6, message: "use kind instead")
public var requirement: Requirement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ extension Target.Dependency: Encodable {
case type
case name
case package
case moduleAliases
case condition
}

Expand All @@ -308,10 +309,11 @@ extension Target.Dependency: Encodable {
try container.encode(Kind.target, forKey: .type)
try container.encode(name, forKey: .name)
try container.encode(condition, forKey: .condition)
case .productItem(let name, let package, let condition):
case .productItem(let name, let package, let moduleAliases, let condition):
try container.encode(Kind.product, forKey: .type)
try container.encode(name, forKey: .name)
try container.encode(package, forKey: .package)
try container.encode(moduleAliases, forKey: .moduleAliases)
try container.encode(condition, forKey: .condition)
case .byNameItem(let name, let condition):
try container.encode(Kind.byName, forKey: .type)
Expand Down
43 changes: 36 additions & 7 deletions Sources/PackageDescription/Target.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public final class Target {
/// The different types of a target's dependency on another entity.
public enum Dependency {
case targetItem(name: String, condition: TargetDependencyCondition?)
case productItem(name: String, package: String?, condition: TargetDependencyCondition?)
case productItem(name: String, package: String?, moduleAliases: [String: String]?, condition: TargetDependencyCondition?)
case byNameItem(name: String, condition: TargetDependencyCondition?)
}

Expand Down Expand Up @@ -936,9 +936,20 @@ extension Target.Dependency {
/// - package: The name of the package.
@available(_PackageDescription, obsoleted: 5.2, message: "the 'package' argument is mandatory as of tools version 5.2")
public static func product(name: String, package: String? = nil) -> Target.Dependency {
return .productItem(name: name, package: package, condition: nil)
return .productItem(name: name, package: package, moduleAliases: nil, condition: nil)
}


/// Creates a dependency on a product from a dependent package.
///
/// - parameters:
/// - name: The name of the product.
/// - moduleAliases: The module aliases for targets in the product.
/// - package: The name of the package.
@available(_PackageDescription, introduced: 999.0)
public static func product(name: String, package: String? = nil, moduleAliases: [String: String]? = nil) -> Target.Dependency {
return .productItem(name: name, package: package, moduleAliases: moduleAliases, condition: nil)
}

/// Creates a dependency that resolves to either a target or a product with the specified name.
///
/// - parameters:
Expand All @@ -960,7 +971,7 @@ extension Target.Dependency {
name: String,
package: String
) -> Target.Dependency {
return .productItem(name: name, package: package, condition: nil)
return .productItem(name: name, package: package, moduleAliases: nil, condition: nil)
}

/// Creates a dependency on a target in the same package.
Expand All @@ -981,15 +992,33 @@ extension Target.Dependency {
/// - package: The name of the package.
/// - condition: A condition that limits the application of the target dependency. For example, only apply a
/// dependency for a specific platform.
@available(_PackageDescription, introduced: 5.3)
@available(_PackageDescription, introduced: 5.3, obsoleted: 999.0)
public static func product(
name: String,
package: String,
condition: TargetDependencyCondition? = nil
) -> Target.Dependency {
return .productItem(name: name, package: package, condition: condition)
return .productItem(name: name, package: package, moduleAliases: nil, condition: condition)
}


/// Creates a target dependency on a product from a package dependency.
///
/// - parameters:
/// - name: The name of the product.
/// - package: The name of the package.
/// - moduleAliases: The module aliases for targets in the product.
/// - condition: A condition that limits the application of the target dependency. For example, only apply a
/// dependency for a specific platform.
@available(_PackageDescription, introduced: 999.0)
public static func product(
name: String,
package: String,
moduleAliases: [String: String]? = nil,
condition: TargetDependencyCondition? = nil
) -> Target.Dependency {
return .productItem(name: name, package: package, moduleAliases: moduleAliases, condition: condition)
}

/// Creates a by-name dependency that resolves to either a target or a product but after the Swift Package Manager
/// has loaded the package graph.
///
Expand Down
63 changes: 63 additions & 0 deletions Sources/PackageGraph/PackageGraph+Loading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,32 @@ private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], obse
}
}

extension Package {
// Add module aliases specified for applicable targets
fileprivate func setModuleAliasesForTargets(with moduleAliasMap: [String: String]) {
// Set module aliases for each target's dependencies
for (entryName, entryAlias) in moduleAliasMap {
for target in self.targets {
// First add dependency module aliases for this target
if entryName != target.name {
target.addModuleAlias(for: entryName, as: entryAlias)
}
}
}

// This loop should run after the loop above as it may rename the target
// as an alias if specified
for (entryName, entryAlias) in moduleAliasMap {
for target in self.targets {
// Then set this target to be aliased if specified
if entryName == target.name {
target.addModuleAlias(for: target.name, as: entryAlias)
}
}
}
}
}

fileprivate extension ResolvedProduct {
/// Returns true if and only if the product represents a command plugin target.
var isCommandPlugin: Bool {
Expand Down Expand Up @@ -239,6 +265,9 @@ private func createResolvedPackages(
return ($0.package.identity, $0)
}

// Gather all module aliases specified for dependencies from each package
let pkgToAliasesMap = gatherModuleAliases(from: packageBuilders)

// Scan and validate the dependencies
for packageBuilder in packageBuilders {
let package = packageBuilder.package
Expand All @@ -247,6 +276,10 @@ private func createResolvedPackages(
description: "Validating package dependencies",
metadata: package.diagnosticsMetadata
)

if let aliasMap = pkgToAliasesMap[package.manifest.displayName] {
package.setModuleAliasesForTargets(with: aliasMap)
}

var dependencies = OrderedCollections.OrderedDictionary<PackageIdentity, ResolvedPackageBuilder>()
var dependenciesByNameForTargetDependencyResolution = [String: ResolvedPackageBuilder]()
Expand Down Expand Up @@ -490,6 +523,36 @@ private func createResolvedPackages(
return try packageBuilders.map{ try $0.construct() }
}

// Create a map between a package and module aliases specified for its targets
private func gatherModuleAliases(from packageBuilders: [ResolvedPackageBuilder]) -> [String: [String: String]] {
// Use a list to track all the module aliases specified for a given target to handle an override later
var nameToAliasAndPkgMap = [String: [(String, String)]]()
packageBuilders.forEach { $0.package.targets.forEach { $0.dependencies.forEach { dep in
if case let .product(prodRef, _) = dep {
if let prodPkg = prodRef.package {
if let prodModuleAliases = prodRef.moduleAliases {
for (depName, depAlias) in prodModuleAliases {
// Add a module alias to a map if specified
nameToAliasAndPkgMap[depName, default: []].append((depAlias, prodPkg))
}
}
}
}
}}}

var pkgToAliasesMap = [String: [String: String]]()
nameToAliasAndPkgMap.forEach { (keyName, aliasAndPkgList) in
aliasAndPkgList.forEach { (elemAlias, elemPkg) in
// FIXME: handle an override for multiple aliases
// Use one of the module aliases specified for now
if pkgToAliasesMap[elemPkg]?[keyName] == nil, !elemAlias.isEmpty {
pkgToAliasesMap[elemPkg] = [keyName: elemAlias]
}
}
}
return pkgToAliasesMap
}

/// A generic builder for `Resolved` models.
private class ResolvedBuilder<T> {
/// The constructed object, available after the first call to `construct()`.
Expand Down
7 changes: 7 additions & 0 deletions Sources/PackageGraph/ResolvedTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ public final class ResolvedTarget {
return underlyingTarget.c99name
}

/// Module aliases for dependencies of this target. The key is an
/// original target name and the value is a new unique name mapped
/// to the name of its .swiftmodule binary.
public var moduleAliases: [String: String]? {
return underlyingTarget.moduleAliases
}

/// The "type" of target.
public var type: Target.Kind {
return underlyingTarget.type
Expand Down
Loading