diff --git a/Package.swift b/Package.swift index 1f853d81f..251a6cae1 100644 --- a/Package.swift +++ b/Package.swift @@ -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 { @@ -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 [