Repository navigation
JNI: support consumers with C++ interoperability enabled - #927
NakaokaRei wants to merge 7 commits into
Conversation
Preserve the runtime's C JNI types in generated entry points and calls. Expose typed JNI interface getters and an object-value factory so Android consumers do not reimport JNI signatures using the NDK's C++ wrappers. Update generator and macro expectations for the preserved types. Allow the JavaKit and JNI extraction samples to opt into C++ interoperability on consumer targets only. Exercise this mode in existing stable Swift CI jobs, including one Android configuration, and rerun Gradle tests across configurations without reusing a daemon from another Swift toolchain. Validation: 820 package tests; normal and C++ sample tests on macOS and Linux ARM64; Android JNI sample build; hello-cpp-swift emulator execution. Scoped act format, shell, and sample checks passed; the full GitHub Actions workflow and Linux AMD64 execution remain unverified.
Preserve main's Java exception conversion while keeping C-compatible JNI calls in generated async thunks. Use JNITypes.jthrowable for the new error conformances and update closure expectations added since the original fix. Validated with 839 Swift tests and 270 macOS C++ JNI sample tests.
ktoso
left a comment
There was a problem hiding this comment.
Overall supportive of this but I had a few notes
| /// | ||
| /// Use these aliases in generated code so C++-enabled consumers share the | ||
| /// runtime's types instead of importing Android's C++ JNI wrapper types. | ||
| public enum JNITypes { |
There was a problem hiding this comment.
Hmmm, shouldn't these be used from swift-java jni core?
There was a problem hiding this comment.
Thanks. Moved the helpers to swift-java-jni-core in swiftlang/swift-java-jni-core#25, with a C++ interop test.
| chmod 500 install-and-build-with-sdk.sh | ||
| ./install-and-build-with-sdk.sh --android --build-command="swift build" --android-sdk-triple="${{ matrix.sdk_triple }}" --android-ndk-version="${{ matrix.ndk_version }}" ${{ matrix.swift_version }} | ||
| - name: Verify Android JNI consumer with C++ interoperability | ||
| if: matrix.swift_version == '6.3' && matrix.sdk_triple == 'aarch64-unknown-linux-android28' && matrix.ndk_version == 'r27d' |
There was a problem hiding this comment.
| if: matrix.swift_version == '6.3' && matrix.sdk_triple == 'aarch64-unknown-linux-android28' && matrix.ndk_version == 'r27d' | |
| if: matrix.sdk_triple == 'aarch64-unknown-linux-android28' && matrix.ndk_version == 'r27d' |
I don't think we need to lock this to 6.3, do we?
There was a problem hiding this comment.
Removed the Swift 6.3 restriction.
| if: matrix.swift_version == '6.3' && (matrix.sample_app == 'JavaKitSampleApp' || matrix.sample_app == 'SwiftJavaExtractJNISampleApp') | ||
| env: | ||
| CXX_INTEROP: '1' | ||
| SWIFT_JAVA_VERBOSE: true |
There was a problem hiding this comment.
do we need to keep this in CI?
There was a problem hiding this comment.
Removed SWIFT_JAVA_VERBOSE from the added steps.
| // Enable C++ interoperability only in the consumer targets, not their dependencies. | ||
| let sampleSwiftSettings: [SwiftSetting] = | ||
| [.swiftLanguageMode(.v5)] | ||
| + (Context.environment["CXX_INTEROP"] == "1" ? [.interoperabilityMode(.Cxx)] : []) |
There was a problem hiding this comment.
Hmm, I wonder if this should be SWIFT_JAVA_CXX_INTEROP?
There was a problem hiding this comment.
Renamed to SWIFT_JAVA_CXX_INTEROP in both samples and CI.
ktoso
left a comment
There was a problem hiding this comment.
primarily because the JNITypes question
Fixes #391. Follow-up to #463.
Problem
Enabling
.interoperabilityMode(.Cxx)in a consumer changes how JNI headers are imported. In particular, Android exposes differentJNIEnvand reference types in C++ mode, while SwiftJava's runtime uses their C definitions. Generated JNI entry points and calls then fail with type mismatches.Solution
JNIEnvironmentand runtime-ownedJNITypesaliases. Add typed JNI function-table accessors and an object-value factory to preserve C signatures in C++ consumers, withoutunsafeBitCast.CXX_INTEROP=1. Following the feedback on fix: .interoperabilityMode(.Cxx) build issue #463, reuse existing stable Swift 6.3 CI jobs on Linux/macOS and one Android configuration, retaining verbose output. Rerun Gradle tests across configurations and avoid stale toolchain daemons.Testing
Locally verified before rebasing onto current main (the patch is unchanged):
hello-cpp-swiftbuilt and ran on an emulator with C++ interoperability enabled andextern "C"removed.actformatting, ShellCheck, and sample checks using local workflow adaptations. The full unmodified workflow and Linux AMD64 execution were not verified locally; GitHub CI remains to be confirmed.