From 7a0f4de3c18cab43b5bff47fdab4944e006c68e4 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 17 Mar 2024 19:32:15 +0800 Subject: [PATCH] Improve C++ standard library detection on Android * configure.ac: Stop relaying --with-ndk-cxx-shared to the nested invocation of configure. * build-aux/ndk-build-helper-1.mk (SYSTEM_LIBRARIES): * build-aux/ndk-build-helper-2.mk (SYSTEM_LIBRARIES): Insert all of the C++ libraries available on Android. * configure.ac: Call ndk_LATE and ndk_LATE_EARLY within if statement at toplevel, averting needless calls to AC_PROG_CXX. * cross/ndk-build/Makefile.in (NDK_BUILD_CXX_STL) (NDK_BUILD_CXX_LDFLAGS): * cross/ndk-build/ndk-build.mk.in (NDK_BUILD_CXX_STL) (NDK_BUILD_CXX_LDFLAGS): New variables. * cross/ndk-build/ndk-resolve.mk (NDK_SYSTEM_LIBRARIES): Introduce several other C++ libraries sometimes present on Android. (NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE)): Insert NDK_BUILD_CXX_STL when any of these new C++ libraries are requested. * m4/ndk-build.m4: Completely rewrite C++ compiler and library detection. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): Attempt to load more libraries from static initializer. * java/INSTALL: Remove obsolete information. --- build-aux/ndk-build-helper-1.mk | 2 +- build-aux/ndk-build-helper-2.mk | 2 +- configure.ac | 12 +- cross/ndk-build/Makefile.in | 26 +- cross/ndk-build/ndk-build.mk.in | 2 + cross/ndk-build/ndk-resolve.mk | 32 ++- java/INSTALL | 30 +-- java/org/gnu/emacs/EmacsNative.java | 6 +- m4/ndk-build.m4 | 354 +++++++++++++++++++++------- 9 files changed, 335 insertions(+), 131 deletions(-) diff --git a/build-aux/ndk-build-helper-1.mk b/build-aux/ndk-build-helper-1.mk index 5681728154c..490064b6e32 100644 --- a/build-aux/ndk-build-helper-1.mk +++ b/build-aux/ndk-build-helper-1.mk @@ -94,7 +94,7 @@ endef # dependencies can be ignored while building a shared library, as they # will be linked in to the resulting shared object file later. -SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ log liblog android libandroid +SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ stlport libstlport gnustl libgnustl c++ libc++ log liblog android libandroid $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES) $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)),$(eval $(call add-includes,$(module)))) diff --git a/build-aux/ndk-build-helper-2.mk b/build-aux/ndk-build-helper-2.mk index 1c2409cfd57..e696fcbdade 100644 --- a/build-aux/ndk-build-helper-2.mk +++ b/build-aux/ndk-build-helper-2.mk @@ -87,7 +87,7 @@ endef # Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and # LOCAL_SHARED_LIBRARIES. -SYSTEM_LIBRARIES = z libz libc c libdl dl libstdc++ stdc++ log liblog android libandroid +SYSTEM_LIBRARIES = z libz libc c libdl dl libstdc++ stdc++ stlport libstlport gnustl libgnustl c++ libc++ log liblog android libandroid $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module)))) $(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) diff --git a/configure.ac b/configure.ac index 452aa0838f1..bd678ea52a3 100644 --- a/configure.ac +++ b/configure.ac @@ -171,7 +171,6 @@ AS_IF([test "$XCONFIGURE" = "android"],[ # Make sure to pass through the CFLAGS, as older versions of the # NDK require them to be able to find system includes. with_ndk_path="$android_ndk_path" - with_ndk_cxx_shared="$android_ndk_cxx_shared" with_ndk_cxx="$android_ndk_cxx" ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build], [$ANDROID_CFLAGS]) @@ -1233,7 +1232,7 @@ package will likely install on older systems but crash on startup.]) passthrough="$passthrough --with-harfbuzz=$with_harfbuzz" passthrough="$passthrough --with-threads=$with_threads" - # Now pass through some checking options. + # Now pass through some checking-related options. emacs_val="--enable-check-lisp-object-type=$enable_check_lisp_object_type" passthrough="$passthrough $emacs_val" @@ -1243,7 +1242,6 @@ package will likely install on older systems but crash on startup.]) AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \ ANDROID_SDK="$android_sdk" android_abi=$android_abi \ android_ndk_path="$with_ndk_path" \ - android_ndk_cxx_shared="$with_ndk_cxx_shared" \ android_ndk_cxx="$android_ndk_cxx" \ $CONFIG_SHELL $0 $passthrough], [], [AC_MSG_ERROR([Failed to cross-configure Emacs for android.])]) @@ -1570,7 +1568,13 @@ AC_DEFUN_ONCE([gl_STDLIB_H], # Initialize gnulib right after choosing the compiler. dnl Amongst other things, this sets AR and ARFLAGS. gl_EARLY -ndk_LATE + +# ndk_LATE must be enclosed in this conditional to prevent the +# AC_PROG_CXX it indirectly requires from being expanded at top level. +if test "$ndk_INITIALIZED" = "yes"; then + ndk_LATE_EARLY + ndk_LATE +fi if test "$ac_test_CFLAGS" != set; then # It's helpful to have C macros available to GDB, so prefer -g3 to -g diff --git a/cross/ndk-build/Makefile.in b/cross/ndk-build/Makefile.in index 8ba2d356f27..0970a765b45 100644 --- a/cross/ndk-build/Makefile.in +++ b/cross/ndk-build/Makefile.in @@ -24,15 +24,17 @@ srcdir = @srcdir@ # This is a list of Android.mk files which provide targets. -NDK_BUILD_ANDROID_MK = @NDK_BUILD_ANDROID_MK@ - NDK_BUILD_ARCH = @NDK_BUILD_ARCH@ - NDK_BUILD_ABI = @NDK_BUILD_ABI@ - NDK_BUILD_SDK = @NDK_BUILD_SDK@ - NDK_BUILD_CC = @NDK_BUILD_CC@ - NDK_BUILD_CXX = @NDK_BUILD_CXX@ - NDK_BUILD_AR = @NDK_BUILD_AR@ - NDK_BUILD_NASM = @NDK_BUILD_NASM@ - NDK_BUILD_CFLAGS = @NDK_BUILD_CFLAGS@ + NDK_BUILD_ANDROID_MK = @NDK_BUILD_ANDROID_MK@ + NDK_BUILD_ARCH = @NDK_BUILD_ARCH@ + NDK_BUILD_ABI = @NDK_BUILD_ABI@ + NDK_BUILD_SDK = @NDK_BUILD_SDK@ + NDK_BUILD_CC = @NDK_BUILD_CC@ + NDK_BUILD_CXX = @NDK_BUILD_CXX@ + NDK_BUILD_CXX_STL = @NDK_BUILD_CXX_STL@ +NDK_BUILD_CXX_LDFLAGS = @NDK_BUILD_CXX_LDFLAGS@ + NDK_BUILD_AR = @NDK_BUILD_AR@ + NDK_BUILD_NASM = @NDK_BUILD_NASM@ + NDK_BUILD_CFLAGS = @NDK_BUILD_CFLAGS@ # This is a list of targets to build. NDK_BUILD_MODULES = @NDK_BUILD_MODULES@ @@ -58,8 +60,10 @@ NDK_BUILD_ANDROID_MK := $(call uniqify,$(NDK_BUILD_ANDROID_MK)) NDK_BUILD_MODULES := $(call uniqify,$(NDK_BUILD_MODULES)) # Define CFLAGS for compiling C++ code; this involves removing all -# -std=NNN options. -NDK_BUILD_CFLAGS_CXX := $(filter-out -std=%,$(NDK_BUILD_CFLAGS)) +# -std=NNN options and inserting compilation options for the C++ +# library. +NDK_BUILD_CFLAGS_CXX := $(filter-out -std=%,$(NDK_BUILD_CFLAGS)) \ + $(NDK_BUILD_CXX_STL) define subr-1 diff --git a/cross/ndk-build/ndk-build.mk.in b/cross/ndk-build/ndk-build.mk.in index 6c85ff5044e..ea1be5af6f1 100644 --- a/cross/ndk-build/ndk-build.mk.in +++ b/cross/ndk-build/ndk-build.mk.in @@ -22,6 +22,8 @@ NDK_BUILD_MODULES = @NDK_BUILD_MODULES@ NDK_BUILD_CXX_SHARED = @NDK_BUILD_CXX_SHARED@ +NDK_BUILD_CXX_STL = @NDK_BUILD_CXX_STL@ +NDK_BUILD_CXX_LDFLAGS = @NDK_BUILD_CXX_LDFLAGS@ NDK_BUILD_ANY_CXX_MODULE = @NDK_BUILD_ANY_CXX_MODULE@ NDK_BUILD_SHARED = NDK_BUILD_STATIC = diff --git a/cross/ndk-build/ndk-resolve.mk b/cross/ndk-build/ndk-resolve.mk index d3b398bca62..4d8ecf8667a 100644 --- a/cross/ndk-build/ndk-resolve.mk +++ b/cross/ndk-build/ndk-resolve.mk @@ -20,7 +20,7 @@ # which actually builds targets. # List of system libraries to ignore. -NDK_SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ log liblog android libandroid +NDK_SYSTEM_LIBRARIES = z libz libc c libdl dl stdc++ libstdc++ stlport libstlport gnustl libgnustl c++ libc++ log liblog android libandroid # Save information. NDK_LOCAL_PATH_$(LOCAL_MODULE) := $(LOCAL_PATH) @@ -90,11 +90,35 @@ endif # Likewise for libstdc++. ifeq ($(strip $(1)),libstdc++) -NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++ +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) endif -ifeq ($(strip $(1)),dl) -NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += -lstdc++ +ifeq ($(strip $(1)),stdc++) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),libstlport) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),stlport) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),libgnustl) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),gnustl) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),libc++) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) +endif + +ifeq ($(strip $(1)),c++) +NDK_SO_EXTRA_FLAGS_$(LOCAL_MODULE) += $(NDK_BUILD_CXX_LDFLAGS) endif # Likewise for liblog. diff --git a/java/INSTALL b/java/INSTALL index 175ff2826b2..f1063b40c25 100644 --- a/java/INSTALL +++ b/java/INSTALL @@ -166,25 +166,21 @@ than a compressed package for a newer version of Android. BUILDING C++ DEPENDENCIES -With a new version of the NDK, dependencies containing C++ code should -build without any further configuration. However, older versions -require that you use the ``make_standalone_toolchain.py'' script in -the NDK distribution to create a ``standalone toolchain'', and use -that instead, in order for C++ headers to be found. +In normal circumstances, Emacs should automatically detect and configure +one of the C++ standard libraries part of the NDK when such a library is +required to build a dependency specified under `--with-ndk-path'. -See https://developer.android.com/ndk/guides/standalone_toolchain for -more details; when a ``standalone toolchain'' is specified, the -configure script will try to determine the location of the C++ -compiler based on the C compiler specified. If that automatic -detection does not work, you can specify a C++ compiler yourself, like -so: +Nevertheless, this process is not infalliable, and with certain versions +of the NDK is liable to fail to locate a C++ compiler, requiring that +you run the `make_standalone_toolchain.py' script in the NDK +distribution to create a ``standalone toolchain'' and substitute the +same for the regular compiler toolchain. See +https://developer.android.com/ndk/guides/standalone_toolchain for +further details. - ./configure --with-ndk-cxx=/path/to/toolchain/bin/i686-linux-android-g++ - -Some versions of the NDK have a bug, where GCC fails to locate -``stddef.h'' after being copied to a standalone toolchain. To work -around this problem (which normally exhibits itself when building C++ -code), add: +Some versions of the NDK that ship GCC 4.9.x exhibit a bug where the +compiler cannot locate `stddef.h' after being copied to a standalone +toolchain. To work around this problem, add: -isystem /path/to/toolchain/include/c++/4.9.x diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 6845f833908..898eaef41a7 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java @@ -323,7 +323,9 @@ public static native void blitRect (Bitmap src, Bitmap dest, int x1, Every time you add a new shared library dependency to Emacs, please add it here as well. */ - libraryDeps = new String[] { "png_emacs", "selinux_emacs", + libraryDeps = new String[] { "c++_shared", "gnustl_shared", + "stlport_shared", "gabi++_shared", + "png_emacs", "selinux_emacs", "crypto_emacs", "pcre_emacs", "packagelistparser_emacs", "gnutls_emacs", "gmp_emacs", @@ -331,7 +333,7 @@ public static native void blitRect (Bitmap src, Bitmap dest, int x1, "tasn1_emacs", "hogweed_emacs", "jansson_emacs", "jpeg_emacs", "tiff_emacs", "xml2_emacs", - "icuuc_emacs", + "icuuc_emacs", "harfbuzz_emacs", "tree-sitter_emacs", }; for (String dependency : libraryDeps) diff --git a/m4/ndk-build.m4 b/m4/ndk-build.m4 index aacb2ed048b..7012471e046 100644 --- a/m4/ndk-build.m4 +++ b/m4/ndk-build.m4 @@ -21,10 +21,6 @@ AC_ARG_WITH([ndk_path], [AS_HELP_STRING([--with-ndk-path], [find Android libraries in these directories])]) -AC_ARG_WITH([ndk_cxx_shared], - [AS_HELP_STRING([--with-ndk-cxx-shared], - [name of the C++ standard library included with the NDK])]) - AC_ARG_WITH([ndk_cxx], [AS_HELP_STRING([--with-ndk-cxx], [name of the C++ compiler included with the NDK])]) @@ -59,6 +55,7 @@ ndk_DIR=$3 ndk_ANY_CXX= ndk_BUILD_CFLAGS="$4" ndk_working_cxx=no +ndk_CXX_SHARED= AS_CASE(["$ndk_ABI"], [*arm64*], [ndk_ARCH=arm64], @@ -149,7 +146,7 @@ ndk_resolve_import_module () { for ndk_android_mk in $ndk_module_files; do # Read this Android.mk file. Set NDK_ROOT to /tmp: the Android in - # tree build system sets it to a meaning value, but build files + # tree build system sets it to a meaningful value, but build files # just use it to test whether or not the NDK is being used. ndk_commands=`ndk_run_test` eval "$ndk_commands" @@ -169,13 +166,14 @@ that could not be found in the list of directories specified in \ ndk_ANY_CXX=yes fi - AS_IF([test "$ndk_ANY_CXX" = "yes" && test -z "$with_ndk_cxx_shared"], - [AC_MSG_ERROR([The module [$]1 requires the C++ standard library \ -(libc++_shared.so), but it was not found.])]) + AS_IF([test "$module_cxx_deps" = "yes" && test -z "$ndk_CXX_STL" \ + && test -z "$ndk_CXX_LDFLAGS"], + [AC_MSG_ERROR([The module $1 requires a C++ standard library, +but none were found.])]) - AS_IF([test "$ndk_ANY_CXX" = "yes" && test "$ndk_working_cxx" != "yes"], - [AC_MSG_ERROR([The module [$]1 requires the C++ standard library \ -(libc++_shared.so), but a working C++ compiler was not found.])]) + AS_IF([test "$module_cxx_deps" = "yes" && test "$ndk_working_cxx" != "yes"], + [AC_MSG_ERROR([The module [$]1 requires the C++ standard library, +but a working C++ compiler was not found.])]) AC_MSG_RESULT([yes]) @@ -227,6 +225,88 @@ ndk_subst_cc_onto_cxx () { done } +# ndk_subst_cflags_onto_cxx +# --------------------- +# Print any options in CFLAGS also suitable for a C++ compiler. + +ndk_subst_cflags_onto_cxx () { + ndk_flag= + for ndk_word in $CFLAGS; do + AS_IF([test "$ndk_flag" = "yes"], + [AS_ECHO_N(["$ndk_word "]) + ndk_flag=no], + [AS_CASE([$ndk_word], + [*-sysroot=*], + [AS_ECHO_N(["$ndk_word "])], + [*-isystem*], + [AS_ECHO_N(["$ndk_word "]) + ndk_flag=yes], + [*-I*], + [AS_ECHO_N(["$ndk_word "]) + ndk_flag=yes], + [*-sysroot*], + [AS_ECHO_N(["$ndk_word "]) + ndk_flag=yes], + [-D__ANDROID_API__*], + [AS_ECHO_N(["$ndk_word "])])]) + done +} + +# Detect the installation directory and type of the NDK being used. + +ndk_install_dir= +ndk_toolchain_type= + +AC_MSG_CHECKING([for the directory where the NDK is installed]) + +dnl If the install directory isn't available, repeat the search over +dnl each entry in the programs directory. +ndk_programs_dirs=`$CC -print-search-dirs | sed -n "s/^programs:[[\t ]]*=\?\(.*\)/\1/p"` +ndk_save_IFS=$IFS; IFS=: +for ndk_dir in $ndk_programs_dirs; do + if test -d "$ndk_dir"; then :; else + continue + fi + ndk_dir=`cd "$ndk_dir"; pwd` + while test "$ndk_dir" != "/" && test -z "$ndk_toolchain_type"; do + ndk_dir=`AS_DIRNAME([$ndk_dir])` + AS_IF([test -d "$ndk_dir/bin" && test -d "$ndk_dir/lib"], + [dnl The directory reached is most likely either the directory + dnl holding prebuilt binaries in a combined toolchain or the + dnl directory holding a standalone toolchain itself. + dnl + dnl Distinguish between the two by verifying the name of the + dnl parent directory (and its parent). + ndk_dir1=`AS_DIRNAME(["$ndk_dir"])` + ndk_basename=`AS_BASENAME(["$ndk_dir1"])` + AS_IF([test "$ndk_basename" = "prebuilt"], + [dnl Directories named "prebuilt" are exclusively present in + dnl combined toolchains, where they are children of the + dnl base directory or, in recent releases, a directory + dnl within the base directory. Continue searching for the + dnl base directory. + ndk_toolchain_type=combined + while test "$ndk_dir1" != "/"; do + AS_IF([test -d "$ndk_dir1/toolchains" \ + && test -d "$ndk_dir1/sources"], + [ndk_install_dir=$ndk_dir1 + break]) + ndk_dir1=`AS_DIRNAME(["$ndk_dir1"])` + done], + [ndk_toolchain_type=standalone + ndk_install_dir=$ndk_dir])]) + done + AS_IF([test -n "$ndk_toolchain_type"], + [break]) +done +IFS=$ndk_save_IFS + +AS_IF([test -z "$ndk_install_dir"], + [AC_MSG_RESULT([unknown]) + AC_MSG_WARN([The NDK installation directory could not be \ +derived from the compiler.])], + [AC_MSG_RESULT([$ndk_install_dir ($ndk_toolchain_type)])]) + # Look for a suitable ar and ranlib in the same directory as the C # compiler. ndk_cc_firstword=`AS_ECHO(["$CC"]) | cut -d' ' -f1` @@ -259,72 +339,8 @@ NDK_BUILD_NASM= AS_IF([test "$ndk_ARCH" = "x86" || test "$ndk_ARCH" = "x86_64"], [AC_CHECK_PROGS([NDK_BUILD_NASM], [nasm])]) -# Look for a file named ``libc++_shared.so'' in a subdirectory of -# $ndk_where_cc if it was not specified. -AC_MSG_CHECKING([for libc++_shared.so]) - -ndk_where_toolchain= -AS_IF([test -z "$with_ndk_cxx_shared" && test -n "$ndk_where_cc"],[ - # Find the NDK root directory. Go to $ndk_where_cc. - SAVE_PWD=`pwd` - cd `AS_DIRNAME(["$ndk_where_cc"])` - - # Now, keep moving backwards until pwd ends with ``toolchains''. - while :; do - if test "`pwd`" = "/"; then - cd "$SAVE_PWD" - break - fi - - ndk_pwd=`pwd` - if test "`AS_BASENAME([$ndk_pwd])`" = "toolchains"; then - ndk_where_toolchain=$ndk_pwd - cd "$SAVE_PWD" - break - fi - - cd .. - done - - ndk_matching_libcxx_shared_so= - - # The toolchain directory should be in "$ndk_where_toolchain". - AS_IF([test -n "$ndk_where_toolchain"],[ - # Now, look in the directory behind it. - ndk_cxx_shared_so=`find "$ndk_where_toolchain" -name libc++_shared.so` - - # Look for one with the correct architecture. - for ndk_candidate in $ndk_cxx_shared_so; do - AS_CASE([$ndk_candidate], - [*arm-linux-android*], - [AS_IF([test "$ndk_ARCH" = "arm"], - [ndk_matching_libcxx_shared_so=$ndk_candidate])], - [*aarch64-linux-android*], - [AS_IF([test "$ndk_ARCH" = "arm64"], - [ndk_matching_libcxx_shared_so=$ndk_candidate])], - [*i[[3-6]]86-linux-android*], - [AS_IF([test "$ndk_ARCH" = "x86"], - [ndk_matching_libcxx_shared_so=$ndk_candidate])], - [*x86_64-linux-android*], - [AS_IF([test "$ndk_ARCH" = "x86_64"], - [ndk_matching_libcxx_shared_so=$ndk_candidate])]) - - AS_IF([test -n "$ndk_matching_libcxx_shared_so"], - [with_ndk_cxx_shared=$ndk_matching_libcxx_shared_so]) - done])]) - -AS_IF([test -z "$with_ndk_cxx_shared"],[AC_MSG_RESULT([no]) - AC_MSG_WARN([The C++ standard library could not be found. \ -If you try to build Emacs with a dependency that requires the C++ standard \ -library, Emacs will not build correctly, unless you manually specify the \ -name of an appropriate ``libc++_shared.so'' binary.])], - [AC_MSG_RESULT([$with_ndk_cxx_shared])]) - -ndk_CXX_SHARED=$with_ndk_cxx_shared - -# These variables have now been found. Now look for a C++ compiler. -# Upon failure, pretend the C compiler is a C++ compiler and use that -# instead. +# Search for a C++ compiler. Upon failure, pretend the C compiler is a +# C++ compiler and use that instead. ndk_cc_name=`AS_BASENAME(["${ndk_cc_firstword}"])` ndk_cxx_name= @@ -338,8 +354,162 @@ AS_IF([test -n "$with_ndk_cxx"], [CXX=$with_ndk_cxx], [], [`AS_DIRNAME(["$ndk_where_cc"])`:$PATH]) AS_IF([test -z "$CXX"], [CXX=`ndk_filter_cc_for_cxx`], [CXX=`ndk_subst_cc_onto_cxx`])]) + +# None of the C++ standard libraries installed with Android are +# available to NDK programs, which are expected to select one of several +# standard libraries distributed with the NDK. This library must be +# extracted from the NDK by the program's build system and copied into +# the application directory, and the build system is also expected to +# provide the compiler with suitable options to enable it. +# +# Emacs, on recent releases of the NDK, prefers the libc++ library, the +# most complete of the libraries available, when it detects the presence +# of its headers and libraries in the compiler's search path. Next in +# line are the several libraries located in a directory named `cxx-stl' +# inside the NDK distribution, of which Emacs prefers, in this order, +# the GNU libstdc++, stlport, gabi and the system C++ library. The +# scope of the last two is confined to providing runtime support for +# basic C++ operations, and is useless for compiling most C++ +# dependencies whose requirements go beyond such operations. +# +# The NDK comes in two forms. In a "combined toolchain", all C++ +# libraries are present in the NDK directory and the responsibility is +# left to the build system to locate and select the best C++ library, +# whereas in a "standalone toolchain" an STL will have already been +# specified a C++ library, besides which no others will be present. +# +# Though Android.mk files are provided by the NDK for each such library, +# Emacs cannot use any of these, both for lack of prebuilt support in +# its ndk-build implementation, and since they are absent from combined +# toolchains. + +ndk_CXX_SHARED= +ndk_CXX_STL= +ndk_CXX_LDFLAGS= + +AS_IF([test -n "$CXX" && test -n "$ndk_install_dir"], + [ndk_library_dirs=`$CXX -print-search-dirs \ + | sed -n "s/^libraries:[[\t ]]*=\?\(.*\)/\1/p"` + AS_IF([test "$ndk_toolchain_type" = "standalone"], + [dnl With a standalone toolchain, just use the first C++ library + dnl present in the compiler's library search path, that being the + dnl only C++ library that will ever be present. + ndk_save_IFS=$IFS; IFS=: + for ndk_dir in $ndk_library_dirs; do + if test -d "$ndk_dir"; then :; else + continue + fi + ndk_dir=`cd "$ndk_dir"; pwd` + if test -f "$ndk_dir/libc++_shared.so"; then + ndk_CXX_SHARED="$ndk_dir/libc++_shared.so" + ndk_CXX_LDFLAGS=-lc++_shared; break + elif test -f "$ndk_dir/libgnustl_shared.so"; then + ndk_CXX_SHARED="$ndk_dir/libgnustl_shared.so" + ndk_CXX_LDFLAGS=-lgnustl_shared; break + elif test -f "$ndk_dir/libstlport_shared.so"; then + ndk_CXX_SHARED="$ndk_dir/libstlport_shared.so" + ndk_CXX_LDFLAGS=-lstlport_shared; break + fi + done + IFS=$ndk_save_IFS], + [dnl Otherwise, search for a suitable standard library + dnl in the order stated above. + dnl + dnl Detect if this compiler is configured to link against libc++ by + dnl default. + AC_MSG_CHECKING([whether compiler defaults to libc++]) + cat <<_ACEOF >conftest.cc +#include +#ifndef _LIBCPP_VERSION +Not libc++! +#endif /* _LIBCPP_VERSION */ + +int +main (void) +{ + +} +_ACEOF + AS_IF([$CXX conftest.cc -o conftest.o >&AS_MESSAGE_LOG_FD 2>&1], + [dnl The compiler defaults to libc++. + AC_MSG_RESULT([yes]) + ndk_save_IFS=$IFS; IFS=: + for ndk_dir in $ndk_library_dirs; do + if test -f "$ndk_dir/libc++_shared.so"; then + ndk_CXX_SHARED="$ndk_dir/libc++_shared.so" + ndk_CXX_LDFLAGS=-lc++_shared; break + fi + done + IFS=$ndk_save_IFS], + [dnl Search for gnustl, stlport, gabi, and failing that, system. + dnl The name of the gabi system root directory varies by GCC + dnl version. + AC_MSG_RESULT([no]) + ndk_gcc_version=`($CXX -v 2>&1) \ + | sed -n "s/^gcc version \([[0123456789]\+.[0123456789]\+]\).*/\1/p"` + cxx_stl="$ndk_install_dir/sources/cxx-stl" + ndk_cxx_stl_base="$cxx_stl/gnu-libstdc++/$ndk_gcc_version" + AS_IF([test -n "$ndk_gcc_version" \ + && test -d "$ndk_cxx_stl_base/libs/$ndk_ABI"], + [ndk_CXX_LDFLAGS="-L$ndk_cxx_stl_base/libs/$ndk_ABI -lgnustl_shared" + ndk_CXX_LDFLAGS="$ndk_CXX_LDFLAGS -lsupc++" + ndk_CXX_STL="-isystem $ndk_cxx_stl_base/include" + ndk_CXX_STL="$ndk_CXX_STL -isystem $ndk_cxx_stl_base/libs/$ndk_ABI/include" + ndk_CXX_SHARED="$ndk_cxx_stl_base/libs/$ndk_ABI/libgnustl_shared.so"]) + AS_IF([test -f "$ndk_CXX_SHARED"], [], + [dnl No STL was located or the library is not reachable. + dnl Search for alternatives. + ndk_CXX_STL= + ndk_CXX_SHARED= + ndk_CXX_LDFLAGS= + ndk_cxx_stl_base="$cxx_stl/stlport" + AS_IF([test -d "$ndk_cxx_stl_base"], + [ndk_CXX_LDFLAGS="-L$ndk_cxx_stl_base/libs/$ndk_ABI -lstlport_shared" + ndk_CXX_STL="-isystem $ndk_cxx_stl_base/stlport" + ndk_CXX_SHARED="$ndk_cxx_stl_base/libs/$ndk_ABI/libstlport_shared.so"]) + AS_IF([test -f "$ndk_CXX_SHARED"], [], + [ndk_CXX_STL= + ndk_CXX_SHARED= + ndk_CXX_LDFLAGS= + ndk_cxx_stl_base="$cxx_stl/gabi++" + AS_IF([test -d "$ndk_cxx_stl_base"], + [ndk_CXX_LDFLAGS="-L$ndk_cxx_stl_base/libs/$ndk_ABI -lgabi++_shared" + ndk_CXX_STL="$ndk_CXX_STL -isystem $ndk_cxx_stl_base/include" + ndk_CXX_SHARED="$ndk_cxx_stl_base/libs/$ndk_ABI/lgabi++_shared.so"])]) + AS_IF([test -f "$ndk_CXX_SHARED"], [], + [ndk_CXX_STL= + ndk_CXX_SHARED= + ndk_CXX_LDFLAGS= + ndk_cxx_stl_base="$cxx_stl/system" + AS_IF([test -d "$ndk_cxx_stl_base"], + [ndk_CXX_LDFLAGS="-L$ndk_cxx_stl_base/libs/$ndk_ABI -lstdc++" + ndk_CXX_STL="-isystem $ndk_cxx_stl_base/include" + dnl The "system" library is distributed with Android and + dnl need not be present in app packages. + ndk_CXX_SHARED= + dnl Done. + ])])])]) + rm -f conftest.o])]) + +AS_ECHO([]) +AS_ECHO(["C++ compiler configuration: "]) +AS_ECHO([]) +AS_ECHO(["Library includes : $ndk_CXX_STL"]) +AS_ECHO(["Linker options : $ndk_CXX_LDFLAGS"]) +AS_ECHO(["Library file (if any) : $ndk_CXX_SHARED"]) +AS_ECHO([]) ]) +# ndk_LATE_EARLY +# -------------- +# Call before ndk_LATE to establish certain variables in time for +# ndk_LATE's C++ compiler detection. + +AC_DEFUN([ndk_LATE_EARLY], +[ndk_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $ndk_CXX_LDFLAGS" + CXXFLAGS="$CXXFLAGS `ndk_subst_cflags_onto_cxx` $ndk_CXX_STL"]) + # ndk_LATE # -------- # Perform late initialization of the ndk-build system by checking for @@ -347,17 +517,14 @@ AS_IF([test -n "$with_ndk_cxx"], [CXX=$with_ndk_cxx], AC_DEFUN([ndk_LATE], [dnl -dnl This calls AC_REQUIRE([AC_PROG_CXX]), leading to configure looking -dnl for a C++ compiler. However, the language is not restored -dnl afterwards if not `$ndk_INITIALIZED'. AS_IF([test "$ndk_INITIALIZED" = "yes"],[ - AS_IF([test -n "$CXX"], [AC_LANG_PUSH([C++]) + AS_IF([test -n "$CXX"], [ + AC_LANG_PUSH([C++]) AC_CHECK_HEADER([string], [ndk_working_cxx=yes], - [AC_MSG_WARN([Your C++ compiler is not properly set up, and\ - the standard library headers could not be found.])]) + [AC_MSG_WARN([Your C++ compiler is not properly configured, as \ +the standard library headers could not be found.])]) AC_LANG_POP([C++])])]) -dnl Thus, manually switch back to C here. -AC_LANG([C]) +LDFLAGS="$ndk_save_LDFLAGS" ]) # ndk_SEARCH_MODULE(MODULE, NAME, ACTION-IF-FOUND, [ACTION-IF-NOT-FOUND]) @@ -396,13 +563,14 @@ else ndk_ANY_CXX=yes fi - AS_IF([test "$ndk_ANY_CXX" = "yes" && test -z "$with_ndk_cxx_shared"], - [AC_MSG_ERROR([The module $1 requires the C++ standard library \ -(libc++_shared.so), but it was not found.])]) + AS_IF([test "$module_cxx_deps" = "yes" && test -z "$ndk_CXX_STL" \ + && test -z "$ndk_CXX_LDFLAGS"], + [AC_MSG_ERROR([The module $1 requires a C++ standard library, +but none were found.])]) - AS_IF([test "$ndk_ANY_CXX" = "yes" && test "$ndk_working_cxx" != "yes"], - [AC_MSG_ERROR([The module [$]1 requires the C++ standard library \ -(libc++_shared.so), but a working C++ compiler was not found.])]) + AS_IF([test "$module_cxx_deps" = "yes" && test "$ndk_working_cxx" != "yes"], + [AC_MSG_ERROR([The module [$]1 requires the C++ standard library, +but a working C++ compiler was not found.])]) $2[]_CFLAGS="[$]$2[]_CFLAGS $module_cflags $module_includes" $2[]_LIBS="[$]$2[]_LIBS $module_ldflags" @@ -457,6 +625,8 @@ AC_DEFUN_ONCE([ndk_CONFIG_FILES], NDK_BUILD_AR=$AR NDK_BUILD_MODULES="$ndk_MODULES" NDK_BUILD_CXX_SHARED="$ndk_CXX_SHARED" + NDK_BUILD_CXX_STL="$ndk_CXX_STL" + NDK_BUILD_CXX_LDFLAGS="$ndk_CXX_LDFLAGS" NDK_BUILD_ANY_CXX_MODULE=$ndk_ANY_CXX NDK_BUILD_CFLAGS="$ndk_BUILD_CFLAGS" @@ -470,6 +640,8 @@ AC_DEFUN_ONCE([ndk_CONFIG_FILES], AC_SUBST([NDK_BUILD_NASM]) AC_SUBST([NDK_BUILD_MODULES]) AC_SUBST([NDK_BUILD_CXX_SHARED]) + AC_SUBST([NDK_BUILD_CXX_STL]) + AC_SUBST([NDK_BUILD_CXX_LDFLAGS]) AC_SUBST([NDK_BUILD_ANY_CXX_MODULE]) AC_SUBST([NDK_BUILD_CFLAGS])