@@ -7134,5 +7134,176 @@ struct PackageCommandTests {
71347134 expectNoDiagnostics ( observability. diagnostics)
71357135 }
71367136 }
7137+
7138+ @Test ( arguments: getBuildData ( for: SupportedBuildSystemOnAllPlatforms) )
7139+ func commandPluginDynamicDependencies(
7140+ buildData: BuildData
7141+ ) async throws {
7142+ try await withKnownIssue {
7143+ try await testWithTemporaryDirectory { tmpPath in
7144+ // Create a sample package with a command plugin that has a dynamic dependency.
7145+ let packageDir = tmpPath. appending ( components: " MyPackage " )
7146+ try localFileSystem. writeFileContents (
7147+ packageDir. appending ( components: " Package.swift " ) ,
7148+ string:
7149+ """
7150+ // swift-tools-version: 6.0
7151+ // The swift-tools-version declares the minimum version of Swift required to build this package.
7152+
7153+ import PackageDescription
7154+
7155+ let package = Package(
7156+ name: " command-plugin-dynamic-linking " ,
7157+ products: [
7158+ // Products can be used to vend plugins, making them visible to other packages.
7159+ .plugin(
7160+ name: " command-plugin-dynamic-linking " ,
7161+ targets: [ " command-plugin-dynamic-linking " ]),
7162+ ],
7163+ dependencies: [
7164+ .package(path: " LocalPackages/DynamicLib " )
7165+ ],
7166+ targets: [
7167+ // Targets are the basic building blocks of a package, defining a module or a test suite.
7168+ // Targets can depend on other targets in this package and products from dependencies.
7169+ .executableTarget(
7170+ name: " Core " ,
7171+ dependencies: [
7172+ .product(name: " DynamicLib " , package: " DynamicLib " )
7173+ ]
7174+ ),
7175+ .plugin(
7176+ name: " command-plugin-dynamic-linking " ,
7177+ capability: .command(intent: .custom(
7178+ verb: " command_plugin_dynamic_linking " ,
7179+ description: " prints hello world "
7180+ )),
7181+ dependencies: [
7182+ " Core "
7183+ ]
7184+ )
7185+ ]
7186+ )
7187+ """
7188+ )
7189+ try localFileSystem. writeFileContents (
7190+ packageDir. appending ( components: " Sources " , " Core " , " Core.swift " ) ,
7191+ string:
7192+ """
7193+ import DynamicLib
7194+
7195+ @main
7196+ struct Core {
7197+ static func main() {
7198+ let result = dynamicLibFunc()
7199+ print(result)
7200+ }
7201+ }
7202+ """
7203+ )
7204+ try localFileSystem. writeFileContents (
7205+ packageDir. appending ( components: " Plugins " , " command-plugin-dynamic-linking.swift " ) ,
7206+ string:
7207+ """
7208+ import PackagePlugin
7209+ import Foundation
7210+
7211+ enum CommandError: Error, CustomStringConvertible {
7212+ var description: String {
7213+ String(describing: self)
7214+ }
7215+
7216+ case pluginError(String)
7217+ }
7218+
7219+ @main
7220+ struct command_plugin_dynamic_linking: CommandPlugin {
7221+ // Entry point for command plugins applied to Swift Packages.
7222+ func performCommand(context: PluginContext, arguments: [String]) async throws {
7223+ let tool = try context.tool(named: " Core " )
7224+
7225+ let process = try Process.run(tool.url, arguments: arguments)
7226+ process.waitUntilExit()
7227+
7228+ if process.terminationReason != .exit || process.terminationStatus != 0 {
7229+ throw CommandError.pluginError( " \\ (tool.name) failed " )
7230+ } else {
7231+ print( " Works fine! " )
7232+ }
7233+ }
7234+ }
7235+
7236+ #if canImport(XcodeProjectPlugin)
7237+ import XcodeProjectPlugin
7238+
7239+ extension command_plugin_dynamic_linking: XcodeCommandPlugin {
7240+ // Entry point for command plugins applied to Xcode projects.
7241+ func performCommand(context: XcodePluginContext, arguments: [String]) throws {
7242+ print( " Hello, World! " )
7243+ }
7244+ }
7245+
7246+ #endif
7247+ """
7248+ )
7249+
7250+ try localFileSystem. writeFileContents (
7251+ packageDir. appending ( components: " LocalPackages " , " DynamicLib " , " Package.swift " ) ,
7252+ string:
7253+ """
7254+ // swift-tools-version: 6.0
7255+ // The swift-tools-version declares the minimum version of Swift required to build this package.
7256+
7257+ import PackageDescription
7258+
7259+ let package = Package(
7260+ name: " DynamicLib " ,
7261+ products: [
7262+ // Products define the executables and libraries a package produces, making them visible to other packages.
7263+ .library(
7264+ name: " DynamicLib " ,
7265+ type: .dynamic,
7266+ targets: [ " DynamicLib " ]),
7267+ ],
7268+ targets: [
7269+ // Targets are the basic building blocks of a package, defining a module or a test suite.
7270+ // Targets can depend on other targets in this package and products from dependencies.
7271+ .target(
7272+ name: " DynamicLib " ),
7273+ .testTarget(
7274+ name: " DynamicLibTests " ,
7275+ dependencies: [ " DynamicLib " ]
7276+ ),
7277+ ]
7278+ )
7279+ """
7280+ )
7281+
7282+ try localFileSystem. writeFileContents (
7283+ packageDir. appending ( components: " LocalPackages " , " DynamicLib " , " Sources " , " DynamicLib.swift " ) ,
7284+ string:
7285+ """
7286+ // The Swift Programming Language
7287+ // https://docs.swift.org/swift-book
7288+
7289+ public func dynamicLibFunc() -> String {
7290+ return " Hello from DynamicLib! "
7291+ }
7292+ """
7293+ )
7294+
7295+ let ( stdout, _) = try await execute (
7296+ [ " plugin " , " command_plugin_dynamic_linking " ] ,
7297+ packagePath: packageDir,
7298+ configuration: buildData. config,
7299+ buildSystem: buildData. buildSystem,
7300+ )
7301+
7302+ #expect( stdout. contains ( " Works fine! " ) )
7303+ }
7304+ } when: {
7305+ ( ProcessInfo . hostOperatingSystem == . windows && buildData. buildSystem == . swiftbuild) || ( ProcessInfo . hostOperatingSystem == . linux && buildData. buildSystem == . swiftbuild)
7306+ }
7307+ }
71377308 }
71387309}
0 commit comments