Skip to content

Allow building against a single dynamic swift-syntax library 🚥#851 #852

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

Merged
merged 2 commits into from
Oct 14, 2024
Merged
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
276 changes: 152 additions & 124 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,125 +14,153 @@
import Foundation
import PackageDescription

let package = Package(
name: "swift-format",
platforms: [
.macOS("12.0"),
.iOS("13.0"),
],
products: [
.executable(
name: "swift-format",
targets: ["swift-format"]
),
.library(
name: "SwiftFormat",
targets: ["SwiftFormat"]
),
.plugin(
name: "FormatPlugin",
targets: ["Format Source Code"]
),
.plugin(
name: "LintPlugin",
targets: ["Lint Source Code"]
),
],
dependencies: dependencies,
targets: [
.target(
name: "_SwiftFormatInstructionCounter",
exclude: ["CMakeLists.txt"]
),
var products: [Product] = [
.executable(
name: "swift-format",
targets: ["swift-format"]
),
.library(
name: "SwiftFormat",
targets: ["SwiftFormat"]
),
.plugin(
name: "FormatPlugin",
targets: ["Format Source Code"]
),
.plugin(
name: "LintPlugin",
targets: ["Lint Source Code"]
),
]

var targets: [Target] = [
.target(
name: "_SwiftFormatInstructionCounter",
exclude: ["CMakeLists.txt"]
),

.target(
name: "SwiftFormat",
dependencies: omittingExternalDependenciesIfNecessary([
.product(name: "Markdown", package: "swift-markdown"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftParserDiagnostics", package: "swift-syntax"),
.target(
name: "SwiftFormat",
dependencies: [
.product(name: "Markdown", package: "swift-markdown")
]
+ swiftSyntaxDependencies([
"SwiftOperators", "SwiftParser", "SwiftParserDiagnostics", "SwiftSyntax", "SwiftSyntaxBuilder",
]),
exclude: ["CMakeLists.txt"]
),
.target(
name: "_SwiftFormatTestSupport",
dependencies: omittingExternalDependenciesIfNecessary([
"SwiftFormat",
.product(name: "SwiftOperators", package: "swift-syntax"),
exclude: ["CMakeLists.txt"]
),
.target(
name: "_SwiftFormatTestSupport",
dependencies: [
"SwiftFormat"
]
+ swiftSyntaxDependencies([
"SwiftOperators", "SwiftParser", "SwiftParserDiagnostics", "SwiftSyntax", "SwiftSyntaxBuilder",
])
),
.plugin(
name: "Format Source Code",
capability: .command(
intent: .sourceCodeFormatting(),
permissions: [
.writeToPackageDirectory(reason: "This command formats the Swift source files")
]
),
dependencies: [
.target(name: "swift-format")
],
path: "Plugins/FormatPlugin"
),
.plugin(
name: "Lint Source Code",
capability: .command(
intent: .custom(
verb: "lint-source-code",
description: "Lint source code for a specified target."
)
),
dependencies: [
.target(name: "swift-format")
],
path: "Plugins/LintPlugin"
),
.executableTarget(
name: "generate-swift-format",
dependencies: [
"SwiftFormat"
),
.plugin(
name: "Format Source Code",
capability: .command(
intent: .sourceCodeFormatting(),
permissions: [
.writeToPackageDirectory(reason: "This command formats the Swift source files")
]
),
.executableTarget(
name: "swift-format",
dependencies: omittingExternalDependenciesIfNecessary([
"_SwiftFormatInstructionCounter",
"SwiftFormat",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
]),
exclude: ["CMakeLists.txt"],
linkerSettings: swiftformatLinkSettings
dependencies: [
.target(name: "swift-format")
],
path: "Plugins/FormatPlugin"
),
.plugin(
name: "Lint Source Code",
capability: .command(
intent: .custom(
verb: "lint-source-code",
description: "Lint source code for a specified target."
)
),
dependencies: [
.target(name: "swift-format")
],
path: "Plugins/LintPlugin"
),
.executableTarget(
name: "generate-swift-format",
dependencies: [
"SwiftFormat"
]
),
.executableTarget(
name: "swift-format",
dependencies: [
"_SwiftFormatInstructionCounter",
"SwiftFormat",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
] + swiftSyntaxDependencies(["SwiftParser", "SwiftSyntax"]),
exclude: ["CMakeLists.txt"],
linkerSettings: swiftformatLinkSettings
),

.testTarget(
name: "SwiftFormatPerformanceTests",
dependencies: omittingExternalDependenciesIfNecessary([
"SwiftFormat",
"_SwiftFormatTestSupport",
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
])
),
.testTarget(
name: "SwiftFormatTests",
dependencies: omittingExternalDependenciesIfNecessary([
"SwiftFormat",
"_SwiftFormatTestSupport",
.product(name: "Markdown", package: "swift-markdown"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
])
),
]
.testTarget(
name: "SwiftFormatPerformanceTests",
dependencies: [
"SwiftFormat",
"_SwiftFormatTestSupport",
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
] + swiftSyntaxDependencies(["SwiftParser", "SwiftSyntax"])
),
.testTarget(
name: "SwiftFormatTests",
dependencies: [
"SwiftFormat",
"_SwiftFormatTestSupport",
.product(name: "Markdown", package: "swift-markdown"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
]
),
]

if buildOnlyTests {
products = []
targets = targets.compactMap { target in
guard target.isTest || target.name == "_SwiftFormatTestSupport" else {
return nil
}
target.dependencies = target.dependencies.filter { dependency in
if case .byNameItem(name: "_SwiftFormatTestSupport", _) = dependency {
return true
}
return false
}
return target
}
}

let package = Package(
name: "swift-format",
platforms: [
.macOS("12.0"),
.iOS("13.0"),
],
products: products,
dependencies: dependencies,
targets: targets
)

func swiftSyntaxDependencies(_ names: [String]) -> [Target.Dependency] {
if buildDynamicSwiftSyntaxLibrary {
return [.product(name: "_SwiftSyntaxDynamic", package: "swift-syntax")]
} else {
return names.map { .product(name: $0, package: "swift-syntax") }
}
}

// MARK: - Parse build arguments

func hasEnvironmentVariable(_ name: String) -> Bool {
Expand All @@ -147,26 +175,26 @@ var installAction: Bool { hasEnvironmentVariable("SWIFTFORMAT_CI_INSTALL") }
/// remote dependency.
var useLocalDependencies: Bool { hasEnvironmentVariable("SWIFTCI_USE_LOCAL_DEPS") }

var omitExternalDependencies: Bool { hasEnvironmentVariable("SWIFTFORMAT_OMIT_EXTERNAL_DEPENDENCIES") }
/// Build only tests targets and test support modules.
///
/// This is used to test swift-format on Windows, where the modules required for the `swift-format` executable are
/// built using CMake. When using this setting, the caller is responsible for passing the required search paths to
/// the `swift test` invocation so that all pre-built modules can be found.
var buildOnlyTests: Bool { hasEnvironmentVariable("SWIFTFORMAT_BUILD_ONLY_TESTS") }

func omittingExternalDependenciesIfNecessary(
_ dependencies: [Target.Dependency]
) -> [Target.Dependency] {
guard omitExternalDependencies else {
return dependencies
}
return dependencies.filter { dependency in
if case .productItem(_, let package, _, _) = dependency {
return package == nil
}
return true
}
/// Whether swift-syntax is being built as a single dynamic library instead of as a separate library per module.
///
/// This means that the swift-syntax symbols don't need to be statically linked, which alles us to stay below the
/// maximum number of exported symbols on Windows, in turn allowing us to build sourcekit-lsp using SwiftPM on Windows
/// and run its tests.
var buildDynamicSwiftSyntaxLibrary: Bool {
hasEnvironmentVariable("SWIFTSYNTAX_BUILD_DYNAMIC_LIBRARY")
}

// MARK: - Dependencies

var dependencies: [Package.Dependency] {
if omitExternalDependencies {
if buildOnlyTests {
return []
} else if useLocalDependencies {
return [
Expand Down
Loading