From ef7a4c06206976de7ef2e974267407347ddb75a4 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Oct 2017 20:17:26 +0200 Subject: [PATCH] Prepare Mono for Android NDK with unified headers (#5680) Up until NDK release 14 Android SDK included a separate set of C header files for each supported platform. NDK 14 introduced a new set of those headers (they are NOT the same as the old ones) which unifies support for all of the platforms so that bug fixes are available for all the API levels without having to backport etc. With NDK 15 the unified headers become the default ones (including when creating standalone toolchains) and with NDK 16 (in beta currently) the old per-platform headers are removed. Unfortunately, the new headers introduce breaking changes which made it impossible to build Mono with NDK configured to use them. This commit makes a handful of changes to Mono which make it build with unified headers. --- configure.ac | 67 +++++++++++++++++++++++++ mono/metadata/w32socket-unix.c | 1 + mono/utils/mono-compiler.h | 35 +++++++++++++ mono/utils/mono-complex.h | 2 +- mono/utils/mono-threads-posix-signals.c | 4 ++ support/fcntl.c | 2 +- support/libm/complex.h | 6 +++ support/libm/math_private.h | 6 +++ support/macros.c | 1 + support/mph.h | 43 ++++++++++++++++ support/pwd.c | 2 +- support/sys-mman.c | 1 + support/sys-sendfile.c | 1 + support/sys-stat.c | 2 +- support/sys-statvfs.c | 10 ++-- support/unistd.c | 2 +- 16 files changed, 177 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index bad8ecc8e3c..9299a874b30 100644 --- a/configure.ac +++ b/configure.ac @@ -554,6 +554,73 @@ AC_CHECK_FUNCS(_finite, , AC_MSG_CHECKING(for _finite in math.h) # for Linux statfs support AC_CHECK_HEADERS(linux/magic.h) +# For Android NDK unified headers +if test x$platform_android = xyes; then + AC_CHECK_HEADERS(machine/endian.h sys/endian.h) + AC_CHECK_HEADERS(android/legacy_signal_inlines.h, [have_android_signal_inlines=yes], [have_android_signal_inlines=no]) + + # Make sure SIGRT{MIN,MAX} work - they will fail to work with unified headers if building for + # API level < 21 *and* android/legacy_signal_inlines.h doesn't declare (and define) the required + # libc APIs to obtain values for SIGRT{MIN,MAX}. We perform the check only if android/legacy_signal_inlines.h + # is found because in other cases the macros will either work (for NDK < 14) or fail if the legacy header + # doesn't contain the required definitions (NDK 14) + if test x$have_android_signal_inlines = xyes; then + AC_MSG_CHECKING([Whether Android SIGRTMIN/SGRTMAX macros are valid]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([#include ],[ + int i; + for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) { + } + ])],[ + AC_MSG_RESULT(yes) + android_sigrtminmax_work=yes + ],[ + AC_MSG_RESULT(no) + android_sigrtminmax_work=no + ] + ) + + if test x$android_sigrtminmax_work = xno; then + AC_MSG_ERROR([Android SIGRTMIN/SIGRTMAX macros don't work in this NDK]) + fi + fi + + # Attempt to detect whether we're using Android NDK unified headers + AC_CHECK_HEADERS(android/api-level.h, [have_android_api_level=yes], [have_android_api_level=no]) + AC_CHECK_HEADERS(android/versioning.h, [have_android_versioning=yes], [have_android_versioning=no]) + + android_unified_headers=no + if test x$have_android_api_level = xyes; then + if test x$have_android_versioning = xyes; then + AC_MSG_CHECKING([whether using Android NDK unified headers]) + + # Both macros are defined only in the NDK unified headers + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([ + #include + #include + ],[ + #if __ANDROID_API_O__ == 26 && defined(__INTRODUCED_IN) + return 0 + #else + #error __ANDROID_API_O__ != 26 or the __INTRODUCED_IN macro not defined + #endif + ])],[ + AC_MSG_RESULT(yes) + android_unified_headers=yes + ],[ + AC_MSG_RESULT(no) + android_unified_headers=no + ] + ) + fi + fi + + if test x$android_unified_headers = xyes; then + AC_DEFINE(ANDROID_UNIFIED_HEADERS, 1, [Whether Android NDK unified headers are used]) + fi +fi # Android + # not 64 bit clean in cross-compile if test "x$enable_wasm" = "xyes"; then AC_DEFINE(SIZEOF_VOID_P,4) diff --git a/mono/metadata/w32socket-unix.c b/mono/metadata/w32socket-unix.c index 74e1fcceab5..28a5a63a5b4 100644 --- a/mono/metadata/w32socket-unix.c +++ b/mono/metadata/w32socket-unix.c @@ -54,6 +54,7 @@ #include "fdhandle.h" #include "utils/mono-logger-internals.h" #include "utils/mono-poll.h" +#include "utils/mono-compiler.h" typedef struct { MonoFDHandle fdhandle; diff --git a/mono/utils/mono-compiler.h b/mono/utils/mono-compiler.h index 3e1b4108b4e..50a91886fc1 100644 --- a/mono/utils/mono-compiler.h +++ b/mono/utils/mono-compiler.h @@ -10,6 +10,9 @@ * compiler behaviours. */ #include +#if defined(HAVE_UNISTD_H) +#include +#endif #ifdef __GNUC__ #define MONO_ATTR_USED __attribute__ ((__used__)) @@ -130,5 +133,37 @@ typedef SSIZE_T ssize_t; #define MONO_NO_SANITIZE_THREAD #endif +/* Used when building with Android NDK's unified headers */ +#if defined(HOST_ANDROID) +#if __ANDROID_API__ < 21 + +typedef int32_t __mono_off32_t; + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#if !defined(mmap) +/* Unified headers before API 21 do not declare mmap when LARGE_FILES are used (via -D_FILE_OFFSET_BITS=64) + * which is always the case when Mono build targets Android. The problem here is that the unified headers + * map `mmap` to `mmap64` if large files are enabled but this api exists only in API21 onwards. Therefore + * we must carefully declare the 32-bit mmap here without changing the ABI along the way. Carefully because + * in this instance off_t is redeclared to be 64-bit and that's not what we want. + */ +void* mmap (void*, size_t, int, int, int, __mono_off32_t); +#endif /* !mmap */ + +#ifdef HAVE_SYS_SENDFILE_H +#include +#endif + +#if !defined(sendfile) +/* The same thing as with mmap happens with sendfile */ +ssize_t sendfile (int out_fd, int in_fd, __mono_off32_t* offset, size_t count); +#endif /* !sendfile */ + +#endif /* __ANDROID_API__ < 21 */ +#endif /* HOST_ANDROID */ + #endif /* __UTILS_MONO_COMPILER_H__*/ diff --git a/mono/utils/mono-complex.h b/mono/utils/mono-complex.h index b7488c7cf52..385eee9b159 100644 --- a/mono/utils/mono-complex.h +++ b/mono/utils/mono-complex.h @@ -12,7 +12,7 @@ #include #include -#if !defined (HAVE_COMPLEX_H) +#if !defined (HAVE_COMPLEX_H) || (defined (ANDROID_UNIFIED_HEADERS) && __ANDROID_API__ < 23) #include <../../support/libm/complex.h> #else #include diff --git a/mono/utils/mono-threads-posix-signals.c b/mono/utils/mono-threads-posix-signals.c index 5f762c83abe..b39277393f5 100644 --- a/mono/utils/mono-threads-posix-signals.c +++ b/mono/utils/mono-threads-posix-signals.c @@ -18,6 +18,10 @@ #include #include +#ifdef HAVE_ANDROID_LEGACY_SIGNAL_INLINES_H +#include +#endif + #include "mono-threads-debug.h" gint diff --git a/support/fcntl.c b/support/fcntl.c index 900a58f8104..1fd324e399f 100644 --- a/support/fcntl.c +++ b/support/fcntl.c @@ -22,8 +22,8 @@ #include #endif +#include "mph.h" /* Don't remove or move after map.h! Works around issues with Android SDK unified headers */ #include "map.h" -#include "mph.h" G_BEGIN_DECLS diff --git a/support/libm/complex.h b/support/libm/complex.h index b8a16a8b4bf..2fc2284d63e 100644 --- a/support/libm/complex.h +++ b/support/libm/complex.h @@ -29,8 +29,14 @@ #ifndef _COMPLEX_H #define _COMPLEX_H +#include #include +#if HOST_ANDROID && !defined(__pure2) +/* NDK unified headers don't define __pure2 */ +#define __pure2 __attribute__((__const__)) +#endif + #ifdef __GNUC__ #if __STDC_VERSION__ < 199901 #define _Complex __complex__ diff --git a/support/libm/math_private.h b/support/libm/math_private.h index b33cf60271a..ddb615e15cd 100644 --- a/support/libm/math_private.h +++ b/support/libm/math_private.h @@ -18,7 +18,13 @@ #define _MATH_PRIVATE_H_ #include + +#if HAVE_MACHINE_ENDIAN_H #include +#elif HAVE_SYS_ENDIAN_H && HOST_ANDROID +/* Android unified headers don't have machine/endian.h */ +#include +#endif /* * The original fdlibm code used statements like: diff --git a/support/macros.c b/support/macros.c index 8d455889d7c..e15fa76b7ed 100644 --- a/support/macros.c +++ b/support/macros.c @@ -9,6 +9,7 @@ #include #include #include +#include "mph.h" /* Don't remove or move after map.h! Works around issues with Android SDK unified headers */ #include "map.h" int wifexited (int status) diff --git a/support/mph.h b/support/mph.h index e5992e5e71f..2fbae6a27cd 100644 --- a/support/mph.h +++ b/support/mph.h @@ -32,10 +32,53 @@ #include /* for ERANGE */ #include /* for g* types, etc. */ +#ifdef HAVE_SYS_STAT_H +#include +#endif + #ifdef HAVE_STDINT_H #include /* for SIZE_MAX */ #endif +#ifdef ANDROID_UNIFIED_HEADERS +#ifdef HAVE_STDIO_H +#include +#endif + +#undef st_atime_nsec +#undef st_mtime_nsec +#undef st_ctime_nsec + +#ifndef L_cuserid +#define L_cuserid 9 /* size for cuserid(); UT_NAMESIZE + 1 */ +#endif + +/* NDK unified headers will define fpos_t to be 64-bit if large files support is + * enabled (which is the case with Mono) so we need to make sure the offsets here + * are actually 32-bit for Android APIs before API24 which did NOT have the 64-bit + * versions. + */ +#if !defined(fgetpos) && __ANDROID_API__ < 24 +int fgetpos(FILE*, fpos_t*); +#endif + +#if !defined(fsetpos) && __ANDROID_API__ < 24 +int fsetpos(FILE*, const fpos_t*); +#endif + +#ifdef HAVE_PWD_H +#include +#endif +/* Unified headers define 'pw_gecos' to be an alias for 'pw_passwd` on 32-bit Android which + * results in two fields named 'pw_passwd' in map.h's 'struct passwd' + */ +#if !defined(__LP64__) && defined(pw_gecos) +#undef pw_gecos +#undef HAVE_STRUCT_PASSWD_PW_GECOS +#endif + +#endif + #if __APPLE__ || __BSD__ || __FreeBSD__ || __OpenBSD__ #define MPH_ON_BSD #endif diff --git a/support/pwd.c b/support/pwd.c index 6e3b68a208e..0e73af22bf9 100644 --- a/support/pwd.c +++ b/support/pwd.c @@ -13,8 +13,8 @@ #include #include +#include "mph.h" /* Don't remove or move after map.h! Works around issues with Android SDK unified headers */ #include "map.h" -#include "mph.h" G_BEGIN_DECLS diff --git a/support/sys-mman.c b/support/sys-mman.c index 143148f8ca3..ad74ef2ad02 100644 --- a/support/sys-mman.c +++ b/support/sys-mman.c @@ -31,6 +31,7 @@ #include #include +#include "mono/utils/mono-compiler.h" #include "map.h" #include "mph.h" diff --git a/support/sys-sendfile.c b/support/sys-sendfile.c index 7b6797acb04..794341b5899 100644 --- a/support/sys-sendfile.c +++ b/support/sys-sendfile.c @@ -12,6 +12,7 @@ #include #include +#include "mono/utils/mono-compiler.h" #include "map.h" #include "mph.h" diff --git a/support/sys-stat.c b/support/sys-stat.c index 075563b0cf4..d6abce4a1fa 100644 --- a/support/sys-stat.c +++ b/support/sys-stat.c @@ -19,8 +19,8 @@ #include #include +#include "mph.h" /* Don't remove or move after map.h! Works around issues with Android SDK unified headers */ #include "map.h" -#include "mph.h" G_BEGIN_DECLS diff --git a/support/sys-statvfs.c b/support/sys-statvfs.c index e03152a773d..128baaa03b3 100644 --- a/support/sys-statvfs.c +++ b/support/sys-statvfs.c @@ -33,6 +33,8 @@ #include /* for pathconf */ #endif /* def HAVE_GETFSSTAT */ +#include "mono/utils/mono-compiler.h" + G_BEGIN_DECLS #ifdef HAVE_SYS_STATVFS_H @@ -129,9 +131,11 @@ Mono_Posix_Syscall_fstatvfs (gint32 fd, struct Mono_Posix_Statvfs *buf) * BSD-compatible definitions. * * Linux also provides these, but are deprecated in favor of (f)statvfs. + * Android NDK unified headers define HAVE_FSTATFS but also HAVE_SYS_STATVFS_H + * which makes these duplicates of the functions defined above */ -#if (defined (HAVE_STATFS) || defined (HAVE_FSTATFS)) && !defined (HAVE_STATVFS) +#if (defined (HAVE_STATFS) || defined (HAVE_FSTATFS)) && !defined (HAVE_STATVFS) && !defined(ANDROID_UNIFIED_HEADERS) int Mono_Posix_ToStatvfs (void *_from, struct Mono_Posix_Statvfs *to) { @@ -197,7 +201,7 @@ set_fnamemax (int fd, struct Mono_Posix_Statvfs *buf) } #endif /* (def HAVE_STATFS || def HAVE_FSTATFS) && !def HAVE_STATVFS */ -#if !defined (HAVE_STATVFS) && defined (HAVE_STATFS) +#if !defined (HAVE_STATVFS) && defined (HAVE_STATFS) && (!defined(ANDROID_UNIFIED_HEADERS) || __ANDROID_API__ >= 19) gint32 Mono_Posix_Syscall_statvfs (const char *path, struct Mono_Posix_Statvfs *buf) { @@ -218,7 +222,7 @@ Mono_Posix_Syscall_statvfs (const char *path, struct Mono_Posix_Statvfs *buf) } #endif /* !def HAVE_STATVFS && def HAVE_STATFS */ -#if !defined (HAVE_STATVFS) && defined (HAVE_STATFS) +#if !defined (HAVE_STATVFS) && defined (HAVE_STATFS) && (!defined(ANDROID_UNIFIED_HEADERS) || __ANDROID_API__ >= 19) gint32 Mono_Posix_Syscall_fstatvfs (gint32 fd, struct Mono_Posix_Statvfs *buf) { diff --git a/support/unistd.c b/support/unistd.c index 0f560e28d00..145de5192eb 100644 --- a/support/unistd.c +++ b/support/unistd.c @@ -21,8 +21,8 @@ #include #include /* for swab(3) on Mac OS X */ +#include "mph.h" /* Don't remove or move after map.h! Works around issues with Android SDK unified headers */ #include "map.h" -#include "mph.h" G_BEGIN_DECLS -- 2.25.1