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

[swiftpm] For development, build a local copy of PackageDescription #405

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 16 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,14 @@ let package = Package(
"BuildServerProtocol",
"LanguageServerProtocol",
"SKCore",
.product(name: "SwiftPM-auto", package: "SwiftPM")
],
exclude: ["CMakeLists.txt"]),
.product(name: "SwiftPM-auto", package: "SwiftPM"),
] + (useLocalPackageDescriptionModule() ? [
.product(name: "PackageDescription", package: "SwiftPM"),
] : []),
exclude: ["CMakeLists.txt"],
swiftSettings: useLocalPackageDescriptionModule() ? [
.define("USE_LOCAL_PACKAGE_DESCRIPTION_MODULE")
] : []),

.testTarget(
name: "SKSwiftPMWorkspaceTests",
Expand Down Expand Up @@ -248,3 +253,11 @@ if ProcessInfo.processInfo.environment["SWIFTCI_USE_LOCAL_DEPS"] == nil {
.package(path: "../swift-argument-parser")
]
}

func useLocalPackageDescriptionModule() -> Bool {
// By default, create a local PackageDescription module to ensure it stays
// in sync with libSwiftPM during development. To install sourcekit-lsp as
// part of the toolchain we use the toolchain's own PackageDescription, and
// rely on the whole toolchain being built from the same swiftpm sources.
return ProcessInfo.processInfo.environment["SWIFTCI_USE_TOOLCHAIN_PACKAGE_DESCRIPTION"] == nil
}
41 changes: 38 additions & 3 deletions Sources/SKSwiftPMWorkspace/SwiftPMWorkspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import SKCore
import SKSupport
import Workspace
import Dispatch
import struct Foundation.URL
import Foundation

/// Swift Package Manager build system and workspace support.
///
Expand Down Expand Up @@ -84,6 +84,7 @@ public final class SwiftPMWorkspace {

let destination = try Destination.hostDestination(destinationToolchainBinDir)
let toolchain = try UserToolchain(destination: destination)
let manifestResources = manifestResources(for: toolchain)

let buildPath: AbsolutePath = buildSetup.path ?? packageRoot.appending(component: ".build")

Expand All @@ -93,7 +94,7 @@ public final class SwiftPMWorkspace {
dataPath: buildPath,
editablesPath: packageRoot.appending(component: "Packages"),
pinsFile: packageRoot.appending(component: "Package.resolved"),
manifestLoader: ManifestLoader(manifestResources: toolchain.manifestResources, cacheDir: buildPath),
manifestLoader: ManifestLoader(manifestResources: manifestResources, cacheDir: buildPath),
config: workspaceConfiguration,
fileSystem: fileSystem,
skipUpdate: true)
Expand Down Expand Up @@ -122,7 +123,7 @@ public final class SwiftPMWorkspace {
/// Creates a build system using the Swift Package Manager, if this workspace is a package.
///
/// - Returns: nil if `workspacePath` is not part of a package or there is an error.
public convenience init?(url: URL,
public convenience init?(url: Foundation.URL,
toolchainRegistry: ToolchainRegistry,
buildSetup: BuildSetup)
{
Expand Down Expand Up @@ -454,3 +455,37 @@ extension TSCBasic.Diagnostic.Behavior {
}
}
}

private func manifestResources(for toolchain: UserToolchain) -> ManifestResourceProvider {
#if USE_LOCAL_PACKAGE_DESCRIPTION_MODULE
var buildURL = Bundle(for: SwiftPMWorkspace.self).bundleURL
if buildURL.pathExtension == "xctest" {
// If we are statically linked into a test bundle, look in the parent.
buildURL.deleteLastPathComponent()
}
// Look for a local copy of PackageDescription -- either as a bare module, or
// a framework when building with Xcode. If we find a local PackageDescription
// module, override the manifest resources `binDir` so that it will be used
// instead of the toolchain's own manifest resources.
let fileManager = FileManager.default
let bareModule = buildURL
.appendingPathComponent("PackageDescription.swiftmodule")
let frameworkModule = buildURL
.appendingPathComponent("PackageFrameworks")
.appendingPathComponent("PackageDescription.framework")
if fileManager.fileExists(atPath: bareModule.path) || fileManager.fileExists(atPath: frameworkModule.path) {
let manifestResources = toolchain.manifestResources
return UserManifestResources(
swiftCompiler: manifestResources.swiftCompiler,
swiftCompilerFlags: manifestResources.swiftCompilerFlags,
libDir: manifestResources.libDir,
sdkRoot: manifestResources.sdkRoot,
xctestLocation: manifestResources.xctestLocation,
binDir: AbsolutePath(buildURL.path))
} else {
log("requested USE_LOCAL_PACKAGE_DESCRIPTION_MODULE but did not find PackageDescription in \(buildURL); falling back to toolchain resources", level: .error)
}
#endif

return toolchain.manifestResources
}
3 changes: 3 additions & 0 deletions Utilities/build-script-helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def handle_invocation(swift_exec, args):
if not args.no_local_deps:
env['SWIFTCI_USE_LOCAL_DEPS'] = "1"

# Always use the toolchain's package description module.
env['SWIFTCI_USE_TOOLCHAIN_PACKAGE_DESCRIPTION'] = "1"

if args.ninja_bin:
env['NINJA_BIN'] = args.ninja_bin

Expand Down