At least since WWDC'19, many devs have been turning their former Cocoapods into full Swift Packages thanks to the SPM being integrated into Xcode. My current implementation issue is the following: I'm migrating the Fuzi Pod from Cocoapods to SPM (see Adding support for Swift Package Manager by thebluepotato · Pull Request #101 · cezheng/Fuzi · GitHub). This package wraps libxml2
to provide an excellent HTML parser for Swift. To make things simple, I create a Package with a Fuzi
target with the following:
.target(name: "Fuzi",
path: "Sources",
cSettings: [.headerSearchPath("$(SDKROOT)/usr/include/libxml2")],
linkerSettings: [.linkedLibrary("xml2")]
)
This worked up until Xcode 11b4 because it did not yet enforce the .headerSearchPath
to be exclusively relative. After that, it seemed impossible to point to libxml2
in iOS projects because $(SDKROOT)
could not be used anymore. It goes without saying that all unsafe
options were looked at but not considered since Xcode won't even look at packages using them.
My next idea was using a .systemLibrary
target. For context, the SPM PackageDescription has been updated for Swift 5/5.1 as well, including changes to how "System libraries" should be declared but this has not followed the new availability of SPM for iOS projects. Indeed, Usage.md still refers to system packages which have been deprecated some time ago (swift-package-manager/Usage.md at main · apple/swift-package-manager · GitHub). In the description for PackageDescription, the .systemLibrary
target type is referred to but just as the system packages of yore, require to be installed via homebrew (swift-package-manager/PackageDescription.md at main · apple/swift-package-manager · GitHub). This makes no sense on non-macOS or Linux platforms. And it does not make any sense either that such system libraries should be nearly inaccessible under iOS. My newest try is having that target:
.systemLibrary(
name: "libxmlFuzi",
path: "Module")
Of course the main Fuzi
target depends on libxmlFuzi
. The Module folder contains this modulemap:
module libxmlFuzi [system] {
link "xml2"
umbrella header "libxml2-fuzi.h"
export *
module * { export * }
}
And the following umbrella header:
#import <libxml2/libxml/xmlreader.h>
#import <libxml2/libxml/xpath.h>
#import <libxml2/libxml/xpathInternals.h>
#import <libxml2/libxml/HTMLparser.h>
#import <libxml2/libxml/HTMLtree.h>
My question to the Swift community is the following: how can I possibly get this to build and be used in other projects? It did build at random once or twice, but hasn't since, and never built when include in another Package/project. Any help is greatly appreciated!
EDIT: To clarify, the build errors when building Fuzi are the following, for all Swift files contained in the Package:
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "libxml/HTMLparser.h"
^
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.sdk/usr/include/libxml2/libxml/HTMLparser.h:15:10: error: 'libxml/xmlversion.h' file not found
#include <libxml/xmlversion.h>
^
/Users/xxx/Documents/Projects/Fuzi/Sources/Document.swift:23:8: error: could not build Objective-C module 'libxml2'
import libxml2
^