I have 2 dependencies in my project libevent
and libressl
. Both of which are installed locally ( respectively under /usr/local/include
and /usr/local/opt/libressl/include
)
What I am looking for to achieve is for SPM to automatically understand to search in those directories.
I know I can pass flags to swift build to achieve this; but my ultimate goal is that I can properly generate xcode projects from the command line without having to constantly add custom build flags in Xcode.
I'm pretty sure it is possible, since I do not have to enter the custom settings for PostgreSQL.
Swift-tools version is at 4.0.x
Package.swift for reference:
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "CEvent",
providers: [
.brew(["libevent"]),
.apt(["libevent-dev"])
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "CEvent",
targets: ["CEvent"]),
],
dependencies: [
],
targets: [
.target(
name: "CEvent",
dependencies: []
),
]
)
Module map:
module CEvent [system] {
header "shim.h"
link "event"
export *
}
And my current build script ( build.sh ):
#!/usr/local/bin/fish
swift build -Xcc -O0 -Xcc -fblocks -Xswiftc -lbcrypt -Xswiftc -I/usr/local/include -Xswiftc -L/usr/local/lib -Xswiftc -ltls -Xswiftc -lcrypto -Xswiftc -lssl -Xswiftc -L/usr/local/opt/postgresql/lib -Xswi$
As for the reason that I want this. If I add/update/remove dependencies in swift I want to generate a new xcode project, and not have to fix its settings on respective build machines; as well as apt/ubuntu /usr/lib instead.
What you've found out, and documented in your answer, is a good start but not the full story. Yes, SwiftPM uses pkg-config
to determine where certain libraries are installed. Yes, SwiftPM uses the pkgConfig
name which it'll pass on to pkg-config
. However the search paths are a bit more involved. On macOS it uses the following list as a base search path:
/usr/local/lib/pkgconfig
/usr/local/share/pkgconfig
/usr/lib/pkgconfig
/usr/share/pkgconfig
PKG_CONFIG_PATH
environment variable
However SwiftPM doesn't use the pkg-config
command, but instead parses .pc
files directly. By setting the pkgConfig
parameter on your package, it knows what filename to look for in the paths listed above. And, for the example in your answer, the story stops here. If there's a libevent.pc
file found it parses that file, and any flags returned are passed on to the compiler and linker.
However if you were to define package providers, e.g.:
providers: [
.Brew("libsodium"),
.Apt("libsodium-dev")
]
Then SwiftPM adds additional search paths depending on the package provider for the platform it is building for. Continuing the example of macOS, SwiftPM will run brew --prefix
. If this returns a path, the following path is added as a additional search path:
[brewPrefix]/opt/[packageName]/lib/pkgconfig
In my example of libsodium
, SwiftPM is now able to infer the location of the library without requiring brew link
or symlinks at all. In my verbose build output it lists the libsodium
library path in my cellar: -L/usr/local/Cellar/libsodium/1.0.11/lib
.
Alright so the thing I ignored from analysing other projects ( IBM-Swift/CLibpq in particular ) seems to be making use of the tool pkg-config
which is not something I personally ever touched before.
pkg-config looks in /usr/lib/pkgconfig
/usr/share/pkgconfig
and the local variants for config files used in during the build process.
Inside Package.swift, after the name
parameter you need to insert something for example:
let package = Package(
name: "CEvent",
pkgConfig: "libevent",
Some caveats I discovered with this:
- The bcrypt library I am using does not have a full fletched install or build inside the makefile so I compiled it using the new options found in swift4 PM instead found here: BCrypt example on github and the Swift docs for more help here: SPM API Redesign
- LibreSSL found in Homebrew will not install its pkgconfig on the system; so it is easiest or in my eyes best maintenance wise to either manually add it or to compile LibreSSL-portable from source.
Overall great learning experience for me today.