Android: error: module 'Glibc' has no member named 'stderr'

Hi,

I am building "https://github.com/apple/swift-log" for Android using NDK 21.3.6528147 and getting errors below when targeting Android API 21:

error: module 'Glibc' has no member named 'stderr'
   _ = Glibc.stderr!
       ^~~~~ ~~~~~~
error: module 'Glibc' has no member named 'stdout'
   _ = Glibc.stdout!
       ^~~~~ ~~~~~~

The problem seems that stdin, stdout and stderr defined in NDK using #define.

// File: sysroot/usr/include/stdio.h

/* Before API 23 the actual symbols for stdin and friends had different names. */
extern FILE __sF[] __REMOVED_IN(23);

#define stdin (&__sF[0])
#define stdout (&__sF[1])
#define stderr (&__sF[2])

As I understand clang not including into module types defined with #define. Thus stdin, stdout and stderr not visible by Swift.

Is the any workaround or solution for such cases (when some type defined with #define on C side)?

Thank you in advance!


To reproduce you can:

  1. Download Swift Android Toolchain: https://github.com/vgorloff/swift-everywhere-toolchain/releases/tag/1.0.65

  2. Create file with following contents:

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Windows)
import MSVCRT
#else
import Glibc
#endif

func test() {

   tolower(5) // sysroot/usr/include/ctype.h
   fesetround(6) // sysroot/usr/include/fenv.h
   localeconv() // sysroot/usr/include/locale.h
   #if os(Android)
   isnan(7) // sysroot/usr/include/math.h
   #endif

   #if os(Android)
   _ = Glibc.stderr!
   _ = Glibc.stdout!
   #endif

   //> sysroot/usr/include/stdio.h
   _ = FOPEN_MAX
   _ = off_t()
   clearerr(nil)
   fclose(nil)
   //<
}
  1. Compile it for Android API 23 (Should be no error):
/.../swift-android-toolchain/usr/bin/swiftc-arm-linux-androideabi ./FILE.swift -v -Xcc -D__ANDROID_API__=23
  1. Compile it for Android API 21 (Should be an error):
/.../swift-android-toolchain/usr/bin/swiftc-arm-linux-androideabi ./FILE.swift -v -Xcc -D__ANDROID_API__=21

You will need to define these using Swift in the SwiftGlibc module as they cannot be imported through the clang importer as they are no longer simple numeric defines. See https://github.com/apple/swift/blob/main/stdlib/public/Platform/Platform.swift#L102-L153. One thing to keep in mind is that if the definition changed, you may have to guard this with version checks.

I can reproduce with my Android AArch64 SDK by compiling your test file with this command:

./swift/swift-5.3.1-RELEASE-ubuntu20.04/usr/bin/swiftc
-resource-dir swift-android-aarch64-24-sdk/usr/lib/swift
-sdk swift/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/sysroot/
-tools-directory swift/android-ndk-r21d/toolchains/llvm/prebuilt/linux-x86_64/bin/
stdio.swift -target aarch64-unknown-linux-android21

It's because the ClangImporter doesn't recognize anything other than simple preprocessor defines, I ran into another problem recently when porting swift-nio to Android. I don't think @compnerd's solution will work, as there's currently no built-in way to version Swift code on the Android API level.

Terms of Service

Privacy Policy

Cookie Policy