hassila
(Joakim Hassila)
1
While starting to play around with library evolution and binary targets, I've run into a very strange behaviour.
I have a framework (which is built with resiliency with SPM) and a trivial client (to start verifying that things are built as expected, ensuring I can use @unknown default:)
It works when I run the SPM package in Xcode, but not from the command line - then it can't find the .xcframework / module for import.
I've created a minimised reproducer that can be run following these steps:
gh repo clone ordo-one/prototype-library-evolution
gh repo clone ordo-one/prototype-library-evolution-client
cd prototype-library-evolution
swift build
xcodebuild -create-xcframework -library .build/arm64-apple-macosx/debug/libPrototypeLibraryEvolution.dylib -output PrototypeLibraryEvolution.xcframework
cd ../prototype-library-evolution-client
swift run
swift run will fail with:
hassila@max ~/G/prototype-library-evolution-client (main)> swift build
Building for debugging...
**/Users/hassila/GitHub/prototype-library-evolution-client/Sources/PrototypeLibraryEvolutionClient/PrototypeLibraryEvolutionClient.swift:2:8:** **error:** **no such module 'PrototypeLibraryEvolution'**
import PrototypeLibraryEvolution
But, if one then opens Package.swift and runs it in Xcode (14 b5) - things work as expected!
So any ideas what can cause this to not work from the command line?!
This is with Xcode 14b5.
hassila@max ~/G/prototype-library-evolution-client (main) [1]> swift --version
swift-driver version: 1.62.3 Apple Swift version 5.7 (swiftlang-5.7.0.123.8 clang-1400.0.29.50)
Target: arm64-apple-macosx12.0
NeoNacho
(Boris Buegling)
2
Not super familiar with building XCFrameworks from loose dylibs, but how does the resulting PrototypeLibraryEvolution.xcframework look like? From the command, I would assume it does not actually contain the .swiftmodule/.swiftinterface
hassila
(Joakim Hassila)
3
Yep, it does:
hassila@max ~/t/prototype-library-evolution-client (main) [1]> ls ../prototype-library-evolution/PrototypeLibraryEvolution.xcframework/macos-arm64/
PrototypeLibraryEvolution.swiftdoc PrototypeLibraryEvolution.swiftinterface libPrototypeLibraryEvolution.dylib*
hassila@max ~/t/prototype-library-evolution-client (main)> more ../prototype-library-evolution/PrototypeLibraryEvolution.xcframework/macos-arm64/PrototypeLibraryEvolution.swiftinterface
// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.7 (swiftlang-5.7.0.123.8 clang-1400.0.29.50)
// swift-module-flags: -target arm64-apple-macosx10.13 -enable-objc-interop -enable-library-evolution -swift-version 5 -Onone -module-name PrototypeLibraryEvolution
// swift-module-flags-ignorable: -user-module-version 1.0
import Swift
import _Concurrency
import _StringProcessing
public enum PrototypeLibraryEvolutionTest : Swift.Int {
case a
case b
case c
case d
public init?(rawValue: Swift.Int)
public typealias RawValue = Swift.Int
public var rawValue: Swift.Int {
get
}
}
public func getEnum() -> PrototypeLibraryEvolution.PrototypeLibraryEvolutionTest
extension PrototypeLibraryEvolution.PrototypeLibraryEvolutionTest : Swift.Equatable {}
extension PrototypeLibraryEvolution.PrototypeLibraryEvolutionTest : Swift.Hashable {}
extension PrototypeLibraryEvolution.PrototypeLibraryEvolutionTest : Swift.RawRepresentable {}
hassila@max ~/t/prototype-library-evolution-client (main)>
hassila
(Joakim Hassila)
4
The weird thing is really that opening the package in Xcode (open Package.swift) and it builds/run fine, quite curious.
hassila
(Joakim Hassila)
5
(for completeness, I also had it working with a minimal directory containing just the Package.swift + the .xcframework - same thing there, worked in Xcode, but not from CLI)
NeoNacho
(Boris Buegling)
6
Ah, I guess -create-xcframework must have some smarts where it automatically finds the module definition.
Could you also share the contents of the Info.plist?
hassila
(Joakim Hassila)
7
Certainly;
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AvailableLibraries</key>
<array>
<dict>
<key>LibraryIdentifier</key>
<string>macos-arm64</string>
<key>LibraryPath</key>
<string>libPrototypeLibraryEvolution.dylib</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>macos</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>
NeoNacho
(Boris Buegling)
8
Just from reading the code quickly, I wonder if this might be the problem swift-package-manager/BuildPlan.swift at main · apple/swift-package-manager · GitHub, we're only passing -I for any HeadersPath, but the XCFramework does not set one.
hassila
(Joakim Hassila)
9
So Xcode does use a different implementation? (As it’s found there?)
So does the .xcframework creation tool miss to add that, or is it an issue in SPM in that case?
Anything I can try to nail it down?
NeoNacho
(Boris Buegling)
10
Yes, packages get build with Xcode's own build system there, which is entirely different. The Build module is only used by SwiftPM on the commandline.
Since Xcode pretty much defines how an XCFramework looks like, I would say this needs to be fixed in SwiftPM.
1 Like
hassila
(Joakim Hassila)
11
Ok, thanks! I’ll file an issue with the reproducer then on swiftpm.
hassila
(Joakim Hassila)
12
For future Googlers, the issues is here:
1 Like