You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The proposed Android SDK bundle (#80788) will depend on an external NDK being configured. The NDK changes various headers in between their releases, especially around nullability annotations being aded or removed, which affects Swift's view of the C functions and structures.
This means that in practice, some packages that rely on the definitions in the NDK headers will fail to build with earlier or later versions. For example, swift-nio builds successfully for Android with NDK 27, but fails for NDK 26 and 28:
swift-nio failure for NDK 26
[1618/1660] Compiling NIOPosix Linux.swift
/Users/runner/work/swift-package-builds/swift-package-builds/vapor/.build/checkouts/swift-nio/Sources/NIOPosix/System.swift:130:96: error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<msghdr>?, Int32) -> Int' is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<msghdr>, CInt) -> ssize_t' (aka '@convention(c) (Int32, UnsafeMutablePointer<msghdr>, Int32) -> Int')
128 | #endif
129 | #if canImport(Android)
130 | private let sysRecvMsg: @convention(c) (CInt, UnsafeMutablePointer<msghdr>, CInt) -> ssize_t = recvmsg
| `- error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<msghdr>?, Int32) -> Int' is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<msghdr>, CInt) -> ssize_t' (aka '@convention(c) (Int32, UnsafeMutablePointer<msghdr>, Int32) -> Int')
131 | private let sysSendMsg: @convention(c) (CInt, UnsafePointer<msghdr>, CInt) -> ssize_t = sendmsg
132 | #elseif !os(Windows)
/Users/runner/work/swift-package-builds/swift-package-builds/vapor/.build/checkouts/swift-nio/Sources/NIOPosix/System.swift:131:89: error: C function pointer signature '@Sendable (Int32, UnsafePointer<msghdr>?, Int32) -> Int' is not compatible with expected type '@convention(c) (CInt, UnsafePointer<msghdr>, CInt) -> ssize_t' (aka '@convention(c) (Int32, UnsafePointer<msghdr>, Int32) -> Int')
129 | #if canImport(Android)
130 | private let sysRecvMsg: @convention(c) (CInt, UnsafeMutablePointer<msghdr>, CInt) -> ssize_t = recvmsg
131 | private let sysSendMsg: @convention(c) (CInt, UnsafePointer<msghdr>, CInt) -> ssize_t = sendmsg
| `- error: C function pointer signature '@Sendable (Int32, UnsafePointer<msghdr>?, Int32) -> Int' is not compatible with expected type '@convention(c) (CInt, UnsafePointer<msghdr>, CInt) -> ssize_t' (aka '@convention(c) (Int32, UnsafePointer<msghdr>, Int32) -> Int')
132 | #elseif !os(Windows)
133 | private let sysRecvMsg: @convention(c) (CInt, UnsafeMutablePointer<msghdr>?, CInt) -> ssize_t = recvmsg
/Users/runner/work/swift-package-builds/swift-package-builds/vapor/.build/checkouts/swift-nio/Sources/NIOPosix/System.swift:139:102: error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<sockaddr>?, UnsafeMutablePointer<socklen_t>?) -> Int32' (aka '@Sendable (Int32, Optional<UnsafeMutablePointer<sockaddr>>, Optional<UnsafeMutablePointer<UInt32>>) -> Int32') is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt' (aka '@convention(c) (Int32, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<UInt32>) -> Int32')
137 | #if canImport(Android)
138 | private let sysGetpeername:
139 | @convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt = getpeername
| `- error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<sockaddr>?, UnsafeMutablePointer<socklen_t>?) -> Int32' (aka '@Sendable (Int32, Optional<UnsafeMutablePointer<sockaddr>>, Optional<UnsafeMutablePointer<UInt32>>) -> Int32') is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt' (aka '@convention(c) (Int32, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<UInt32>) -> Int32')
140 | private let sysGetsockname:
141 | @convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt = getsockname
/Users/runner/work/swift-package-builds/swift-package-builds/vapor/.build/checkouts/swift-nio/Sources/NIOPosix/System.swift:141:102: error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<sockaddr>?, UnsafeMutablePointer<socklen_t>?) -> Int32' (aka '@Sendable (Int32, Optional<UnsafeMutablePointer<sockaddr>>, Optional<UnsafeMutablePointer<UInt32>>) -> Int32') is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt' (aka '@convention(c) (Int32, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<UInt32>) -> Int32')
139 | @convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt = getpeername
140 | private let sysGetsockname:
141 | @convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt = getsockname
| `- error: C function pointer signature '@Sendable (Int32, UnsafeMutablePointer<sockaddr>?, UnsafeMutablePointer<socklen_t>?) -> Int32' (aka '@Sendable (Int32, Optional<UnsafeMutablePointer<sockaddr>>, Optional<UnsafeMutablePointer<UInt32>>) -> Int32') is not compatible with expected type '@convention(c) (CInt, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<socklen_t>) -> CInt' (aka '@convention(c) (Int32, UnsafeMutablePointer<sockaddr>, UnsafeMutablePointer<UInt32>) -> Int32')
142 | #elseif !os(Windows)
143 | private let sysGetpeername:
swift-nio failure for NDK 28
[333/417] Compiling NIOPosix VsockAddress.swift
/Users/runner/work/swift-package-builds/swift-package-builds/swift-nio/Sources/NIOPosix/ThreadPosix.swift:66:9: error: cannot convert value of type 'ThreadDestructor' (aka '@convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer') to expected argument type '@convention(c) (UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer?'
64 | &handleLinux,
65 | nil,
66 | destructor,
| `- error: cannot convert value of type 'ThreadDestructor' (aka '@convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer') to expected argument type '@convention(c) (UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer?'
67 | args
68 | )
This is similar to needing to be able to check the Android API level described at #76671, except it is a build-time constant indicated by __NDK_MAJOR__ that wouldn't affect anything at runtime. Android API levels and NDK versions are unrelated (e.g., you can build for API 34+NDK 26 or API 33+NDK 27 or API 29+NDK 28), and so the Android API level cannot be used as a proxy for the NDK version.
The "just do it in C" solution might look like this:
A crude solution might be to have the Android SDK post-install script add per-NDK build variables for everything up to the current NDK, so that when building against NDK 26, swiftc would look like:
swiftc -DANDROID_NDK25 -DANDROID_NDK26 File.swift
and when building against NDK 27, it would look like:
You're right that continually added nullability annotations in each NDK causes us to have to keep changing our C function signatures to match. That said, I doubt that almost anyone will actually use this feature to target multiple NDKs in the same Swift codebase, so I think we should just espouse the best practice that all Swift code should match the current LTS NDK. If someone wants to build with some other NDK, it is up to them to patch all their Swift code to work.
I'm not against adding this #if _ndkVersion feature though, as a few people may use it.
The proposed Android SDK bundle (#80788) will depend on an external NDK being configured. The NDK changes various headers in between their releases, especially around nullability annotations being aded or removed, which affects Swift's view of the C functions and structures.
This means that in practice, some packages that rely on the definitions in the NDK headers will fail to build with earlier or later versions. For example,
swift-nio
builds successfully for Android with NDK 27, but fails for NDK 26 and 28:swift-nio failure for NDK 26
swift-nio failure for NDK 28
This is similar to needing to be able to check the Android API level described at #76671, except it is a build-time constant indicated by
__NDK_MAJOR__
that wouldn't affect anything at runtime. Android API levels and NDK versions are unrelated (e.g., you can build for API 34+NDK 26 or API 33+NDK 27 or API 29+NDK 28), and so the Android API level cannot be used as a proxy for the NDK version.The "just do it in C" solution might look like this:
A crude solution might be to have the Android SDK post-install script add per-NDK build variables for everything up to the current NDK, so that when building against NDK 26, swiftc would look like:
and when building against NDK 27, it would look like:
That way the Swift code could perform checks like:
A solution built into Swift might look like:
The text was updated successfully, but these errors were encountered: