arik
arik

Reputation: 29320

Swift Package Manager link shared archive library on MacOS

I have a swift package manager library with multiple targets and one product.

Its Package.swift looks something like this:

let package = Package(
    name: "FooPackage",
    products: [
        .library(
            name: "FooLibrary",
            targets: ["FooLibrary"]),
    ],
    dependencies: [],
    targets: [
        .target(name: "FooHeaders"),
        .target(
            name: "FooLibrary",
            dependencies: [
                "FooHeaders"
            ],
            path: nil,
            exclude: [],
            sources: nil,
            resources: nil,
            publicHeadersPath: "include",
            cSettings: nil,
            cxxSettings: nil,
            swiftSettings: nil,
            linkerSettings: [
                .linkedLibrary("/path/to/libfoo.a")
            ]
        ),
        .testTarget(
            name: "FooTests",
            dependencies: [
                "FooHeaders",
                "FooLibrary"
            ],
            path: nil,
            exclude: [],
            sources: nil,
            cSettings: nil, cxxSettings: nil, swiftSettings: nil,
            linkerSettings: nil)
    ]
)

I also have a directory structure that looks like this:

Now my issue is that whenever I run swift test, I get the following error message on Mac:

Building for debugging...
ld: library not found for -l/path/to/libfoo.a
[0/1] Linking FooTests
error: fatalError

Note that I specify the path to libfoo.a from root. Oddly enough, running swift build does work on Mac, though it seems that that is merely a compilation step, and does not do any linking.

However, when I compile the shared library on a Linux machine, be it physical or inside Docker, with everything else being exactly equal, there, swift test does work. That seems to be the case on both Debian and Ubuntu; I haven't tried testing other operating systems yet.

What could be going wrong, and what am I doing wrong? I have looked at a bunch of similar posts on StackOverflow, though nobody appears to have their project in a state where the compilation and running actually does work – just not on Mac. I would also like to stress that I am not using Xcode; instead, all of this is compiled straight from the command line.

Also, if that's any help, the shared library is compiled from a Rust project. I simply run cargo build and copy the library inside target/debug into the Libraries folder in my project, whereto the path is specified in Package.swift.

Some things I tried doing was using the same linker settings in both the standard target, as well as the test target. I also tried using the .dylib extension on Mac instead of .a (cargo build generates both), as well as removing the file extension altogether, and I have also tried various experiments with specifying the path relative to the root folder of the project, and various folders within it. So far, all to no avail.

Upvotes: 1

Views: 631

Answers (1)

arik
arik

Reputation: 29320

I believe I have figured it out, and the solution is as follows.

In Package.swift, add this snippet in the beginning:

var linkerSettings: [PackageDescription.LinkerSetting] = [.linkedLibrary("/path/to/libfoo.a")]
#if os(macOS)
    linkerSettings = [
        .unsafeFlags(["-L/path/to/"]),
        .linkedLibrary("foo")
    ]
#endif

And then, where it used to say

linkerSettings: [
    .linkedLibrary("/path/to/libfoo.a")
]

replace that code with

linkerSettings: linkerSettings

instead.

Upvotes: 1

Related Questions