I have a package (GitHub - dowobeha/Foma) that wraps a C library (foma/foma at master · mhulden/foma · GitHub). On my machines, this C library was installed by hand (using ./configure, make, make install) rather than through apt or brew. As such, there is no corresponding .pc file. The C library lives in /usr/local/lib.
In order to get my Foma package to compile, I started off writing a Makefile that passed -Xlinker -L/usr/local/lib to swift build. That worked.
But when I tried opening my package in XCode, XCode didn't know where to find the C library. So, in Package.swift, I modified the .target with linkerSettings: [LinkerSetting.unsafeFlags(["-Xlinker", "-L/usr/local/lib"])]),. That worked. Now my Foma project compiles cleanly in XCode.
But I need to have my Foma package serve as a dependency for another package of mine. In my other project, I added the dependency as .package(url: "GitHub - dowobeha/Foma", from: "0.0.7"),.
Create a package for the C library so that it can be depended on as a package. This is preferable because it'll be easier to use for clients and could work for platforms where there isn't really a place for external libraries to be installed, e.g. iOS.
Thanks. Eventually I do plan on doing the first option (making a package for the C library). But that will involve considerably more effort than just wrapping the C library, and so right now I need a solution that works with the C library wrapper.
In the Package.swift for my Foma package that wraps the C library, I am already doing declaring a system library. But as far as I can tell, .systemLibrary has no mechanism for specifying a path. There is a path argument, but the docs state:
"The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, such as [PackageRoot]/Sources/[TargetName] . Do not escape the package root; that is, values like ../Foo or /Foo are invalid."
And indeed, when I try doing .systemLibrary(name: "CFomaSystem", path: "/usr/local/lib"), XCode complains that "target path '/usr/local/lib' is not supported. It should be relative to the package root.
I am concerned that what I am trying to do is currently impossible. If so, that's a real shame. There should be some supported mechanism for this use case. It is especially important in terms of Swift on Linux. The Swift team is doing great work in expanding the number of supported distros. That is fantastic.
I hope that I'm missing something, and there is a way to accomplish what I'm trying to do.
The other option is to create a .pc file. This is a good idea anyway, especially on Linux where png-config is the standard way to locate a library and provide instructions on how to use it on Linux. However:
That's because the path doesn't do what you want it to do. That path points to somewhere inside the package where you provide a modulemap and potentially a separate header file, not to where the system library itself lives.
This corresponds to the path Sources/CInotify. In that directory are a module.modulemap and a .h. The module.modulemap defines a Clang module for the given target. It basically just says "import the header file in this directory". That header file (cinotify.h) then imports the relevant headers.
Given that your library is apparently stored in /usr/local/lib, it will be found on the standard linker search path. As a result, you should only have to replicate what this user has done for inotify for your library.
Thanks. I'll do some investigation to see if it's feasible to create a .pc file.
The example with Harness and CInotify is helpful. But after looking into it, I believe that still assumes that the C library inotify is in /usr/lib, not /usr/local/lib. I have the following:
.systemLibrary(
name: "CFomaSystem"),
and in Sources/CFomaSystem/module.modulemap, I have tried this:
Yup, so I reproduce this behaviour. I tried an equivalent build with c-ares (just the first thing I spotted in /usr/local/lib on my machine) and I got the same issue with failing to find the library. Seems like for some reason SwiftPM ignores the default build path. @NeoNacho any ideas there?
Are you sure /usr/local/lib is on the linker default search path? If the OP has to provide -L/usr/local/lib as a linker flag, it would seem that that may not be the case. Can't be ignoring search path completely since the system libraries are being linked without specifying /usr/lib. That also squares with my experience with Xcode at least where /usr/local/lib is concerned.
On my machine ld -v 2 says /usr/local/lib is on the default search path. It is also on the default search path for clang, so yeah, it certainly should be.
I can also confirm that despite this fact, SPM does not link against my library that is in /usr/local/lib unless I explicitly provide -L/usr/local/lib.
We are always building using an SDK, which will end up passing -syslibroot to the linker. I think all default paths will be relative to that, so we are probably looking in /usr/local/lib, but not in the one on the host but the one in the SDK.
I'm not sure if it's a bug, but it was certainly unexpected for several folks on this thread, so would be great if you could file it. At the very least, this seems like something that should be documented.
@NeoNacho, I'm not sure I follow. What do you mean by an SDK?
While I might eventually deploy on iOS or macOS with a GUI, right now I'm developing for command-line only use on Linux and macOS. So in my case there is only one system - the one I'm coding on.
On macOS, /usr/include does not exist. /usr/lib contains only the libraries necessary for the operating system and supplied Apple applications. Most of the support expected by a developer actually resides in either: Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs,
As a long-time macOS user and long-time coder used to POSIX-style OSes, that is also fairly disturbing.
When developing programs for the command line, my first instinct is to assume that my programming language compiler will look in the standard locations, such as /usr/lib and /usr/local/lib, and the corresponding include/ subdirs.
If swiftc is instead looking somewhere else (like /Library/Developer/CommandLineTools/usr), that is very unexpected behavior. At a minimum, that behavior should be very prominently documented, as it will almost certainly confuse developers used to working on Linux and similar OSes.
/usr/local is included in the default search paths for both header and libraries, so that is there. Catalina is the first macOS that locked down parts of /usr (or /, for that matter), for security reasons. The compilers (clang/swiftc) do the appropriate mappings to all of the SDK /usr directories so that it looks like what would expect from a POSIX/Unix developer experience when using the compilers. There are compiler flags like -isystemroot that allow you to alter that convention, if you want.
It is a challenge when you want to look at a system header file outside of something like Xcode that follows the mappings.