schwa
(Jonathan Wight)
October 31, 2023, 6:36pm
1
(My project accompanying this post is here: GitHub - schwa/earcut-swift )
I am trying to wrap mapbox's earcut.hpp project (GitHub - mapbox/earcut.hpp: Fast, header-only polygon triangulation ) for Swift.
I would like to expose a single function in C++ that looks something like this to Swift:
template <typename N = uint32_t>
std::vector<N> earcut_swift_simd(const swift::array<swift::array<simd_float2>>& poly) {
...
}
The C++ targets should only need swift::array from swift and in theory need no other types or functions from my Swift. I'm purely exposing C++ to Swift.
I understand however, that I need a Swift target, compiled with swiftSettings: [.interoperabilityMode(.Cxx)]
that I can use to provide Swift types to C++. So I've done that. I then need to include it from C++ (like so… #include <earcut_bridge/earcut_bridge-Swift.h>
)…
However when I compile my project no earcut_bridge-Swift.h
header is generated for my target. If I check the .build directory I can see a module.modulemap file is created for my target, and that module map references the header. It looks like this:
module earcut_bridge {
header "/Users/schwa/Desktop/earcut-swift/.build/arm64-apple-macosx/debug/earcut_bridge.build/earcut_bridge-Swift.h"
requires objc
}
However no file exists at that path. And my import from C++ fails.
1 Like
schwa
(Jonathan Wight)
October 31, 2023, 6:42pm
2
So follow up questions.
This seems like it should work. Targets I add the CXX interop flag to should export headers that I can consume from C++ target. Right?
Also, it seems weird having to create a target when I do not need to expose my swift code to C++ - seems like there are quite a few projects with a similar need to mine - that just want to expose C++ functions (with a Swiftified API) to Swift. Is this feature potentially on a roadmap?
Alternatively I realise I can just use std::vector from Swift and pass my data into the API that way - however that does involve an extra copy of the data to from swift arrays to std::vectors… But at that point I could just use (say) CFArray from C++ potentially and just expose a C API…
1 Like
Alex_L
(Alex Lorenz)
October 31, 2023, 7:01pm
3
schwa:
I would like to expose a single function in C++ that looks something like this to Swift:
template <typename N = uint32_t>
std::vector<N> earcut_swift_simd(const swift::array<swift::array<simd_float2>>& poly) {
...
}
The C++ targets should only need swift::array from swift and in theory need no other types or functions from my Swift. I'm purely exposing C++ to Swift.
It's not yet possible to pass a Swift value type across the Swift -> C++ -> Swift boundary (only across the Swift -> C++ boundary), so I would recommend using a std::vector
instead as you mentioned in your second post. Right now only Swift class types can be passed across the Swift -> C++ -> Swift boundary transparently.
I understand however, that I need a Swift target, compiled with swiftSettings: [.interoperabilityMode(.Cxx)]
that I can use to provide Swift types to C++. So I've done that. I then need to include it from C++ (like so… #include <earcut_bridge/earcut_bridge-Swift.h>
)…
The Swift Package Manager does not yet provide support for using the generated header to use Swift APIs in C++. This is going to be addressed by SE0403: SE-0403: Package Manager Mixed Language Target Support .
3 Likes
schwa
(Jonathan Wight)
October 31, 2023, 7:27pm
4
OK thanks for the definitive answer.
Going to a std::vector based/copy approach and there are now two issues:
It seems that swiftSettings: [.interoperabilityMode(.Cxx)]
is viral. And every target that imports a target compiled with that flag needs to set it too. (Warning of the form: "Module 'earcut' was built with C++ interoperability enabled, but current compilation does not enable C++ interoperability"). Is this vitality intended? I tried to nip it off with @_implementationOnly on the C++ target but that didn't do the trick.
If I get passed that by adding in the flag I get a 100% reproducible crash at compile time. I'll post a JIRA but for now:
Stack dump:
0. Program arguments: /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-frontend -frontend -c -primary-file /Users/schwa/Desktop/earcut-swift/Sources/earcut/earcut_swift.swift -emit-dependencies-path /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.d -emit-const-values-path /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.swiftconstvalues -emit-reference-dependencies-path /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.swiftdeps -serialize-diagnostics-path /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.dia -target arm64-apple-ios12.0 -Xllvm -aarch64-use-tbi -enable-objc-interop -cxx-interoperability-mode=default -sdk /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk -I /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Products/Debug-iphoneos -I /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib -F /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Products/Debug-iphoneos/PackageFrameworks -F /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Products/Debug-iphoneos -F /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks -F /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/Developer/Library/Frameworks -no-color-diagnostics -enable-testing -g -module-cache-path /Users/schwa/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -swift-version 5 -enforce-exclusivity=checked -Onone -D SWIFT_PACKAGE -D DEBUG -D Xcode -serialize-debugging-options -package-name earcut_swift -const-gather-protocols-file /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_const_extract_protocols.json -empty-abi-descriptor -validate-clang-modules-once -clang-build-session-file /Users/schwa/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -working-directory -Xcc /Users/schwa/Desktop/earcut-swift -resource-dir /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift -enable-anonymous-context-mangled-names -Xcc -fmodule-map-file=/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/GeneratedModuleMaps-iphoneos/earcut_cpp.modulemap -Xcc -ivfsstatcache -Xcc /Users/schwa/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphoneos17.0-21A326-a3f61a28211dc0936fbebe5cd08c1f32.sdkstatcache -Xcc -I/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/swift-overrides.hmap -Xcc -I/Users/schwa/Desktop/earcut-swift/Sources/earcut_cpp/include -Xcc -I/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Products/Debug-iphoneos/include -Xcc -I/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/DerivedSources-normal/arm64 -Xcc -I/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/DerivedSources/arm64 -Xcc -I/Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/DerivedSources -Xcc -DSWIFT_PACKAGE -Xcc -DDEBUG=1 -module-name earcut -frontend-parseable-output -disable-clang-spi -target-sdk-version 17.0 -target-sdk-name iphoneos17.0 -external-plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/usr/lib/swift/host/plugins#/Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/usr/local/lib/swift/host/plugins#/Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/swift/host/plugins#/Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -external-plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/local/lib/swift/host/plugins#/Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/swift-plugin-server -plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins -plugin-path /Applications/Xcode-15.1.0-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/local/lib/swift/host/plugins -parse-as-library -o /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Build/Intermediates.noindex/earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.o -index-unit-output-path /earcut-swift.build/Debug-iphoneos/earcut.build/Objects-normal/arm64/earcut_swift.o -index-store-path /Users/schwa/Library/Developer/Xcode/DerivedData/earcut-swift-hgzijbejqoesmrdnqopquilkstjz/Index.noindex/DataStore -index-system-modules
1. Apple Swift version 5.9 (swiftlang-5.9.2.1.6 clang-1500.1.0.1.1)
2. Compiling with the current language version
3. While evaluating request ExecuteSILPipelineRequest(Run pipelines { Non-Diagnostic Mandatory Optimizations, Serialization, Rest of Onone } on SIL for earcut)
4. While running pass #30 SILFunctionTransform "OwnershipModelEliminator" on SILFunction "@$s6earcutAA8polygonsSays6UInt32VGSaySays5SIMD2VySfGGG_tF".
for 'earcut(polygons:)' (at /Users/schwa/Desktop/earcut-swift/Sources/earcut/earcut_swift.swift:9:8)
Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it):
0 swift-frontend 0x000000010572a038 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 56
1 swift-frontend 0x00000001099c1688 llvm::sys::RunSignalHandlers() + 112
2 swift-frontend 0x00000001099c26f4 SignalHandler(int) + 352
3 libsystem_platform.dylib 0x00000001861d1a24 _sigtramp + 56
4 swift-frontend 0x0000000106be9a98 stripOwnership(swift::SILFunction&) + 3380
5 swift-frontend 0x0000000109362a90 (anonymous namespace)::OwnershipModelEliminator::run() (.llvm.6711774290829921419) + 568
6 swift-frontend 0x0000000109392f5c swift::SILPassManager::runFunctionPasses(unsigned int, unsigned int) + 3988
7 swift-frontend 0x0000000109388178 swift::SILPassManager::executePassPipelinePlan(swift::SILPassPipelinePlan const&) + 240
8 swift-frontend 0x00000001095418f0 swift::SimpleRequest<swift::ExecuteSILPipelineRequest, std::__1::tuple<> (swift::SILPipelineExecutionDescriptor), (swift::RequestFlags)1>::evaluateRequest(swift::ExecuteSILPipelineRequest const&, swift::Evaluator&) + 56
9 swift-frontend 0x00000001093e3df0 llvm::Expected<swift::ExecuteSILPipelineRequest::OutputType> swift::Evaluator::getResultUncached<swift::ExecuteSILPipelineRequest>(swift::ExecuteSILPipelineRequest const&) + 476
10 swift-frontend 0x0000000109406210 swift::runSILPassesForOnone(swift::SILModule&) + 184
11 swift-frontend 0x0000000105bc6a70 swift::CompilerInstance::performSILProcessing(swift::SILModule*) + 560
12 swift-frontend 0x000000010997c658 performCompileStepsPostSILGen(swift::CompilerInstance&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule>>, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, int&, swift::FrontendObserver*) + 956
13 swift-frontend 0x0000000109978520 performCompile(swift::CompilerInstance&, int&, swift::FrontendObserver*) + 1748
14 swift-frontend 0x000000010997bc2c swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 4568
15 swift-frontend 0x00000001092ee058 swift::mainEntry(int, char const**) + 4116
16 dyld 0x0000000185e29058 start + 2224
Command SwiftCompile failed with a nonzero exit code
I've updated the GitHub project.
1 Like
Alex_L
(Alex Lorenz)
November 1, 2023, 5:22pm
5
It seems that swiftSettings: [.interoperabilityMode(.Cxx)]
is viral. And every target that imports a target compiled with that flag needs to set it too. (Warning of the form: "Module 'earcut' was built with C++ interoperability enabled, but current compilation does not enable C++ interoperability"). Is this vitality intended? I tried to nip it off with @_implementationOnly on the C++ target but that didn't do the trick.
Yes, that the intentional behavior. Enabling C++ interoperability for a Swift Package Manager target will need other targets that depend on such target to enable C++ interoperability as well.
If I get passed that by adding in the flag I get a 100% reproducible crash at compile time. I'll post a JIRA but for now:
Thanks, please file an issue on GitHub - apple/swift: The Swift Programming Language so we can take a look
1 Like
Thanks for this sort of explanation.