Менеджер пакетов Swift: как добавить локальную общую библиотеку в качестве зависимости для нескольких исполняемых файлов?

У меня есть простое приложение gRPC, клиент и сервер. Оба полагаются на сгенерированные привязки swift-grpc. Для простоты, когда я копирую общие файлы один раз в папку клиента и второй раз в папку сервера, Swift создает и запускает оба. По понятным причинам я хочу разделить общие файлы на общую библиотеку, серверную библиотеку и клиентскую библиотеку, чтобы импортировать в клиент только общие и специфичные для клиента библиотеки.

Начиная с моей общей библиотеки под названием DmxLib, я не могу понять файл Package.swift. По сути, в документах говорится: создайте библиотеку, добавьте ее как зависимость, и все готово. Когда я это делаю, сборка Swift не работает, говоря, что импортированных файлов нет. Когда я добавляю локальные файлы из папки DmXLib в зависимости продукта, он говорит мне, что файл не может быть найден.

Редактор — VSCode, а платформа — Ubuntu 20.04 с Swift 5.3, без XCode.

Как правильно объявить общую локальную библиотеку, которую можно импортировать и использовать как на клиенте, так и на сервере?

Мое исходное дерево выглядит так

И мой файл Package.swift

        // swift-tools-version:5.2
        // The swift-tools-version declares the minimum version of Swift required to build this package.

        import PackageDescription

        let package = Package(
            name: "dmx-db",
            products: [
                .executable(name: "DmxServer", targets: ["DmxServer"]),
                .executable(name: "DmxClient", targets: ["DmxClient"]),
                // This lib will be imported into both, client and server. 
                .library(name: "DmxLib", targets: ["DmxLib"]),
            ],  
            dependencies: [
                .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.21"),
                .package(url: "https://github.com/codewinsdotcom/PostgresClientKit", from: "1.0.0"),
                .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "1.0.0-alpha.5"),
                // Why do I have to declare local files as dependencies???
                .package(path: "../Sources/DmxLib/datasource.grpc.swift")
                ],
            //
            targets: [
                .target(name: "DmxLib", dependencies: [
                    "datasource.grpc.swift" 
                ] ),

                .target(name: "DmxServer", dependencies: [
                    "DmxLib", 
                    .product(name: "GRPC", package: "grpc-swift"),
                    .product(name: "PostgresClientKit", package: "PostgresClientKit"), 
                    .product(name: "Lifecycle", package: "swift-service-lifecycle"), 
                    ]),

                .target(name: "DmxClient", dependencies: [
                    "DmxLib",
                    .product(name: "GRPC", package: "grpc-swift"),
                ]),
            ] 
        )

1 729
2

Ответы:

Решено

Это должно сделать это. Вам не нужно добавлять «зависимость» к цели, где все источники находятся на вашем локальном компьютере.

// swift-tools-version:5.3

import PackageDescription

let package = Package(
    name: "dmx-db",
    products: [
        .executable(name: "DmxServer", targets: ["DmxServer"]),
        .executable(name: "DmxClient", targets: ["DmxClient"]),
                // This lib will be imported into both, client and server. 
        .library(name: "DmxLib", targets: ["DmxLib"]),
    ],
    dependencies: [
        .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0-alpha.21"),
        .package(url: "https://github.com/codewinsdotcom/PostgresClientKit", from: "1.0.0"),
        .package(url: "https://github.com/swift-server/swift-service-lifecycle.git", from: "1.0.0-alpha.5"),
    ],
    targets: [
        .target(name: "DmxServer", dependencies: [
            "DmxLib", 
            .product(name: "GRPC", package: "grpc-swift"),
            .product(name: "PostgresClientKit", package: "PostgresClientKit"), 
            .product(name: "Lifecycle", package: "swift-service-lifecycle"), 
        ]),
        .target(name: "DmxClient", dependencies: [
            "DmxLib",
            .product(name: "GRPC", package: "grpc-swift"),
        ]),
        .target(name: "DmxLib", dependencies: []),
    ]
)

Для этого требуется, чтобы у вас был каталог Sources в корневом каталоге вашего пакета, а внутри него у вас были три папки с именами DmxLib, DmxClient и DmxServer соответственно.

Примечание. На самом деле я обновил swift-tools-version до 5.3, потому что я скопировал и изменил это из одного из моих проектов, но я думаю, что он должен работать с swift-tools-version 5.2.


для LOCAL мы страдаем из-за плохого Xcode UI/UX..

(в моем примере у меня есть SPM, «LocalSPMLib» и потребительское приложение, «LocalSPMConsumerApp»)

Вы можете сделать таким образом:

  1. добавьте SPM как обычно, добавляя через меню SPM или перетаскивая в проект.

он добавит в проект, но не будет работать... Должен отображаться в двоичных файлах, но НЕ ;(

  1. RE-добавить как бинарную библиотеку (ужасно... но работает...)

Теперь вы можете вызывать:

import XCTest
import LocalSPMLib

@testable import LocalSPMConsumerApp

class LocalSPMConsumerAppTests: XCTestCase {

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        XCTAssertEqual(LocalSPMLib().version, 1)

    }

}