diff --git a/Package.swift b/Package.swift index 68447363..e380e47a 100644 --- a/Package.swift +++ b/Package.swift @@ -23,8 +23,9 @@ let package = Package( targets: [ .target( name: "Logging", - dependencies: [] + dependencies: [.byName(name: "CSwiftLogAndroidSupport", condition: .when(platforms: [.android]))] ), + .target(name: "CSwiftLogAndroidSupport"), .testTarget( name: "LoggingTests", dependencies: ["Logging"] diff --git a/Sources/CSwiftLogAndroidSupport/include/CSwiftLogAndroidSupport.h b/Sources/CSwiftLogAndroidSupport/include/CSwiftLogAndroidSupport.h new file mode 100644 index 00000000..7ff0e9e9 --- /dev/null +++ b/Sources/CSwiftLogAndroidSupport/include/CSwiftLogAndroidSupport.h @@ -0,0 +1,17 @@ +#ifndef SWIFT_LOG_ANDROID_SUPPORT_H +#define SWIFT_LOG_ANDROID_SUPPORT_H + +#include + +// These C functions will be called from Swift. They provide a stable +// interface, hiding the pointer type differences between Android versions. + +void *shim_stdout(void); +void *shim_stderr(void); + +void shim_flockfile(void *file); +void shim_funlockfile(void *file); +size_t shim_fwrite(const void *ptr, size_t size, size_t count, void *file); +int shim_fflush(void *file); + +#endif // SWIFT_LOG_ANDROID_SUPPORT_H diff --git a/Sources/CSwiftLogAndroidSupport/include/shim.c b/Sources/CSwiftLogAndroidSupport/include/shim.c new file mode 100644 index 00000000..92b573c9 --- /dev/null +++ b/Sources/CSwiftLogAndroidSupport/include/shim.c @@ -0,0 +1,25 @@ +#include "CSwiftLogAndroidSupport.h" + +void *shim_stdout(void) { + return stdout; +} + +void *shim_stderr(void) { + return stderr; +} + +void shim_flockfile(void *file) { + flockfile(file); +} + +void shim_funlockfile(void *file) { + funlockfile(file); +} + +size_t shim_fwrite(const void *ptr, size_t size, size_t count, void *file) { + return fwrite(ptr, size, count, file); +} + +int shim_fflush(void *file) { + return fflush(file); +} diff --git a/Sources/Logging/Logging.swift b/Sources/Logging/Logging.swift index 544a7399..47ae7ef4 100644 --- a/Sources/Logging/Logging.swift +++ b/Sources/Logging/Logging.swift @@ -24,6 +24,7 @@ import Glibc #endif #elseif canImport(Android) import Android +import CSwiftLogAndroidSupport #elseif canImport(Musl) import Musl #elseif canImport(WASILibc) @@ -1203,8 +1204,10 @@ public struct MultiplexLogHandler: LogHandler { } } -#if canImport(WASILibc) || os(Android) +#if canImport(WASILibc) internal typealias CFilePointer = OpaquePointer +#elseif canImport(Android) +internal typealias CFilePointer = UnsafeMutableRawPointer #else internal typealias CFilePointer = UnsafeMutablePointer #endif @@ -1222,6 +1225,8 @@ internal struct StdioOutputStream: TextOutputStream, @unchecked Sendable { _lock_file(self.file) #elseif canImport(WASILibc) // no file locking on WASI + #elseif canImport(Android) + shim_flockfile(self.file) #else flockfile(self.file) #endif @@ -1230,11 +1235,17 @@ internal struct StdioOutputStream: TextOutputStream, @unchecked Sendable { _unlock_file(self.file) #elseif canImport(WASILibc) // no file locking on WASI + #elseif canImport(Android) + shim_funlockfile(self.file) #else funlockfile(self.file) #endif } + #if canImport(Android) + _ = shim_fwrite(utf8Bytes.baseAddress!, 1, utf8Bytes.count, self.file) + #else _ = fwrite(utf8Bytes.baseAddress!, 1, utf8Bytes.count, self.file) + #endif if case .always = self.flushMode { self.flush() } @@ -1243,7 +1254,11 @@ internal struct StdioOutputStream: TextOutputStream, @unchecked Sendable { /// Flush the underlying stream. internal func flush() { + #if canImport(Android) + _ = shim_fflush(self.file) + #else _ = fflush(self.file) + #endif } internal func contiguousUTF8(_ string: String) -> String.UTF8View { @@ -1261,7 +1276,7 @@ internal struct StdioOutputStream: TextOutputStream, @unchecked Sendable { #elseif canImport(Glibc) let systemStderr = Glibc.stderr! #elseif canImport(Android) - let systemStderr = Android.stderr + let systemStderr = shim_stderr()! #elseif canImport(Musl) let systemStderr = Musl.stderr! #elseif canImport(WASILibc) @@ -1281,7 +1296,7 @@ internal struct StdioOutputStream: TextOutputStream, @unchecked Sendable { #elseif canImport(Glibc) let systemStdout = Glibc.stdout! #elseif canImport(Android) - let systemStdout = Android.stdout + let systemStdout = shim_stdout()! #elseif canImport(Musl) let systemStdout = Musl.stdout! #elseif canImport(WASILibc)