`SystemLibrary` Target basically "Not for Cross-Compiling"?

hi!

im trying to use some c libraries in a shared ios/mac (and potentially linux) app but after adding a systemLibrary target (libmad) with .brew(["libmad"]) in the package.swift, i noticed that if i used any functions there are linkage errors on the ios build (mac links and runs fine).

its probably obvious since what's being linked as a static library, but i had some hope that since it should be the same darwin/c library it might link and work...

am i correct in assuming that systemLibrary is basically not designed for cross-compiling (a.k.a mac → ios)?

maybe a workaround would be to provide ios specific builds for the c library via homebrew?

(i understand there is also the xcframework route but the implication there is i need to make a custom build of the c library and maintain that...:sweat_drops:)

i wonder what other options might be out there or if there is something obvious i am missing......

here's my target definition for example
    targets: [
        .executableTarget(
            name: "AppModule",
            dependencies: [
                "libmad"
            ],
            path: "./app"
        ),
        .systemLibrary(
            name: "libmad",
            path: "./libmad",
            pkgConfig: "mad",
            providers: [
                .brew([
                    "libmad"
                ]
            )
        ]
        )
    ]

systemLibrary is orthogonal to cross-compilation. It only assumes that a given library exists for the target triple, has corresponding declarations available (usually via headers), and can be linked with. If such library doesn't exist on iOS, then you won't be able to cross-compile to iOS with that systemLibrary in your package graph.

That doesn't preclude you from using systemLibrary when cross-compiling to Linux or any other platform that has a Swift SDK for that platform that has the corresponding library.

2 Likes

Yes and no, you can use systemLibrary to build for any platform for which you can provide system packages using brew, apt, etc., but obviously some platforms like iOS don't have such system packages. I'm able to use the apt provider to provide Android apt packages when cross-compiling SwiftPM itself from linux to Android using SwiftPM, by specifying a --pkg-config-path where it can get info on the Termux apt packages like SQLite3, as part of cross-compiling a native Swift toolchain for Android.

Since iOS probably doesn't have such system packages, you'll probably have to maintain a xcframework like you say.

2 Likes

That doesn't preclude you from using systemLibrary when cross-compiling to Linux or any other platform that has a Swift SDK for that platform that has the corresponding library.

thanks for the reply

yea, i guess the real issue is not that .systemLibrary itself is "desktop oriented" but that homebrew is basically "the package manager for macos" and as such doesn't provide for example libmad-ios etc (which makes sense i guess).

I'm able to use the apt provider to provide Android apt packages when cross-compiling SwiftPM itself from linux to Android using SwiftPM

that's pretty cool, i guess for my use case then its something of a limitation with homebew more than .systemLibrary in the end.

Since iOS probably doesn't have such system packages, you'll probably have to maintain a xcframework like you say.

yea... i wish i could avoid doing that since so many libraries have so many different build systems but it seems no other way for now... its too bad c doesn't have a unified build system like swift or rust

You can package libmad or whatever other library written in C or C++ as a SwiftPM package, assuming you have source code available for it. Then it will be built as a static library for whatever supported target platform you're building for, including iOS. In a way, SwiftPM can be a unified build system for C and C++, it's primarily library author's responsibility to add support for it though. But if you can fork and adapt it yourself, that should work.

1 Like

yes definitely, i think for each library i'd need to make sure that things like configure script etc run so proper header files are generated when necessary after updating the library... I've experimented a little with that with some success... but it's feels a bit brittle, but maybe in the end its the path of least resistance... (at least until i have to re-import the source when updating the library anyways)