From 4de6b187933479ce93b6079f42a485e5868f01a5 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 24 Jan 2023 10:34:40 +0800 Subject: [PATCH] Update Android port * .gitignore: Update with new files. Do not ignore std*.in.h. * INSTALL.android: Explain how to build Emacs with external dependencies. * Makefile.in (xcompile, cross): Rename to `cross'. (clean_dirs): Clean cross, not xcompile. * README: Document new directories. * build-aux/ndk-build-helper-1.mk (build_kind, NDK_SO_NAMES): * build-aux/ndk-build-helper-2.mk (build_kind, NDK_SO_NAMES): * build-aux/ndk-build-helper-3.mk (build_kind): * build-aux/ndk-build-helper-4.mk: * build-aux/ndk-build-helper.mk (NDK_BUILD_DIR, my-dir): * build-aux/ndk-module-extract.awk: New files. * configure.ac: Set up libgif, libwebp, and libpng for ndk-build. * cross/ndk-build/Makefile.in (srcdir, NDK_BUILD_ANDROID_MK): * cross/ndk-build/ndk-build-executable.mk: * cross/ndk-build/ndk-build-shared-library.mk (eq, objname): * cross/ndk-build/ndk-build-static-library.mk (eq, objname): * cross/ndk-build/ndk-build.in (NDK_BUILD_MODULES): * cross/ndk-build/ndk-build.mk.in (NDK_BUILD_MODULES) (NDK_BUILD_SHARED): * cross/ndk-build/ndk-clear-vars.mk: * cross/ndk-build/ndk-prebuilt-shared-library.mk: * cross/ndk-build/ndk-prebuilt-static-library.mk: New files. * doc/emacs/android.texi (Android, Android Environment): Document clipboard support on Android. * doc/emacs/emacs.texi (Top): Update menus. * etc/MACHINES: Document Android. * java/AndroidManifest.xml.in: Respect new `--with-android-debug' option. * java/Makefile.in (CROSS_BINS, CROSS_LIBS): Adjust for rename. Include ndk-build.mk.:(emacs.apk-in): Depend on shared libraries. Then, package shared libraries. * java/org/gnu/emacs/EmacsClipboard.java (EmacsClipboard): New class. * java/org/gnu/emacs/EmacsFontDriver.java: Update comment to say this is unused. * java/org/gnu/emacs/EmacsNative.java (EmacsNative): New function `sendExpose'. * java/org/gnu/emacs/EmacsSdk11Clipboard.java (EmacsSdk11Clipboard): * java/org/gnu/emacs/EmacsSdk8Clipboard.java (EmacsSdk8Clipboard): New classes. * java/org/gnu/emacs/EmacsView.java (EmacsView, handleDirtyBitmap) (onDetachedFromWindow): When window is reattached, expose the frame. * lib/Makefile.in (VPATH): (ALL_CFLAGS): Adjust for rename. * lisp/term/android-win.el (android-clipboard-exists-p) (android-get-clipboard, android-set-clipboard) (android-clipboard-owner-p, android-primary-selection) (android-get-clipboard-1, android-get-primary) (android-selection-bounds, android-encode-select-string) (gui-backend-get-selection, gui-backend-selection-exists-p) (gui-backend-selection-owner-p, gui-backend-set-selection): New functions. * m4/ndk-build.m4: New file. * src/Makefile.in (GIF_CFLAGS, ANDROID_LDFLAGS): New variables. (EMACS_CFLAGS): Add GIF_CFLAGS. Include ndk-build.mk. (libemacs.so): Depend on and link with required libraries. * src/android.c (android_check_compressed_file): New function. (android_open): Work around Android platform bug. (sendExpose): New function. (android_readdir): Set d_type if this is a directory. * src/androidgui.h (enum android_event_type) (struct android_expose_event, union android_event): Add expose events. * src/androidselect.c (struct android_emacs_clipboard) (android_init_emacs_clipboard, Fandroid_clipboard_owner_p) (Fandroid_set_clipboard, Fandroid_get_clipboard) (Fandroid_clipboard_exists_p, init_androidselect) (syms_of_androidselect): New file. * src/androidterm.c (handle_one_android_event): Handle exposures. * src/androidterm.h: Update prototypes. * src/emacs.c (android_emacs_init): Initialize androidselect. --- .gitignore | 64 ++-- INSTALL.android | 334 +++++++++++++++++- Makefile.in | 4 +- README | 3 + build-aux/ndk-build-helper-1.mk | 92 +++++ build-aux/ndk-build-helper-2.mk | 87 +++++ build-aux/ndk-build-helper-3.mk | 28 ++ build-aux/ndk-build-helper-4.mk | 38 ++ build-aux/ndk-build-helper.mk | 52 +++ build-aux/ndk-module-extract.awk | 64 ++++ configure.ac | 90 ++++- cross/ndk-build/Makefile.in | 115 ++++++ cross/ndk-build/ndk-build-executable.mk | 22 ++ cross/ndk-build/ndk-build-shared-library.mk | 83 +++++ cross/ndk-build/ndk-build-static-library.mk | 83 +++++ cross/ndk-build/ndk-build.in | 44 +++ cross/ndk-build/ndk-build.mk.in | 43 +++ cross/ndk-build/ndk-clear-vars.mk | 47 +++ .../ndk-build/ndk-prebuilt-shared-library.mk | 24 ++ .../ndk-build/ndk-prebuilt-static-library.mk | 24 ++ doc/emacs/android.texi | 29 +- doc/emacs/emacs.texi | 1 + etc/MACHINES | 8 + java/AndroidManifest.xml.in | 5 +- java/Makefile.in | 30 +- java/org/gnu/emacs/EmacsClipboard.java | 44 +++ java/org/gnu/emacs/EmacsFontDriver.java | 3 + java/org/gnu/emacs/EmacsNative.java | 4 + java/org/gnu/emacs/EmacsSdk11Clipboard.java | 156 ++++++++ java/org/gnu/emacs/EmacsSdk8Clipboard.java | 116 ++++++ java/org/gnu/emacs/EmacsView.java | 23 ++ lib/Makefile.in | 4 +- lisp/term/android-win.el | 106 ++++++ m4/ndk-build.m4 | 213 +++++++++++ src/Makefile.in | 19 +- src/android.c | 82 ++++- src/androidgui.h | 11 + src/androidselect.c | 249 +++++++++++++ src/androidterm.c | 22 ++ src/androidterm.h | 9 + src/emacs.c | 2 + 41 files changed, 2406 insertions(+), 71 deletions(-) create mode 100644 build-aux/ndk-build-helper-1.mk create mode 100644 build-aux/ndk-build-helper-2.mk create mode 100644 build-aux/ndk-build-helper-3.mk create mode 100644 build-aux/ndk-build-helper-4.mk create mode 100644 build-aux/ndk-build-helper.mk create mode 100644 build-aux/ndk-module-extract.awk create mode 100644 cross/ndk-build/Makefile.in create mode 100644 cross/ndk-build/ndk-build-executable.mk create mode 100644 cross/ndk-build/ndk-build-shared-library.mk create mode 100644 cross/ndk-build/ndk-build-static-library.mk create mode 100644 cross/ndk-build/ndk-build.in create mode 100644 cross/ndk-build/ndk-build.mk.in create mode 100644 cross/ndk-build/ndk-clear-vars.mk create mode 100644 cross/ndk-build/ndk-prebuilt-shared-library.mk create mode 100644 cross/ndk-build/ndk-prebuilt-static-library.mk create mode 100644 java/org/gnu/emacs/EmacsClipboard.java create mode 100644 java/org/gnu/emacs/EmacsSdk11Clipboard.java create mode 100644 java/org/gnu/emacs/EmacsSdk8Clipboard.java create mode 100644 m4/ndk-build.m4 create mode 100644 src/androidselect.c diff --git a/.gitignore b/.gitignore index 6494e4e8f39..6b624767c66 100644 --- a/.gitignore +++ b/.gitignore @@ -96,36 +96,40 @@ src/lisp.mk src/verbose.mk # Stuff built during cross compilation -xcompile/lib/alloca.h -xcompile/lib/assert.h -xcompile/lib/byteswap.h -xcompile/lib/dirent.h -xcompile/lib/errno.h -xcompile/lib/execinfo.h -xcompile/lib/fcntl.h -xcompile/lib/getopt.h -xcompile/lib/getopt-cdefs.h -xcompile/lib/gmp.h -xcompile/lib/ieee754.h -xcompile/lib/inttypes.h -xcompile/lib/libgnu.a -xcompile/lib/limits.h -xcompile/lib/malloc/*.gl.h -xcompile/lib/signal.h -xcompile/lib/std*.h -xcompile/!lib/std*.in.h -xcompile/!lib/stdio-impl.h -xcompile/lib/string.h -xcompile/lib/sys/ -xcompile/lib/time.h -xcompile/lib/unistd.h -xcompile/lib/config.h -xcompile/lib/gnulib.mk -xcompile/src/* -xcompile/lib-src/* -xcompile/sys/* -xcompile/config.status -xcompile/*.bak +cross/lib/alloca.h +cross/lib/assert.h +cross/lib/byteswap.h +cross/lib/dirent.h +cross/lib/errno.h +cross/lib/execinfo.h +cross/lib/fcntl.h +cross/lib/getopt.h +cross/lib/getopt-cdefs.h +cross/lib/gmp.h +cross/lib/ieee754.h +cross/lib/inttypes.h +cross/lib/libgnu.a +cross/lib/limits.h +cross/lib/malloc/*.gl.h +cross/lib/signal.h +cross/lib/std*.h +!cross/lib/std*.in.h +!cross/lib/stdio-impl.h +cross/lib/string.h +cross/lib/sys/ +cross/lib/time.h +cross/lib/unistd.h +cross/lib/config.h +cross/lib/gnulib.mk +cross/src/* +cross/lib-src/* +cross/sys/* +cross/config.status +cross/*.bak + +cross/ndk-build/Makefile +cross/ndk-build/ndk-build.mk +cross/ndk-build/*.o # Lisp-level sources built by 'make'. *cus-load.el diff --git a/INSTALL.android b/INSTALL.android index 63c856fe56c..9abea74a55d 100644 --- a/INSTALL.android +++ b/INSTALL.android @@ -62,7 +62,7 @@ medium) and installed on-device. BUILDING WITH OLD NDK VERSIONS Building Emacs with an old version of the Android NDK requires special -setup. This is because there is no separate C compiler binary for +setup. This is because there is no separate C compiler binary for each version of Android in those versions of the NDK. Before running `configure', you must identify three variables: @@ -94,7 +94,339 @@ Emacs is known to build for Android 2.2 (API version 8) or later, and run on Android 2.3 or later. It is supposed to run on Android 2.2 as well. +DEBUG AND RELEASE BUILDS + +Android makes a distinction between ``debug'' and ``release'' builds +of applications. With ``release'' builds, the system will apply +stronger optimizations to the application at the cost of being unable +to debug them with the steps in etc/DEBUG. + +Emacs is built as a debuggable package by default, but: + + ./configure --without-android-debug + +will create a release build of Emacs instead. This may be useful when +running Emacs on resource constrained machines. + +If you are building an Emacs package for redistribution, we urge you +to provide both debug and release versions. + +BUILDING WITH THIRD PARTY LIBRARIES + +The Android NDK does not support the usual ways of locating third +party libraries, especially not via `pkg-config'. Instead, it uses +its own system called `ndk-build'. The one exception to this rule is +zlib, which is considered a part of the Android OS itself and is +available on all devices running Android. + +Android also requires that each application include its own +dependencies, as the system makes no guarantee about the existence of +any particular library. + +Emacs is not built with the `ndk-build' system. Instead, it is built +with Autoconf and Make. + +However, it supports building and including dependencies which use the +similarly Make-based `ndk-build' system. + +To use dependencies built through `ndk-build', you must specify a list +of directories within which Emacs will search for ``Android.mk'' +files, like so: + + ./configure "--with-ndk-path=directory1 directory2" + +Emacs will then read the ``Android.mk'' file in each directory, and +automatically build and use those modules. + +Google, Inc. has adapted many common Emacs dependencies to use the +`ndk-build' system. Here is a non-exhaustive list of what is known to +work: + + libpng - https://android.googlesource.com/platform/external/libpng + libwebp - https://android.googlesource.com/platform/external/webp + giflib - https://android.googlesource.com/platform/external/giflib + (You must add LOCAL_EXPORT_CFLAGS := -I$(LOCAL_PATH) before + its Android.mk includes $(BUILD_STATIC_LIBRARY)) + +We anticipate that most untested non-trivial ndk-build dependencies +will need adjustments in Emacs to work, as the Emacs build system +which emulates ndk-build is in an extremely early state. + +NDK BUILD SYSTEM IMPLEMENTATION + +Emacs implements ndk-build itself, because the version that comes with +the Android NDK is not easy to use from another Makefile, and keeps +accumulating incompatible changes. + +The Emacs implementation of ndk-build consists of one m4 file: + + m4/ndk-build.m4 + +four Makefiles in build-aux, run during configure: + + build-aux/ndk-build-helper-1.mk + build-aux/ndk-build-helper-2.mk + build-aux/ndk-build-helper-3.mk + build-aux/ndk-build-helper.mk + +one awk script in build-awx, run during configure: + + build-aux/ndk-module-extract.awk + +six Makefiles in cross/ndk-build, + + cross/ndk-build/ndk-build-shared-library.mk + cross/ndk-build/ndk-build-static-library.mk + cross/ndk-build/ndk-build-executable.mk + cross/ndk-build/ndk-clear-vars.mk + cross/ndk-build/ndk-prebuilt-shared-library.mk + cross/ndk-build/ndk-prebuilt-static-library.mk + +and finally, two more Makefiles in cross/ndk-build, generated by +configure: + + cross/ndk-build/Makefile (generated from cross/ndk-build/Makefile.in) + cross/ndk-build/ndk-build.mk (generated from cross/ndk-build/ndk-build.mk.in) + +m4/ndk-build.m4 is a collection of macros which are used by the +configure script to set up the ndk-build system, look for modules, add +the appropriate options to LIBS and CFLAGS, and generate the Makefiles +necessary to build the rest of Emacs. + +Immediately after determining the list of directories in which to look +for ``Android.mk'' files, the version and type of Android system being +built for, configure calls: + + ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build]) + +This expands to a sequence of shell script that enumerates all of the +Android.mk files specified in "$with_ndk_path", sets up some shell +functions used by the rest of the ndk-build code run by the configure +script, and teaches the ndk-build system that the Makefiles to be +generated are found in the directory "cross/ndk-build/Makefile". + +When configure is cross-compiling for Android, the macro +EMACS_CHECK_MODULES will expand to the macro ndk_CHECK_MODULES, +instead of pkg-config.m4's PKG_CHECK_MODULES. Thus, the following +code: + + EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0]) + +will actually expand to: + + ndk_CHECK_MODULES([PNG], [libpng >= 1.0.0], [HAVE_PNG=yes], + [HAVE_PNG=no]) + +which in turn expands to a sequence shell script that first invokes: + + make -f build-aux/ndk-build-helper.mk + +for each ``Android.mk'' file found by ndk_INIT, with the following +variables given to Make: + + EMACS_SRCDIR=. # the source directory (in which configure is running) + EMACS_ABI=$ndk_ABI # this is the $android_abi given to ndk_INIT + ANDROID_MAKEFILE="/opt/android/libpng/Android.mk" + ANDROID_MODULE_DIRECTORY="/opt/android/libpng" + NDK_BUILD_DIR="$ndk_DIR" # this is the directory given as to ndk_INIT + +build-aux/ndk-build-helper.mk will then evaluate the contents +$(ANDROID_MAKEFILE), the ``Android.mk'' file, for the first time. The +purpose of this evaluation is to establish a list of packages (or +modules) provided by the ``Android.mk'' file, and the corresponding +Makefile targets and compiler and linker flags required to build and +link to those tagets. + +Before doing so, build-aux/ndk-build-helper.mk will define several +variables and functions required by all ``Android.mk'' files. The +most important of these are: + + my-dir # the directory containing the Android.mk file. + BUILD_SHARED_LIBRARY # build-aux/ndk-build-helper-1.mk + BUILD_STATIC_LIBRARY # build-aux/ndk-build-helper-2.mk + BUILD_EXECUTABLE # build-aux/ndk-build-helper-3.mk + CLEAR_VARS # build-aux/ndk-build-helper-4.mk + +Then, ``Android.mk'' will include $(CLEAN_VARS) (to clear variables +previously set), set several variables describing each module to the +ndk-build system, and include one of $(BUILD_SHARED_LIBRARY), +$(BUILD_STATIC_LIBRARY) and $(BUILD_EXECUTABLE). + +Each one of those three scripts will then read from the variables set +by ``Android.mk'', resolve dependencies, and print out some text +describing the module to Emacs. For example, the shared library +module "libpng" results in the following text being printed: + +Building shared +libpng +/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c +-I/opt/android/libpng + + -L/opt/emacs/cross/ndk-build -l:libpng_emacs.so +libpng_emacs.so +End + +The output is arranged as follows: + + - The first line consists of the word ``Building'', followed by + either ``shared'', ``static'', or ``executable'', depending on + what type of module being built. + + - The second line consists of the name of the module currently being + built. + + - The third line consists of all of the source code files comprising + the module. + + - The fourth line consists of the text that has to be added to + CFLAGS in order to find the includes associated with the module. + + - The fifth line consists of the text that has to be added to LIBS + in order to link with this module and all of its dependencies. + + - The sixth line consists of the Make targets (more on this later) + that will build the final shared object or library archive of this + module, along with all of its dependencies. + +The output from Make is given to an awk script, +build-aux/ndk-module-extract.awk. This is responsible for parsing the +that output and filtering out modules other than what is being built: + + awk -f build-aux/ndk-module-extract.awk MODULE=libpng + +eventually generating this section of shell script: + +module_name=libpng +module_kind=shared +module_src="/opt/android/libpng/png.c /opt/android/libpng/pngerror.c /opt/android/libpng/pngget.c /opt/android/libpng/pngmem.c /opt/android/libpng/pngpread.c /opt/android/libpng/pngread.c /opt/android/libpng/pngrio.c /opt/android/libpng/pngrtran.c /opt/android/libpng/pngrutil.c /opt/android/libpng/pngset.c /opt/android/libpng/pngtrans.c /opt/android/libpng/pngwio.c /opt/android/libpng/pngwrite.c /opt/android/libpng/pngwtran.c /opt/android/libpng/pngwutil.c" +module_includes="-I/opt/android/libpng" +module_cflags="" +module_ldflags=" -L/opt/emacs/cross/ndk-build -l:libpng_emacs.so" +module_target="libpng_emacs.so" + +which is then evaluated by `configure'. Once the variable +`module_name' is set, configure apends the remaining +$(module_includes), $(module_cflags) and $(module_ldflags) to the +module's CFLAGS and LIBS variables, and appends the list of Makefile +targets specified to the variable NDK_BUILD_MODULES. + +Finally, immediately before generating src/Makefile.android, configure +expands: + + ndk_CONFIG_FILES + +to generate $ndk_DIR/Makefile and $ndk_DIR/ndk-build.mk. + +Now, the $ndk_DIR directory is set up to build all modules upon which +depends, and $ndk_DIR/ndk-build.mk includes a list of files required +to link Emacs, along with the rules to chdir into $ndk_DIR in order to +build them. + +$ndk_DIR/ndk-build.mk is included by cross/src/Makefile +(Makefile.android) and java/Makefile. It defines three different +variables: + + NDK_BUILD_MODULES the file names of all modules to be built. + NDK_BUILD_STATIC absolute names of all library archives + to be built. + NDK_BUILD_SHARED absolute names of all shared libraries to + be built. + +and then proceeds to define rules to build each of the modules in +$(NDK_BUILD_MODULES). + +cross/src/Makefile arranges to have all dependencies of Emacs not +already built built before linking ``libemacs.so'' with them. + +java/Makefile additionally arranges to have all shared object +dependencies built before the application package is built, which is +normally redundant because they should have already been built before +linking ``libemacs.so''. + +Building the modules is performed through $ndk_DIR/Makefile, which +contains the actual implementation of the ``ndk-build'' build system. +First, it defines certain variables constant within the ``ndk-build'' +build system, such as the files included by ``Android.mk'' to build +shared or static libraries, and CLEAR_VARS. The most important of +these are: + + CLEAR_VARS cross/ndk-build/ndk-clear-vars.mk + BUILD_EXECUTABLE cross/ndk-build/ndk-build-executable.mk + BUILD_SHARED_LIBRARY cross/ndk-build/ndk-build-shared-library.mk + BUILD_STATIC_LIBRARY cross/ndk-build/ndk-build-static-library.mk + PREBUILT_SHARED_LIBRARY cross/ndk-build/ndk-prebuilt-shared-library.mk + PREBUILT_STATIC_LIBRARY cross/ndk-build/ndk-prebuilt-static-library.mk + +Then, it loads each Emacs dependency's ``Android.mk'' file. For each +module defined there, ``Android.mk'' includes $(CLEAR_VARS) to unset +all variables specific to each module, and then includes +$(BUILD_SHARED_LIBRARY) or $(BUILD_STATIC_LIBRARY) for each shared or +static library module. + +This results in cross/ndk-build/ndk-build-shared-library.mk or +cross/ndk-build/ndk-build-static-library being included, just like the +Makefiles in build-aux were inside the configure script. + +Each one of those two scripts then defines rules to build all of the +object files associated with the module, and then link or archive +them. The name under which the module is linked is the same as the +Make target found on the sixth line of output from +build-aux/ndk-build-helper.mk. + +However, none of the Makefiles in +cross/ndk-build/ndk-build-shared-library.mk perform any kind of +dependency resolution! Instead, they only define rules to build +individual modules, leaving dependency resolution up to the Makefiles +in the `build-aux' directory. + +libpng is a very simple module, providing only a single shared object +module. This module is named libpng_emacs.so and is eventually built +and packaged into the library directory of the Emacs application +package. Now, let us look at a more complex module, libwebp: + + +When built with libwebp, Emacs depends on a single library, +libwebpdemux. This library is named ``libwebpdemux'' on Unix systems, +and that is the name by which it is found with pkg-config. + +However, the library's module is only named ``webpdemux'' on Android. +When ndk_CHECK_MODULES begins to look for a module, it first tries to +see if its name is found in the variable `ndk_package_map', which was +set inside ndk_INIT. In this case, it finds the following word: + + libwebpdemux:webpdemux + +and immediately replaces ``libwebpdemux'' with ``webpdemux''. + +Then, it locates the ``Android.mk'' file containing a static library +module named webpdemux and gives the output from +build-aux/ndk-build-helper.mk to the awk script, resulting in: + +module_name=webpdemux +module_kind=static +module_src="/opt/android/webp/src/demux/anim_decode.c /opt/android/webp/src/demux/demux.c" +module_includes="-I/opt/android/webp/src" +module_cflags="" +module_ldflags=" cross/ndk-build/libwebpdemux.a cross/ndk-build/libwebp.a cross/ndk-build/libwebpdecoder_static.a " +module_target="libwebpdemux.a libwebp.a libwebpdecoder_static.a" + +The attentive reader will notice that in addition to the +``libwebpdemux.a'' archive associated with the ``webpdemux'' library, +Emacs has been made to link with two additional libraries. This is +because the ``webpdemux'' module specifies a dependency on the +``webp'' module (defined in the same Android.mk). +build-aux/ndk-build-helper.mk resolved that dependency, noticing that +it in turn specified another dependency on ``webpdecoder_static'', +which in turn was added to the linker command line and list of targets +to build. + +As a result, all three dependencies will be built and linked to Emacs, +instead of just the single ``webpdemux'' dependency that was +specified. + + + This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify diff --git a/Makefile.in b/Makefile.in index 0090b858228..c4b346128dc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -539,7 +539,7 @@ lib lib-src lisp nt: Makefile java: lisp info $(MAKE) -C $@ all -xcompile: src +cross: src $(MAKE) -C $@ all trampolines: src lisp @@ -1012,7 +1012,7 @@ mostlyclean: $(mostlyclean_dirs:=_mostlyclean) ### with them. ### ### Delete '.dvi' files here if they are not part of the distribution. -clean_dirs = $(mostlyclean_dirs) java xcompile nextstep admin/charsets \ +clean_dirs = $(mostlyclean_dirs) java cross nextstep admin/charsets \ admin/unidata $(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean))) diff --git a/README b/README index 19d5c96e348..c8a3d485c28 100644 --- a/README +++ b/README @@ -95,6 +95,9 @@ There are several subdirectories: 'admin' holds files used by Emacs developers, and Unicode data files. 'build-aux' holds auxiliary files used during the build. 'm4' holds Autoconf macros used for generating the configure script. +'java' holds the Java code for the Emacs port to Android. +'cross' holds Makefiles and an additional copy of gnulib used to build + Emacs for Android devices. Building Emacs on non-Posix platforms requires tools that aren't part of the standard distribution of the OS. The platform-specific README diff --git a/build-aux/ndk-build-helper-1.mk b/build-aux/ndk-build-helper-1.mk new file mode 100644 index 00000000000..fb8e4da2f0a --- /dev/null +++ b/build-aux/ndk-build-helper-1.mk @@ -0,0 +1,92 @@ +# ndk-build-helper-1.mk -- Helper for ndk-build.m4. +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# Print out information now defined. Important details include: +# - list of source files to compile. +# - module export include directories. +# - module export CFLAGS. +# - module export LDFLAGS. +# - module name. + +build_kind = shared +NDK_SO_NAMES = +NDK_A_NAMES = + +# Record this module's dependencies. This information is used later +# on to recurse over libraries. +NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES) +NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) + +$(info Building $(build_kind)) +$(info $(LOCAL_MODULE)) +$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)?,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI)))) + +$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir))) +$(info $(LOCAL_EXPORT_CFLAGS)) +ifeq ($(LOCAL_MODULE_FILENAME),) +ifeq ($(findstring lib,$(LOCAL_MODULE)),lib) +NDK_SO_NAMES = $(LOCAL_MODULE)_emacs.so +else +NDK_SO_NAMES = lib$(LOCAL_MODULE)_emacs.so +endif +else +NDK_SO_NAMES = $(LOCAL_MODULE_FILENAME).so +endif + +define add-a-name +ifeq ($(findstring lib,$(1)),lib) +NDK_A_NAME = $(1).a +else +NDK_A_NAME = lib$(1).a +endif + +ifeq ($$(NDK_A_NAMES:$$(NDK_A_NAME)=),$$(NDK_A_NAMES)) +NDK_A_NAMES := $$(NDK_A_NAMES) $$(NDK_A_NAME) + +# Now recurse over this module's dependencies. +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module)))) +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module)))) +endif +endef + +define add-so-name +ifeq ($(findstring lib,$(1)),lib) +NDK_SO_NAME = $(1)_emacs.so +else +NDK_SO_NAME = lib$(1)_emacs.so +endif + +ifeq ($$(NDK_SO_NAMES:$$(NDK_SO_NAME)=),$$(NDK_SO_NAMES)) +NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME) + +# Now recurse over this module's dependencies. +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module)))) +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module)))) +endif +endef + +# Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and +# LOCAL_SHARED_LIBRARIES. + +SYSTEM_LIBRARIES = z libz libc c + +$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module)))) +$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) + +$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname))) +$(info $(NDK_SO_NAMES)) +$(info End) diff --git a/build-aux/ndk-build-helper-2.mk b/build-aux/ndk-build-helper-2.mk new file mode 100644 index 00000000000..82c1d53c7d0 --- /dev/null +++ b/build-aux/ndk-build-helper-2.mk @@ -0,0 +1,87 @@ +# ndk-build-helper-2.mk -- Helper for ndk-build.m4. +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# Say a static library is being built +build_kind = static +NDK_SO_NAMES = +NDK_A_NAMES = + +# Record this module's dependencies. This information is used later +# on to recurse over libraries. +NDK_$(LOCAL_MODULE)_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) $(LOCAL_WHOLE_STATIC_LIBRARIES) +NDK_$(LOCAL_MODULE)_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) + +$(info Building $(build_kind)) +$(info $(LOCAL_MODULE)) +$(info $(addprefix $(ANDROID_MODULE_DIRECTORY)/,$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI)))) + +$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir))) +$(info $(LOCAL_EXPORT_CFLAGS)) +ifeq ($(LOCAL_MODULE_FILENAME),) + +ifeq ($(findstring lib,$(LOCAL_MODULE)),lib) +NDK_A_NAMES = $(LOCAL_MODULE).a +else +NDK_A_NAMES = lib$(LOCAL_MODULE).a +endif +else +NDK_A_NAMES = $(LOCAL_MODULE_FILENAME).a +endif + +define add-a-name +ifeq ($(findstring lib,$(1)),lib) +NDK_A_NAME = $(1).a +else +NDK_A_NAME = lib$(1).a +endif + +ifeq ($$(NDK_A_NAMES:$$(NDK_A_NAME)=),$$(NDK_A_NAMES)) +NDK_A_NAMES := $$(NDK_A_NAMES) $$(NDK_A_NAME) + +# Now recurse over this module's dependencies. +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module)))) +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module)))) +endif +endef + +define add-so-name +ifeq ($(findstring lib,$(1)),lib) +NDK_SO_NAME = $(1)_emacs.so +else +NDK_SO_NAME = lib$(1)_emacs.so +endif + +ifeq ($$(NDK_SO_NAMES:$$(NDK_SO_NAME)=),$$(NDK_SO_NAMES)) +NDK_SO_NAMES := $$(NDK_SO_NAMES) $$(NDK_SO_NAME) + +# Now recurse over this module's dependencies. +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_STATIC_LIBRARIES)),$$(eval $$(call add-a-name,$$(module)))) +$$(foreach module,$$(filter-out $$(SYSTEM_LIBRARIES), $$(NDK_$(1)_SHARED_LIBRARIES)),$$(eval $$(call add-so-name,$$(module)))) +endif +endef + +# Resolve additional dependencies based on LOCAL_STATIC_LIBRARIES and +# LOCAL_SHARED_LIBRARIES. + +SYSTEM_LIBRARIES = z libz + +$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_STATIC_LIBRARIES)),$(eval $(call add-a-name,$(module)))) +$(foreach module,$(filter-out $(SYSTEM_LIBRARIES), $(LOCAL_SHARED_LIBRARIES)),$(eval $(call add-so-name,$(module)))) + +$(info $(LOCAL_EXPORT_LDFLAGS) $(abspath $(addprefix $(NDK_BUILD_DIR)/,$(NDK_A_NAMES))) $(and $(NDK_SO_NAMES), -L$(abspath $(NDK_BUILD_DIR)) $(foreach soname,$(NDK_SO_NAMES),-l:$(soname)))) +$(info $(NDK_A_NAMES)) +$(info End) diff --git a/build-aux/ndk-build-helper-3.mk b/build-aux/ndk-build-helper-3.mk new file mode 100644 index 00000000000..4d0358d4f77 --- /dev/null +++ b/build-aux/ndk-build-helper-3.mk @@ -0,0 +1,28 @@ +# ndk-build-helper-3.mk -- Helper for ndk-build.m4. +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# Say a static library is being built +build_kind = executable + +$(info Building $(build_kind)) +$(info $(LOCAL_MODULE)) +$(info $(addprefix $(ANDROID_MODULE_DIRECTORY),$(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES$(EMACS_ABI)))) + +$(info $(foreach dir,$(LOCAL_EXPORT_C_INCLUDE_DIRS) $(LOCAL_EXPORT_C_INCLUDES),-I$(dir))) +$(info $(LOCAL_EXPORT_CFLAGS)) +$(info $(LOCAL_EXPORT_LDFLAGS)) +$(info End) diff --git a/build-aux/ndk-build-helper-4.mk b/build-aux/ndk-build-helper-4.mk new file mode 100644 index 00000000000..e1024f0a243 --- /dev/null +++ b/build-aux/ndk-build-helper-4.mk @@ -0,0 +1,38 @@ +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +undefine LOCAL_MODULE +undefine LOCAL_MODULE_FILENAME +undefine LOCAL_SRC_FILES +undefine LOCAL_CPP_EXTENSION +undefine LOCAL_CPP_FEATURES +undefine LOCAL_C_INCLUDES +undefine LOCAL_CFLAGS +undefine LOCAL_CPPFLAGS +undefine LOCAL_STATIC_LIBRARIES +undefine LOCAL_SHARED_LIBRARIES +undefine LOCAL_WHOLE_STATIC_LIBRARIES +undefine LOCAL_LDLIBS +undefine LOCAL_LDFLAGS +undefine LOCAL_ALLOW_UNDEFINED_SYMBOLS +undefine LOCAL_ARM_MODE +undefine LOCAL_ARM_NEON +undefine LOCAL_DISABLE_FORMAT_STRING_CHECKS +undefine LOCAL_EXPORT_CFLAGS +undefine LOCAL_EXPORT_CPPFLAGS +undefine LOCAL_EXPORT_C_INCLUDES +undefine LOCAL_EXPORT_LDFLAGS +undefine LOCAL_EXPORT_LDLIBS diff --git a/build-aux/ndk-build-helper.mk b/build-aux/ndk-build-helper.mk new file mode 100644 index 00000000000..beb32cae3f1 --- /dev/null +++ b/build-aux/ndk-build-helper.mk @@ -0,0 +1,52 @@ +# ndk-build-helper.mk -- Helper for ndk-build.m4. +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# This Makefile sets up enough to parse an Android-style Android.mk +# file and return useful information about its contents. + +# See the text under ``NDK BUILD SYSTEM IMPLEMENTATION'' in +# INSTALL.android for more details. + +# Make NDK_BUILD_DIR absolute. +NDK_BUILD_DIR := $(absname $(NDK_BUILD_DIR)) + +# my-dir is a function that returns the Android module directory. +my-dir = $(ANDROID_MODULE_DIRECTORY) + +# all-subdir-makefiles is a function which returns all Android.mk +# files within this directory. +all-subdir-makefiles = $(shell find . -name "Android.mk") + +# These functions are not implemented. +parent-makefile = +grand-parent-makefile = +import-module = + +# Print out module information every time BUILD_SHARED_LIBRARY is +# called. + +BUILD_SHARED_LIBRARY=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-1.mk +BUILD_STATIC_LIBRARY=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-2.mk +BUILD_EXECUTABLE=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-3.mk +CLEAR_VARS=$(EMACS_SRCDIR)/build-aux/ndk-build-helper-4.mk + +# Now include Android.mk. + +include $(ANDROID_MAKEFILE) + +# Dummy target. +all: diff --git a/build-aux/ndk-module-extract.awk b/build-aux/ndk-module-extract.awk new file mode 100644 index 00000000000..eaea3e96dd8 --- /dev/null +++ b/build-aux/ndk-module-extract.awk @@ -0,0 +1,64 @@ +/^Building.+$/ { + kind = $2 +} + +// { + if (!match ($0, /^End$/) && !match ($0, /^Building.+$/)) + { + if (kind) + { + if (ldflags_found) + target = $0 + else if (cflags_found) + { + ldflags = $0 + ldflags_found = 1 + } + else if (includes_found) + { + cflags = $0 + cflags_found = 1 + } + else if (src_found) + { + includes = $0 + includes_found = 1 + } + else if (name_found) + { + src = $0 + src_found = 1; + } + else + { + name = $0 + name_found = 1 + } + } + } +} + +/^End$/ { + if (name == MODULE && (kind == "shared" || kind == "static")) + { + printf "module_name=%s\n", name + printf "module_kind=%s\n", kind + printf "module_src=\"%s\"\n", src + printf "module_includes=\"%s\"\n", includes + printf "module_cflags=\"%s\"\n", cflags + printf "module_ldflags=\"%s\"\n", ldflags + printf "module_target=\"%s\"\n", target + } + + src = "" + name = "" + kind = "" + includes = "" + cflags = "" + ldflags = "" + name_found = "" + src_found = "" + includes_found = "" + cflags_found = "" + ldflags_found = "" +} diff --git a/configure.ac b/configure.ac index bdcce8d8694..9df4a6a073f 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,13 @@ fi AC_CANONICAL_HOST AC_CANONICAL_BUILD +if test "$XCONFIGURE" = "android"; then + # Initialize the Android NDK build system. Make sure to use the + # passed through NDK path. + with_ndk_path="$android_ndk_path" + ndk_INIT([$android_abi], [$ANDROID_SDK], [cross/ndk-build]) +fi + case $host in *-mingw*) @@ -544,6 +551,7 @@ OPTION_DEFAULT_OFF([cygwin32-native-compilation],[use native compilation on 32-b OPTION_DEFAULT_ON([xinput2],[don't use version 2 of the X Input Extension for input]) OPTION_DEFAULT_OFF([small-ja-dic],[generate a smaller-size Japanese dictionary]) OPTION_DEFAULT_OFF([android],[cross-compile Android application package]) +OPTION_DEFAULT_ON([android-debug],[don't build Emacs as a debug package on Android]) AC_ARG_WITH([file-notification],[AS_HELP_STRING([--with-file-notification=LIB], [use a file notification library (LIB one of: yes, inotify, kqueue, gfile, w32, no)])], @@ -1033,8 +1041,14 @@ package will likely install on older systems but crash on startup.]) mv -f confdefs.h _confdefs.h mv -f config.log _config.log + # Figure out what --with-FOO options to pass through. + passthrough="$passthrough --with-png=$with_png" + passthrough="$passthrough --with-webp=$with_webp" + passthrough="$passthrough --with-gif=$with_gif" + AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \ - ANDROID_SDK="$android_sdk" $0], [], + ANDROID_SDK="$android_sdk" android_abi=$android_abi \ + android_ndk_path="$with_ndk_path" $0 $passthrough], [], [AC_MSG_ERROR([Failed to cross-configure Emacs for android.])]) # Now set ANDROID to yes. @@ -1048,6 +1062,14 @@ package will likely install on older systems but crash on startup.]) AC_MSG_NOTICE([Generating src/config.h.android]) mv -f src/config.h src/config.h.android + # Tell AndroidManifest.xml whether or not Emacs should be built + # debug. + ANDROID_DEBUGGABLE=false + if test "$with_android_debug" = "yes"; then + ANDROID_DEBUGGABLE=true + fi + AC_SUBST([ANDROID_DEBUGGABLE]) + # Move confdefs.h back now that the recursive call to configure is # complete. mv -f _confdefs.h confdefs.h @@ -1083,15 +1105,21 @@ if test "$ANDROID" = "yes"; then with_xpm=no with_jpeg=no with_tiff=no - with_gif=no - with_png=no + + # Some of these dependencies are now supported within Android, so + # they can be enabled. + if test "$XCONFIGURE" != "android"; then + with_png=no + with_webp=no + with_gif=no + fi + + with_xml2=no with_rsvg=no - with_webp=no with_sqlite3=no with_lcms2=no with_libsystemd=no with_cairo=no - with_xml2=no with_imagemagick=no with_json=no with_tree_sitter=no @@ -2218,10 +2246,13 @@ dnl EMACS_CHECK_MODULES accepts optional 3rd and 4th arguments that dnl can take the place of the default HAVE_GSTUFF=yes and HAVE_GSTUFF=no dnl actions. AC_DEFUN([EMACS_CHECK_MODULES], - [PKG_CHECK_MODULES([$1], [$2], - [$1_CFLAGS=`AS_ECHO(["$$1_CFLAGS"]) | sed -e "$edit_cflags"` - m4_default([$3], [HAVE_$1=yes])], - [m4_default([$4], [HAVE_$1=no])])]) + [AS_IF([test -n "$ndk_INITIALIZED"], + [ndk_CHECK_MODULES([$1], [$2], m4_default([$3], [HAVE_$1=yes]), + m4_default([$4],[HAVE_$1=no]))], + [PKG_CHECK_MODULES([$1], [$2], + [$1_CFLAGS=`AS_ECHO(["$$1_CFLAGS"]) | sed -e "$edit_cflags"` + m4_default([$3], [HAVE_$1=yes])], + [m4_default([$4], [HAVE_$1=no])])])]) HAVE_SOUND=no if test "${with_sound}" != "no"; then @@ -2394,6 +2425,7 @@ window_system=none ANDROID_OBJ= ANDROID_LIBS= ANDROID_CFLAGS= +REALLY_ANDROID= CM_OBJ="cm.o" if test "${ANDROID}" = "yes"; then @@ -2423,18 +2455,31 @@ for Android, but all API calls need to be stubbed out]) # Link with libraries required for Android support. ANDROID_LIBS="-landroid -llog -ljnigraphics" + # This is required to make the system load emacs.apk's libpng + # (among others) instead of the system's own. But it doesn't work + # on all Android versions yet, so for now just suffix shared + # libraries with _emacs. + # ANDROID_LDFLAGS="-Wl,-rpath,'\$\$ORIGIN'" + # Link with the sfnt font library and sfntfont.o, along with # sfntfont-android.o. ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o" + # Build androidselect.o. + ANDROID_OBJ="$ANDROID_OBJ androidselect.o" + # Check for some functions not always present in the NDK. AC_CHECK_DECLS([android_get_device_api_level]) + + # Say this build is really for Android. + REALLY_ANDROID=yes fi fi AC_SUBST(ANDROID) AC_SUBST(ANDROID_OBJ) AC_SUBST(ANDROID_LIBS) +AC_SUBST(ANDROID_LDFLAGS) AC_SUBST(ANDROID_CFLAGS) if test "${with_pgtk}" = "yes"; then @@ -3265,7 +3310,8 @@ HAVE_WEBP=no if test "${with_webp}" != "no"; then if test "${HAVE_X11}" = "yes" || test "${opsys}" = "mingw32" \ || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \ - || test "${HAVE_BE_APP}" = "yes" || test "${HAVE_PGTK}" = "yes"; then + || test "${HAVE_BE_APP}" = "yes" || test "${HAVE_PGTK}" = "yes" \ + || test "${REALLY_ANDROID}" = "yes"; then WEBP_REQUIRED=0.6.0 WEBP_MODULE="libwebpdemux >= $WEBP_REQUIRED" @@ -4506,7 +4552,8 @@ HAVE_JPEG=no LIBJPEG= if test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \ || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes" \ - || test "$window_system" = "pgtk"; then + || test "$window_system" = "pgtk" \ + || test "${REALLY_ANDROID}" = "yes"; then if test "${with_jpeg}" != "no"; then AC_CACHE_CHECK([for jpeglib 6b or later], [emacs_cv_jpeglib], @@ -4852,7 +4899,8 @@ if test "${with_png}" != no; then AC_CHECK_HEADER([png.h], [HAVE_PNG=yes]) elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \ || test "${HAVE_NS}" = "yes" || test "${HAVE_BE_APP}" = "yes" \ - || test "$window_system" = "pgtk"; then + || test "$window_system" = "pgtk" \ + || test "${REALLY_ANDROID}" = "yes"; then EMACS_CHECK_MODULES([PNG], [libpng >= 1.0.0]) if test $HAVE_PNG = yes; then LIBPNG=$PNG_LIBS @@ -4951,6 +4999,7 @@ AC_SUBST([LIBTIFF]) ### Use -lgif or -lungif if available, unless '--with-gif=no'. ### mingw32 doesn't use -lgif/-lungif, since it loads the library dynamically. HAVE_GIF=no +GIF_CFLAGS= LIBGIF= if test "${opsys}" = "mingw32"; then if test "${with_gif}" != "no"; then @@ -4963,6 +5012,7 @@ if test "${opsys}" = "mingw32"; then elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \ || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \ || test "${HAVE_BE_APP}" = "yes" || test "$window_system" = "pgtk" \ + || test "${REALLY_ANDROID}" = "yes" \ && test "${with_gif}" != "no"; then AC_CHECK_HEADER([gif_lib.h], # EGifPutExtensionLast only exists from version libungif-4.1.0b1. @@ -4982,12 +5032,20 @@ elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \ test "$HAVE_GIF" = yes && LIBGIF=-lungif fi +# Finally, try ndk-build on Android. + if test "$REALLY_ANDROID" = "yes"; then + ndk_SEARCH_MODULE([libgif], [GIF], [HAVE_GIF=yes], + [HAVE_GIF=no]) + test "$HAVE_GIF" = yes && LIBGIF="$GIF_LIBS" + fi + if test "${HAVE_GIF}" = "yes"; then AC_DEFINE([HAVE_GIF], [1], [Define to 1 if you have a gif (or ungif) library.]) fi fi AC_SUBST([LIBGIF]) +AC_SUBST([GIF_CFLAGS]) dnl Check for required libraries. MISSING= @@ -7291,7 +7349,7 @@ if test "$ANDROID" = "yes"; then fi if test "$XCOMPILE" = "yes"; then - SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES xcompile/Makefile" + SUBDIR_MAKEFILES="$SUBDIR_MAKEFILES cross/Makefile" fi dnl The admin/ directory used to be excluded from tarfiles. @@ -7377,11 +7435,15 @@ fi # Make java/Makefile ARCH_INDEPENDENT_CONFIG_FILES([java/Makefile]) -ARCH_INDEPENDENT_CONFIG_FILES([xcompile/Makefile]) +ARCH_INDEPENDENT_CONFIG_FILES([cross/Makefile]) # Make java/AndroidManifest.xml ARCH_INDEPENDENT_CONFIG_FILES([java/AndroidManifest.xml]) +# Make ndk-build Makefiles. This is only done inside the recursive +# configure. +ndk_CONFIG_FILES + AC_OUTPUT if test ! "$with_mailutils"; then diff --git a/cross/ndk-build/Makefile.in b/cross/ndk-build/Makefile.in new file mode 100644 index 00000000000..ec8e6205680 --- /dev/null +++ b/cross/ndk-build/Makefile.in @@ -0,0 +1,115 @@ +### @configure_input@ + +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + + 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_AR = @NDK_BUILD_AR@ + +# This is a list of targets to build. + NDK_BUILD_MODULES = @NDK_BUILD_MODULES@ + +# This is set by the Android in tree build system and is used by some +# libraries to look for the NDK. Its value is unimportant. + NDK_ROOT = /tmp/ + +# Finally, here are rules common to Emacs. +.PHONY: all +all: $(NDK_BUILD_MODULES) + +define uniqify +$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1))) +endef + +# Remove duplicate files. +NDK_BUILD_ANDROID_MK := $(call uniqify,$(NDK_BUILD_ANDROID_MK)) + +define subr-1 + +# Define ndk-build functions. + +define my-dir +$(dir $(abspath $(1))) +endef + +# NDK-defined include variables. + +CLEAR_VARS = $(srcdir)/ndk-clear-vars.mk +BUILD_EXECUTABLE = $(srcdir)/ndk-build-executable.mk +BUILD_SHARED_LIBRARY = $(srcdir)/ndk-build-shared-library.mk +BUILD_STATIC_LIBRARY = $(srcdir)/ndk-build-static-library.mk +PREBUILT_SHARED_LIBRARY = $(srcdir)/ndk-prebuilt-shared-library.mk +PREBUILT_STATIC_LIBRARY = $(srcdir)/ndk-prebuilt-static-library.mk + +# Target information variables. + +TARGET_ARCH = $(NDK_BUILD_ARCH) +TARGET_PLATFORM = android-$(NDK_BUILD_SDK) +TARGET_ARCH_ABI = $(NDK_BUILD_ABI) +TARGET_ABI = $(TARGET_PLATFORM)-$(TARGET_ABI) + +# Module description variables. These are defined by Android.mk. +LOCAL_PATH := +LOCAL_MODULE := +LOCAL_MODULE_FILENAME := +LOCAL_SRC_FILES := +LOCAL_CPP_EXTENSION := +LOCAL_CPP_FEATURES := +LOCAL_C_INCLUDES := +LOCAL_CFLAGS := +LOCAL_CPPFLAGS := +LOCAL_STATIC_LIBRARIES := +LOCAL_SHARED_LIBRARIES := +LOCAL_WHOLE_STATIC_LIBRARIES := +LOCAL_LDLIBS := +LOCAL_LDFLAGS := +LOCAL_ALLOW_UNDEFINED_SYMBOLS := +LOCAL_ARM_MODE := +LOCAL_ARM_NEON := +LOCAL_DISABLE_FORMAT_STRING_CHECKS := +LOCAL_EXPORT_CFLAGS := +LOCAL_EXPORT_CPPFLAGS := +LOCAL_EXPORT_C_INCLUDES := +LOCAL_EXPORT_LDFLAGS := +LOCAL_EXPORT_LDLIBS := + +# Now load Android.mk. +include $(1) + +endef + +# Now define rules for each Android.mk file. +$(foreach android_mk,$(NDK_BUILD_ANDROID_MK),$(eval $(call subr-1,$(android_mk)))) + +.PHONY: clean mostlyclean +clean mostlyclean: + rm -rf *.o *.so *.a + +.PHONY: extraclean dist-clean maintainer-clean +extraclean dist-clean maintainer-clean: + rm -rf Makefile diff --git a/cross/ndk-build/ndk-build-executable.mk b/cross/ndk-build/ndk-build-executable.mk new file mode 100644 index 00000000000..9591c862b18 --- /dev/null +++ b/cross/ndk-build/ndk-build-executable.mk @@ -0,0 +1,22 @@ +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +# Building executables is not supported diff --git a/cross/ndk-build/ndk-build-shared-library.mk b/cross/ndk-build/ndk-build-shared-library.mk new file mode 100644 index 00000000000..0d90d89e55d --- /dev/null +++ b/cross/ndk-build/ndk-build-shared-library.mk @@ -0,0 +1,83 @@ +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) +objname = $(1)-$(subst /,_,$(2).o) + +define single-object-target + +ifeq (x$(suffix $(1)),x.c) + +$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1) + $(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE)) + +else +ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),) + +$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1) + $(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE)) + +else +$$(error Unsupported suffix: $(suffix $(1))) +endif +endif + +ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1))) + +endef + +NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES))) +NDK_CFLAGS_$(LOCAL_MODULE) ::= -fPIC -iquote $(LOCAL_EXPORT_CFLAGS) $(LOCAL_PATH) $(LOCAL_CFLAGS) +NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) +NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS) +ALL_OBJECT_FILES_$(LOCAL_MODULE) := + +ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm) +NDK_CFLAGS ::= -marm +else +ifeq ($(NDK_BUILD_ARCH),arm) +NDK_CFLAGS ::= -mthumb +endif +endif + +LOCAL_MODULE_FILENAME := $(strip $(LOCAL_MODULE_FILENAME)) + +ifndef LOCAL_MODULE_FILENAME +ifeq ($(findstring lib,$(LOCAL_MODULE)),lib) +LOCAL_MODULE_FILENAME := $(LOCAL_MODULE)_emacs +else +LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE)_emacs +endif +endif + +# Since a shared library is being built, suffix the library with +# _emacs. Otherwise, libraries already on the system will be found +# first, with potentially nasty consequences. + +LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).so + +# Then define rules to build all objects. +ALL_SOURCE_FILES = $(LOCAL_SRC_FILES) +$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source)))) + +# Now define the rule to build the shared library. +$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE)) + $(NDK_BUILD_CC) $^ -o $@ -shared $(NDK_LDFLAGS$(LOCAL_MODULE)) diff --git a/cross/ndk-build/ndk-build-static-library.mk b/cross/ndk-build/ndk-build-static-library.mk new file mode 100644 index 00000000000..1423cf243cf --- /dev/null +++ b/cross/ndk-build/ndk-build-static-library.mk @@ -0,0 +1,83 @@ +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) +objname = $(1)-$(subst /,_,$(2).o) + +define single-object-target + +ifeq (x$(suffix $(1)),x.c) + +$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1) + $(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_CFLAGS_$(LOCAL_MODULE)) + +else +ifneq ($(or $(call eq,x$(suffix $(1)),x.s),$(call eq,x$(suffix $(1)),x.S)),) + +$(call objname,$(LOCAL_MODULE),$(basename $(1))): $(LOCAL_PATH)/$(1) + $(NDK_BUILD_CC) -c $$< -o $$@ $(NDK_ASFLAGS_$(LOCAL_MODULE)) + +else +$$(error Unsupported suffix: $(suffix $(1))) +endif +endif + +ALL_OBJECT_FILES$(LOCAL_MODULE) += $(call objname,$(LOCAL_MODULE),$(basename $(1))) +endef + +NDK_CFLAGS_$(LOCAL_MODULE) := $(addprefix -I,$(addprefix $(LOCAL_PATH),$(LOCAL_C_INCLUDES))) +NDK_CFLAGS_$(LOCAL_MODULE) ::= -iquote $(LOCAL_PATH) $(LOCAL_EXPORT_CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_CFLAGS_$(NDK_BUILD_ARCH)) +NDK_ASFLAGS_$(LOCAL_MODULE) ::= $(LOCAL_ASFLAGS) $(LOCAL_ASFLAGS_$(NDK_BUILD_ARCH)) +NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDLIBS) +NDK_LDFLAGS_$(LOCAL_MODULE) := $(LOCAL_LDFLAGS) +ALL_OBJECT_FILES$(LOCAL_MODULE) := + +ifeq ($(NDK_BUILD_ARCH)$(NDK_ARM_MODE),armarm) +NDK_CFLAGS ::= -marm +else +ifeq ($(NDK_BUILD_ARCH),arm) +NDK_CFLAGS ::= -mthumb +endif +endif + +LOCAL_MODULE_FILENAME := $(strip $(LOCAL_MODULE_FILENAME)) + +ifndef LOCAL_MODULE_FILENAME +ifeq ($(findstring lib,$(LOCAL_MODULE)),lib) +LOCAL_MODULE_FILENAME := $(LOCAL_MODULE) +else +LOCAL_MODULE_FILENAME := lib$(LOCAL_MODULE) +endif +endif + +LOCAL_MODULE_FILENAME := $(LOCAL_MODULE_FILENAME).a + +# Then define rules to build all objects. +ALL_SOURCE_FILES = $(LOCAL_SRC_FILES) $(LOCAL_SRC_FILES_$(NDK_BUILD_ARCH)) + +# This defines all dependencies. +ALL_OBJECT_FILES$(LOCAL_MODULE) = + +$(foreach source,$(ALL_SOURCE_FILES),$(eval $(call single-object-target,$(source)))) + +# Now define the rule to build the library. +$(LOCAL_MODULE_FILENAME): $(ALL_OBJECT_FILES$(LOCAL_MODULE)) + $(NDK_BUILD_AR) r $@ $^ diff --git a/cross/ndk-build/ndk-build.in b/cross/ndk-build/ndk-build.in new file mode 100644 index 00000000000..8586b90d840 --- /dev/null +++ b/cross/ndk-build/ndk-build.in @@ -0,0 +1,44 @@ +### @configure_input@ + +# Copyright (C) 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# This file is included all over the place to build prerequisites. + +NDK_BUILD_MODULES = @NDK_BUILD_MODULES@ +NDK_BUILD_SHARED = +NDK_BUILD_STATIC = + +define subr-1 + +.PHONY $(top_builddir)/cross/ndk-build/$(0) +$(top_builddir)/cross/ndk-build/$(0): + $(MAKE) -C $(top_builddir)/cross/ndk-build $(0) + +ifeq ($(suffix $(0)),.so) +NDK_BUILD_SHARED += $(top_builddir)/cross/ndk-build/$(0) +else +ifeq ($(suffix $(0)),.a) +NDK_BUILD_STATIC += $(top_builddir)/cross/ndk-build/$(0) +endif +endif + +endef + +# Generate rules for each module. + +$(foreach module,$(NDK_BUILD_MODULES),$(eval $(call subr-1,$(module)))) diff --git a/cross/ndk-build/ndk-build.mk.in b/cross/ndk-build/ndk-build.mk.in new file mode 100644 index 00000000000..6ad577ccc35 --- /dev/null +++ b/cross/ndk-build/ndk-build.mk.in @@ -0,0 +1,43 @@ +### @configure_input@ + +# Copyright (C) 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# This file is included all over the place to build prerequisites. + +NDK_BUILD_MODULES = @NDK_BUILD_MODULES@ +NDK_BUILD_SHARED = +NDK_BUILD_STATIC = + +define subr-1 + +$(top_builddir)/cross/ndk-build/$(1): + $(MAKE) -C $(top_builddir)/cross/ndk-build $(1) + +ifeq ($(suffix $(1)),.so) +NDK_BUILD_SHARED += $(top_builddir)/cross/ndk-build/$(1) +else +ifeq ($(suffix $(1)),.a) +NDK_BUILD_STATIC += $(top_builddir)/cross/ndk-build/$(1) +endif +endif + +endef + +# Generate rules for each module. + +$(foreach module,$(NDK_BUILD_MODULES),$(eval $(call subr-1,$(module)))) diff --git a/cross/ndk-build/ndk-clear-vars.mk b/cross/ndk-build/ndk-clear-vars.mk new file mode 100644 index 00000000000..df2bf95fd5e --- /dev/null +++ b/cross/ndk-build/ndk-clear-vars.mk @@ -0,0 +1,47 @@ +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +undefine LOCAL_MODULE +undefine LOCAL_MODULE_FILENAME +undefine LOCAL_SRC_FILES +undefine LOCAL_CPP_EXTENSION +undefine LOCAL_CPP_FEATURES +undefine LOCAL_C_INCLUDES +undefine LOCAL_CFLAGS +undefine LOCAL_CPPFLAGS +undefine LOCAL_STATIC_LIBRARIES +undefine LOCAL_SHARED_LIBRARIES +undefine LOCAL_WHOLE_STATIC_LIBRARIES +undefine LOCAL_LDLIBS +undefine LOCAL_LDFLAGS +undefine LOCAL_ALLOW_UNDEFINED_SYMBOLS +undefine LOCAL_ARM_MODE +undefine LOCAL_ARM_NEON +undefine LOCAL_DISABLE_FORMAT_STRING_CHECKS +undefine LOCAL_EXPORT_CFLAGS +undefine LOCAL_EXPORT_CPPFLAGS +undefine LOCAL_EXPORT_C_INCLUDES +undefine LOCAL_EXPORT_LDFLAGS +undefine LOCAL_EXPORT_LDLIBS + +undefine LOCAL_SRC_FILES_$(NDK_BUILD_ARCH) +undefine LOCAL_ASFLAGS_$(NDK_BUILD_ARCH) +undefine LOCAL_CFLAGS_$(NDK_BUILD_ARCH) diff --git a/cross/ndk-build/ndk-prebuilt-shared-library.mk b/cross/ndk-build/ndk-prebuilt-shared-library.mk new file mode 100644 index 00000000000..2a8260f9851 --- /dev/null +++ b/cross/ndk-build/ndk-prebuilt-shared-library.mk @@ -0,0 +1,24 @@ +### @configure_input@ + +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +$(warn Prebuilt shared libraries are not supported) diff --git a/cross/ndk-build/ndk-prebuilt-static-library.mk b/cross/ndk-build/ndk-prebuilt-static-library.mk new file mode 100644 index 00000000000..9230f690bb1 --- /dev/null +++ b/cross/ndk-build/ndk-prebuilt-static-library.mk @@ -0,0 +1,24 @@ +### @configure_input@ + +# Copyright 2023 Free Software Foundation, Inc. + +# This file is part of GNU Emacs. + +# GNU Emacs is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# GNU Emacs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with GNU Emacs. If not, see . + +# ndk-build works by including a bunch of Makefiles which set +# variables, and then having those Makefiles include another makefile +# which actually builds targets. + +$(warn Prebuilt static libraries are not supported) diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 223e9dbf8ef..e4498da401d 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -18,6 +18,7 @@ about using such devices with Emacs, @pxref{Other Input Devices}. * Android Startup:: Starting up Emacs on Android. * Android File System:: The Android file system. * Android Environment:: Running Emacs under Android. +* Android Windowing:: The Android window system. * Android Fonts:: Font selection under Android. @end menu @@ -299,7 +300,8 @@ settings application. Consult the manufacturer of your device for more details, as how to do this varies by device. @end itemize -@section Android windowing +@node Android Windowing +@section The Android window system Android has an unusual window system; there, all windows are maximized or full-screen, and only one window can be displayed at a @@ -372,6 +374,31 @@ The @code{fullscreen} frame parameter is always @code{maximized} for top-level frames. @end itemize +@cindex selections, android +@cindex android clipboard + Emacs does not implement all selection related features supported +under the X Window System on Android. For example, only the +@code{CLIPBOARD} and @code{PRIMARY} selections (@pxref{Cut and Paste}) +are supported, and plain text is the only supported data type. + + In addition, the Android system itself places certain restrictions +on what selection data Emacs can access: + +@itemize @bullet +@item +On Android 2.3 and earlier, the function @code{gui-selection-owner-p} +always returns @code{nil} for the clipboard selection. + +@item +On Android 3.0 and later, Emacs can only access clipboard data when +one of its frames has the input focus. +@end itemize + + Since the Android system itself has no concept of a primary +selection, Emacs provides an emulation instead. This means there is +no way to transfer the contents of the primary selection to another +application via cut-and-paste. + @node Android Fonts @section Font backends and selection under Android @cindex fonts, android diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 0cb454e5294..30758efb43a 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi @@ -1264,6 +1264,7 @@ Emacs and Android * Android Startup:: Starting up Emacs on Android. * Android File System:: The Android file system. * Android Environment:: Running Emacs under Android. +* Android Windowing:: The Android window system. * Android Fonts:: Font selection under Android. Emacs and unconventional input devices diff --git a/etc/MACHINES b/etc/MACHINES index 8c6f3f48ce7..8ba0b1faa77 100644 --- a/etc/MACHINES +++ b/etc/MACHINES @@ -131,6 +131,14 @@ the list at the end of this file. The earliest release of Haiku that will successfully compile Emacs is R1/Beta2. For windowing support, R1/Beta3 or later is required. +** Android + + Emacs is known to run on all Android versions from 2.3 onwards. + It should work with Android 2.2 as well, but only the build + has been tested, and actually running the built Emacs has not. + + See the file INSTALL.android for detailed installation instructions. + * Obsolete platforms diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 74f69d2a8e5..c4a9d1f5177 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -60,12 +60,13 @@ along with GNU Emacs. If not, see . --> android:hardwareAccelerated="true" android:supportsRtl="true" android:theme="@android:style/Theme" - android:debuggable="true" + android:debuggable="@ANDROID_DEBUGGABLE@" android:extractNativeLibs="true"> @@ -76,10 +77,12 @@ along with GNU Emacs. If not, see . --> diff --git a/java/Makefile.in b/java/Makefile.in index 22c912fdce5..d27775ea3db 100644 --- a/java/Makefile.in +++ b/java/Makefile.in @@ -81,21 +81,24 @@ APK_NAME = emacs-$(version)-$(ANDROID_MIN_SDK)-$(ANDROID_ABI).apk all: $(APK_NAME) # Binaries to cross-compile. -CROSS_BINS = ../xcompile/src/android-emacs ../xcompile/lib-src/ctags \ - ../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \ - ../xcompile/lib-src/ebrowse ../xcompile/lib-src/emacsclient +CROSS_BINS = ../cross/src/android-emacs ../cross/lib-src/ctags \ + ../cross/lib-src/hexl ../cross/lib-src/movemail \ + ../cross/lib-src/ebrowse ../cross/lib-src/emacsclient # Libraries to cross-compile. -CROSS_LIBS = ../xcompile/src/libemacs.so +CROSS_LIBS = ../cross/src/libemacs.so + +# Third party libraries to compile. +include $(top_builddir)/cross/ndk-build/ndk-build.mk .PHONY: $(CROSS_BINS) $(CROSS_LIBS) -../xcompile/src/android-emacs ../xcompile/src/libemacs.so: - make -C ../xcompile src/$(notdir $@) +../cross/src/android-emacs ../cross/src/libemacs.so: + make -C ../cross src/$(notdir $@) -../xcompile/lib-src/hexl ../xcompile/lib-src/movemail \ -../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &: - make -C ../xcompile lib-src/$(notdir $@) +../cross/lib-src/hexl ../cross/lib-src/movemail \ +../cross/lib-src/ctags ../cross/lib-src/ebrowse &: + make -C ../cross lib-src/$(notdir $@) # This is needed to generate the ``.directory-tree'' file used by the # Android emulations of readdir and faccessat. @@ -104,7 +107,7 @@ $(libsrc)/asset-directory-tool: $(MAKE) -C $(libsrc) $(notdir $@) emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \ - AndroidManifest.xml + AndroidManifest.xml $(NDK_BUILD_SHARED) # Make the working directory for this stuff rm -rf install_temp mkdir -p install_temp/lib/$(ANDROID_ABI) @@ -145,11 +148,13 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \ cp -f $$file install_temp/lib/$(ANDROID_ABI); \ fi \ done + $(foreach module,$(NDK_BUILD_SHARED), \ + cp -f $(module) install_temp/lib/$(ANDROID_ABI)) # Package everything. Specifying the assets on this command line is # necessary for AAssetManager_getNextFileName to work on old versions # of Android. - $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml \ - -A install_temp/assets + $(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f \ + -M AndroidManifest.xml -A install_temp/assets pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd rm -rf install_temp @@ -196,3 +201,4 @@ clean: find . -name '*.class' -delete maintainer-clean distclean bootstrap-clean: clean + rm -f Makefile ndk-build.mk diff --git a/java/org/gnu/emacs/EmacsClipboard.java b/java/org/gnu/emacs/EmacsClipboard.java new file mode 100644 index 00000000000..cd6bcebfe0e --- /dev/null +++ b/java/org/gnu/emacs/EmacsClipboard.java @@ -0,0 +1,44 @@ +/* Communication module for Android terminals. -*- c-file-style: "GNU" -*- + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +package org.gnu.emacs; + +import android.os.Build; + +/* This class provides helper code for accessing the clipboard, + abstracting between the different interfaces on API 8 and 11. */ + +public abstract class EmacsClipboard +{ + public abstract void setClipboard (byte[] bytes); + public abstract int ownsClipboard (); + public abstract boolean clipboardExists (); + public abstract byte[] getClipboard (); + + /* Create the correct kind of clipboard for this system. */ + + public static EmacsClipboard + makeClipboard () + { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) + return new EmacsSdk11Clipboard (); + else + return new EmacsSdk8Clipboard (); + } +}; diff --git a/java/org/gnu/emacs/EmacsFontDriver.java b/java/org/gnu/emacs/EmacsFontDriver.java index 1d1e6f7b33f..39bda5a456d 100644 --- a/java/org/gnu/emacs/EmacsFontDriver.java +++ b/java/org/gnu/emacs/EmacsFontDriver.java @@ -23,6 +23,9 @@ import java.util.List; import android.os.Build; +/* This code is mostly unused. See sfntfont-android.c for the code + that is actually used. */ + public abstract class EmacsFontDriver { /* Font weights. */ diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java index 3efdc0cff9a..962538bef7b 100644 --- a/java/org/gnu/emacs/EmacsNative.java +++ b/java/org/gnu/emacs/EmacsNative.java @@ -132,6 +132,10 @@ public class EmacsNative /* Send an ANDROID_CONTEXT_MENU event. */ public static native long sendContextMenu (short window, int menuEventID); + /* Send an ANDROID_EXPOSE event. */ + public static native long sendExpose (short window, int x, int y, + int width, int height); + static { System.loadLibrary ("emacs"); diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java b/java/org/gnu/emacs/EmacsSdk11Clipboard.java new file mode 100644 index 00000000000..0a725200723 --- /dev/null +++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java @@ -0,0 +1,156 @@ +/* Communication module for Android terminals. -*- c-file-style: "GNU" -*- + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +package org.gnu.emacs; + +import android.content.ClipboardManager; +import android.content.Context; +import android.content.ClipData; + +import android.util.Log; + +import java.io.UnsupportedEncodingException; + +/* This class implements EmacsClipboard for Android 3.0 and later + systems. */ + +public class EmacsSdk11Clipboard extends EmacsClipboard + implements ClipboardManager.OnPrimaryClipChangedListener +{ + private static final String TAG = "EmacsSdk11Clipboard"; + private ClipboardManager manager; + private boolean ownsClipboard; + private int clipboardChangedCount; + private int monitoredClipboardChangedCount; + + public + EmacsSdk11Clipboard () + { + String what; + Context context; + + what = Context.CLIPBOARD_SERVICE; + context = EmacsService.SERVICE; + manager + = (ClipboardManager) context.getSystemService (what); + manager.addPrimaryClipChangedListener (this); + } + + @Override + public synchronized void + onPrimaryClipChanged () + { + Log.d (TAG, ("onPrimaryClipChanged: " + + monitoredClipboardChangedCount + + " " + clipboardChangedCount)); + + /* Increment monitoredClipboardChangeCount. If it is now greater + than clipboardChangedCount, then Emacs no longer owns the + clipboard. */ + monitoredClipboardChangedCount++; + + if (monitoredClipboardChangedCount > clipboardChangedCount) + { + ownsClipboard = false; + + /* Reset both values back to 0. */ + monitoredClipboardChangedCount = 0; + clipboardChangedCount = 0; + } + } + + /* Set the clipboard text to CLIPBOARD, a string in UTF-8 + encoding. */ + + @Override + public synchronized void + setClipboard (byte[] bytes) + { + ClipData data; + String string; + + try + { + string = new String (bytes, "UTF-8"); + data = ClipData.newPlainText ("Emacs", string); + manager.setPrimaryClip (data); + ownsClipboard = true; + + /* onPrimaryClipChanged will be called again. Use this + variable to keep track of how many times the clipboard has + been changed. */ + ++clipboardChangedCount; + } + catch (UnsupportedEncodingException exception) + { + Log.w (TAG, "setClipboard: " + exception); + } + } + + /* Return whether or not Emacs owns the clipboard. Value is 1 if + Emacs does, 0 if Emacs does not, and -1 if that information is + unavailable. */ + + @Override + public synchronized int + ownsClipboard () + { + return ownsClipboard ? 1 : 0; + } + + /* Return whether or not clipboard content currently exists. */ + + @Override + public boolean + clipboardExists () + { + return manager.hasPrimaryClip (); + } + + /* Return the current content of the clipboard, as plain text, or + NULL if no content is available. */ + + @Override + public byte[] + getClipboard () + { + ClipData clip; + CharSequence text; + Context context; + + clip = manager.getPrimaryClip (); + + if (clip == null || clip.getItemCount () < 1) + return null; + + context = EmacsService.SERVICE; + + try + { + text = clip.getItemAt (0).coerceToText (context); + return text.toString ().getBytes ("UTF-8"); + } + catch (UnsupportedEncodingException exception) + { + Log.w (TAG, "getClipboard: " + exception); + } + + return null; + } +}; diff --git a/java/org/gnu/emacs/EmacsSdk8Clipboard.java b/java/org/gnu/emacs/EmacsSdk8Clipboard.java new file mode 100644 index 00000000000..34e66912562 --- /dev/null +++ b/java/org/gnu/emacs/EmacsSdk8Clipboard.java @@ -0,0 +1,116 @@ +/* Communication module for Android terminals. -*- c-file-style: "GNU" -*- + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +package org.gnu.emacs; + +/* Importing the entire package avoids the deprecation warning. */ +import android.text.*; + +import android.content.Context; +import android.util.Log; + +import java.io.UnsupportedEncodingException; + +/* This class implements EmacsClipboard for Android 2.2 and other + similarly old systems. */ + +@SuppressWarnings ("deprecation") +public class EmacsSdk8Clipboard extends EmacsClipboard +{ + private static final String TAG = "EmacsSdk8Clipboard"; + private ClipboardManager manager; + + public + EmacsSdk8Clipboard () + { + String what; + Context context; + + what = Context.CLIPBOARD_SERVICE; + context = EmacsService.SERVICE; + manager + = (ClipboardManager) context.getSystemService (what); + } + + /* Set the clipboard text to CLIPBOARD, a string in UTF-8 + encoding. */ + + @Override + public void + setClipboard (byte[] bytes) + { + try + { + manager.setText (new String (bytes, "UTF-8")); + } + catch (UnsupportedEncodingException exception) + { + Log.w (TAG, "setClipboard: " + exception); + } + } + + /* Return whether or not Emacs owns the clipboard. Value is 1 if + Emacs does, 0 if Emacs does not, and -1 if that information is + unavailable. */ + + @Override + public int + ownsClipboard () + { + return -1; + } + + /* Return whether or not clipboard content currently exists. */ + + @Override + public boolean + clipboardExists () + { + return manager.hasText (); + } + + /* Return the current content of the clipboard, as plain text, or + NULL if no content is available. */ + + @Override + public byte[] + getClipboard () + { + String string; + CharSequence text; + + text = manager.getText (); + + if (text == null) + return null; + + string = text.toString (); + + try + { + return string.getBytes ("UTF-8"); + } + catch (UnsupportedEncodingException exception) + { + Log.w (TAG, "getClipboard: " + exception); + } + + return null; + } +}; diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 74bbb7b3ecc..881cbc363ba 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java @@ -99,6 +99,9 @@ public class EmacsView extends ViewGroup yet responded to. 0 if there is no such outstanding event. */ public long pendingConfigure; + /* Whether or not this view is attached to a window. */ + public boolean isAttachedToWindow; + public EmacsView (EmacsWindow window) { @@ -140,6 +143,9 @@ public class EmacsView extends ViewGroup if (measuredWidth == 0 || measuredHeight == 0) return; + if (!isAttachedToWindow) + return; + /* If bitmap is the same width and height as the measured width and height, there is no need to do anything. Avoid allocating the extra bitmap. */ @@ -547,6 +553,8 @@ public class EmacsView extends ViewGroup public synchronized void onDetachedFromWindow () { + isAttachedToWindow = false; + synchronized (this) { /* Recycle the bitmap and call GC. */ @@ -559,6 +567,21 @@ public class EmacsView extends ViewGroup } } + @Override + public synchronized void + onAttachedToWindow () + { + isAttachedToWindow = true; + + /* Dirty the bitmap, as it was destroyed when onDetachedFromWindow + was called. */ + bitmapDirty = true; + + /* Now expose the view contents again. */ + EmacsNative.sendExpose (this.window.handle, 0, 0, + measuredWidth, measuredHeight); + } + public void showOnScreenKeyboard () { diff --git a/lib/Makefile.in b/lib/Makefile.in index fd730b554e3..b84a1bf9741 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -21,7 +21,7 @@ srcdir = @srcdir@ VPATH = @srcdir@ # This is not empty if this is a Makefile that will be copied to -# xcompile/lib. +# cross/lib. XCONFIGURE = @XCONFIGURE@ # This is required to make sure symbol visibility is correct and @@ -64,7 +64,7 @@ endif ifeq ($(XCONFIGURE),android) # The next line is necessary to override -I$(srcdir), which will end # up pulling in lots of headers from the host. -ALL_CFLAGS += -I$(top_srcdir)/xcompile -I. +ALL_CFLAGS += -I$(top_srcdir)/cross -I. endif DEPDIR = deps diff --git a/lisp/term/android-win.el b/lisp/term/android-win.el index 43b75d39f50..6ab469dc0b0 100644 --- a/lisp/term/android-win.el +++ b/lisp/term/android-win.el @@ -59,5 +59,111 @@ DISPLAY is ignored on Android." ;; arguments on. (ignore)) + +;;; Selection support. + +(declare-function android-clipboard-exists-p "androidselect.c") +(declare-function android-get-clipboard "androidselect.c") +(declare-function android-set-clipboard "androidselect.c") +(declare-function android-clipboard-owner-p "androidselect.c") + +(defvar android-primary-selection nil + "The last string placed in the primary selection. +Nil if there was no such string. + +Android does not have a primary selection of its own, so Emacs +emulates one inside Lisp.") + +(defun android-get-clipboard-1 (data-type) + "Return the clipboard data. +DATA-TYPE is a selection conversion target; only STRING and +TARGETS are supported." + (or (and (eq data-type 'STRING) + (android-get-clipboard)) + (and (eq data-type 'TARGETS) + (android-clipboard-exists-p) + [TARGETS STRING]))) + +(defun android-get-primary (data-type) + "Return the last string placed in the primary selection, or nil. +Return nil if DATA-TYPE is anything other than STRING or TARGETS." + (when android-primary-selection + (or (and (eq data-type 'STRING) + android-primary-selection) + (and (eq data-type 'TARGETS) + [TARGETS])))) + +(defun android-selection-bounds (value) + "Return bounds of selection value VALUE. +The return value is a list (BEG END BUF) if VALUE is a cons of +two markers or an overlay. Otherwise, it is nil." + (cond ((bufferp value) + (with-current-buffer value + (when (mark t) + (list (mark t) (point) value)))) + ((and (consp value) + (markerp (car value)) + (markerp (cdr value))) + (when (and (marker-buffer (car value)) + (buffer-name (marker-buffer (car value))) + (eq (marker-buffer (car value)) + (marker-buffer (cdr value)))) + (list (marker-position (car value)) + (marker-position (cdr value)) + (marker-buffer (car value))))) + ((overlayp value) + (when (overlay-buffer value) + (list (overlay-start value) + (overlay-end value) + (overlay-buffer value)))))) + +(defun android-encode-select-string (value) + "Turn VALUE into a string suitable for placing in the clipboard. +VALUE should be something suitable for passing to +`gui-set-selection'." + (unless (stringp value) + (when-let ((bounds (android-selection-bounds value))) + (setq value (ignore-errors + (with-current-buffer (nth 2 bounds) + (buffer-substring (nth 0 bounds) + (nth 1 bounds))))))) + value) + +(cl-defmethod gui-backend-get-selection (type data-type + &context (window-system android)) + (cond ((eq type 'CLIPBOARD) + (android-get-clipboard-1 data-type)) + ((eq type 'PRIMARY) + (android-get-primary data-type)))) + +(cl-defmethod gui-backend-selection-exists-p (selection + &context (window-system android)) + (cond ((eq selection 'CLIPBOARD) + (android-clipboard-exists-p)) + ((eq selection 'PRIMARY) + (not (null android-primary-selection))))) + +(cl-defmethod gui-backend-selection-owner-p (selection + &context (window-system android)) + (cond ((eq selection 'CLIPBOARD) + (let ((ownership (android-clipboard-owner-p))) + ;; If ownership is `lambda', then Emacs couldn't determine + ;; whether or not it owns the clipboard. + (and (not (eq ownership 'lambda)) ownership))) + ((eq selection 'PRIMARY) + ;; Emacs always owns its own primary selection as long as it + ;; exists. + (not (null android-primary-selection))))) + +(cl-defmethod gui-backend-set-selection (type value + &context (window-system android)) + ;; First, try to turn value into a string. + ;; Don't set anything if that did not work. + (when-let ((string (android-encode-select-string value))) + (cond ((eq type 'CLIPBOARD) + (android-set-clipboard string)) + ((eq type 'PRIMARY) + (setq android-primary-selection string))))) + (provide 'android-win) ;; android-win.el ends here. diff --git a/m4/ndk-build.m4 b/m4/ndk-build.m4 new file mode 100644 index 00000000000..a35900884d9 --- /dev/null +++ b/m4/ndk-build.m4 @@ -0,0 +1,213 @@ +dnl Copyright (C) 2023 Free Software Foundation, Inc. +dnl This file is part of GNU Emacs. + +dnl GNU Emacs is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. + +dnl GNU Emacs is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. + +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Emacs. If not, see . + +# Support for building Emacs with dependencies using the Android NDK +# build system. + +AC_ARG_WITH([ndk_path], + [AS_HELP_STRING([--with-ndk-path], + [find Android libraries in these directories])]) + +# ndk_INIT(ABI, API, DIR) +# -------- +# Initialize the Android NDK. ABI is the ABI being built for. +# API is the API version being built for. +# As a side effect, set the variable ndk_INITIALIZED to true. +# DIR should be a directory containing the Makefile.in actually +# implementing the Android NDK build system. + +AC_DEFUN_ONCE([ndk_INIT], +[ +# Look for Android.mk files. +ndk_module_files= +for file in $with_ndk_path; do + if test -f $file/Android.mk; then + ndk_module_files="$ndk_module_files$file/Android.mk " + fi +done + +ndk_ABI=$1 +ndk_MODULES= +ndk_MAKEFILES= +ndk_INITIALIZED=yes +ndk_API=$2 +ndk_DIR=$3 + +case "$ndk_ABI" in + *arm64* ) + ndk_ARCH=arm64 + ;; + *arm* ) + ndk_ARCH=arm + ;; + *x86_64* ) + ndk_ARCH=x86_64 + ;; + *x86* ) + ndk_ARCH=x86 + ;; + * ) + AC_MSG_ERROR([Failed to determine Android device architecture]) + ;; +esac + +# This is a map between pkg-config style package names and Android +# ones. + +ndk_package_map="libwebpdemux:webpdemux libxml-2.0:libxml2" + +# Replace ndk_module with the appropriate Android module name if it is +# found in ndk_package_map. + +ndk_replace_pkg_config_package () { + for ndk_stuff in $ndk_package_map; do + ndk_key=${ndk_stuff%%:*} + ndk_value=${ndk_stuff#*:} + + if test "$ndk_key" = "$ndk_module"; then + ndk_module="$ndk_value" + break + fi + done +} + +# Parse a pkg-config style list of modules. Place the resulting list +# in ndk_modules. + +ndk_parse_pkg_config_string () { + ndk_input=[$]1 + ndk_modules= + while test -n "$ndk_input"; do + ndk_str=$(printf "$ndk_input" | cut -f1 -d' ') + ndk_input="$(printf "$ndk_input" | cut -s -f2- -d' ')" + + if test "$ndk_str" = ">=" || test "$ndk_str" = "<=" \ + || test "$ndk_str" = ">" || test "$ndk_str" = "<"; then + ndk_input="$(printf "$ndk_input" | cut -s -f2- -d' ')" + else + ndk_modules="$ndk_modules$ndk_str " + fi + done +} + +# Look for a suitable ar in the same directory as the C compiler. +ndk_where_cc=$(which $CC) +ndk_ar_search_path=$PATH + +# First, try to find $host_alias-ar in PATH. +AC_PATH_PROGS([AR], [$host_alias-ar], [], [$ndk_ar_search_path]) + +if test -z "$AR"; then + # Next, try finding either that or llvm-ar in the directory holding + # CC. + ndk_ar_search_path="$(dirname $ndk_where_cc):$ndk_ar_search_path" + AC_PATH_PROGS([AR], [$host_alias-ar llvm-ar], [], [$ndk_ar_search_path]) +fi + +# These variables have now been found. +]) + +# ndk_SEARCH_MODULE(MODULE, NAME, ACTION-IF-FOUND, [ACTION-IF-NOT-FOUND]) +# -------------------------------------------------------------------- +# Search for a module named MODULE in `with_ndk_path'. Add the file +# name of the module's Android.mk file to the variable ndk_MODULES. +# Set NAME_CFLAGS and NAME_LIBS to the appropriate values. Then, +# call ACTION-IF-FOUND, or ACTION-IF-NOT-FOUND upon failure. +AC_DEFUN([ndk_SEARCH_MODULE], +[ +module_name= +ndk_module=$1 +ndk_replace_pkg_config_package +AC_MSG_CHECKING([for Android.mk that builds $ndk_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 just + # use it to test whether or not the NDK is being used. + ndk_commands=$(make -s -f build-aux/ndk-build-helper.mk EMACS_SRCDIR=. \ + EMACS_ABI=$ndk_ABI ANDROID_MAKEFILE="$ndk_android_mk" \ + ANDROID_MODULE_DIRECTORY=$(dirname "$ndk_android_mk") \ + NDK_BUILD_DIR="$ndk_DIR" NDK_ROOT="/tmp" \ + | awk -f build-aux/ndk-module-extract.awk \ + MODULE="$ndk_module") + + AS_IF([test -n "${ndk_commands//\n }"], [eval "$ndk_commands"]) + + if test -n "$module_name"; then + break + fi +done + +if test -z "$module_name"; then + AC_MSG_RESULT([no]) + $4 +else + $2[]_CFLAGS="[$]$2[]_CFLAGS $module_cflags $module_includes" + $2[]_LIBS="[$]$2[]_LIBS $module_ldflags" + ndk_MAKEFILES="$ndk_MAKEFILES $ndk_android_mk" + ndk_MODULES="$ndk_MODULES $module_target" + AC_MSG_RESULT([yes]) + $3 +fi +]) + +# ndk_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# -------------------------------------------------------------- +# Just like `PKG_CHECK_MODULES'. However, it uses the ndk-build +# system instead. + +AC_DEFUN([ndk_CHECK_MODULES], +[ + ndk_modules= + ndk_parse_pkg_config_string "$2" + ndk_found=no + + for module in $ndk_modules; do + ndk_SEARCH_MODULE([$module], [$1], [ndk_found=yes], [ndk_found=no]) + done + + AS_IF([test "$ndk_found" = "yes"],[$3],[$4]) +]) + +# ndk_CONFIG_FILES +# ------------------------------------------------------------- +# Write out the NDK build Makefile with the appropriate variables +# set if the NDK has been initialized. + +AC_DEFUN_ONCE([ndk_CONFIG_FILES], +[ + if test "$ndk_INITIALIZED" = "yes"; then + NDK_BUILD_ANDROID_MK="$ndk_MAKEFILES" + NDK_BUILD_ARCH=$ndk_ARCH + NDK_BUILD_ABI=$ndk_ABI + NDK_BUILD_SDK=$ndk_API + NDK_BUILD_CC=$CC + NDK_BUILD_AR=$AR + NDK_BUILD_MODULES="$ndk_MODULES" + + AC_SUBST([NDK_BUILD_ANDROID_MK]) + AC_SUBST([NDK_BUILD_ARCH]) + AC_SUBST([NDK_BUILD_ABI]) + AC_SUBST([NDK_BUILD_SDK]) + AC_SUBST([NDK_BUILD_CC]) + AC_SUBST([NDK_BUILD_AR]) + AC_SUBST([NDK_BUILD_MODULES]) + + AC_CONFIG_FILES([$ndk_DIR/Makefile]) + AC_CONFIG_FILES([$ndk_DIR/ndk-build.mk]) + fi +]) diff --git a/src/Makefile.in b/src/Makefile.in index 1b4a8a16c46..ddc0b89dda1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -35,7 +35,7 @@ abs_top_srcdir=@abs_top_srcdir@ VPATH = $(srcdir) # This is not empty if this is a Makefile that will be copied to -# xcompile/src. +# cross/src. XCONFIGURE = @XCONFIGURE@ ifneq ($(XCONFIGURE),) @@ -138,6 +138,8 @@ LIB_PTHREAD=@LIB_PTHREAD@ LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@ +GIF_CFLAGS=@GIF_CFLAGS@ + XCB_LIBS=@XCB_LIBS@ XFT_LIBS=@XFT_LIBS@ XRENDER_LIBS=@XRENDER_LIBS@ @@ -384,6 +386,7 @@ HAIKU_CFLAGS = @HAIKU_CFLAGS@ ANDROID_OBJ = @ANDROID_OBJ@ ANDROID_LIBS = @ANDROID_LIBS@ +ANDROID_LDFLAGS = @ANDROID_LDFLAGS@ ANDROID_CFLAGS = @ANDROID_CFLAGS@ DUMPING=@DUMPING@ @@ -428,7 +431,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) $(TREE_SITTER_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ $(WERROR_CFLAGS) $(HAIKU_CFLAGS) $(XCOMPOSITE_CFLAGS) $(XSHAPE_CFLAGS) \ - $(ANDROID_CFLAGS) + $(ANDROID_CFLAGS) $(GIF_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) ALL_OBJC_CFLAGS = $(EMACS_CFLAGS) \ $(filter-out $(NON_OBJC_CFLAGS),$(WARN_CFLAGS)) $(CFLAGS) \ @@ -745,10 +748,18 @@ ifeq ($(XCONFIGURE),android) ## is not dumped here. Instead, it dumps itself the first time it ## starts on the user's device. +# Include ndk-build.mk in order to build Emacs dependencies. +old_top_builddir := $(top_builddir) +top_builddir := $(old_top_builddir)/.. +include $(old_top_builddir)/ndk-build/ndk-build.mk +top_builddir := $(old_top_builddir) + libemacs.so: $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(EMACSRES) \ - $(MAKE_PDUMPER_FINGERPRINT) + $(MAKE_PDUMPER_FINGERPRINT) $(NDK_BUILD_SHARED) \ + $(NDK_BUILD_STATIC) $(AM_V_CCLD)$(CC) -o $@ $(ALL_CFLAGS) $(TEMACS_LDFLAGS) \ - $(LDFLAGS) -shared $(ALLOBJS) $(LIBEGNU_ARCHIVE) $(LIBES) + $(ANDROID_LDFLAGS) $(LDFLAGS) -shared $(ALLOBJS) \ + $(LIBEGNU_ARCHIVE) $(LIBES) $(AM_V_at)$(MAKE_PDUMPER_FINGERPRINT) $@ # There is also a binary named `android-emacs' which simply calls diff --git a/src/android.c b/src/android.c index a51d0518484..d788c6f19b4 100644 --- a/src/android.c +++ b/src/android.c @@ -1086,6 +1086,39 @@ android_hack_asset_fd (AAsset *asset) return fd; } +/* Read two bytes from FD and see if they are ``PK'', denoting ZIP + archive compressed data. + + If they are not, rewind the file descriptor to offset 0. + + If either operation fails, return -1 and close FD. Else, value is + FD. */ + +static int +android_check_compressed_file (int fd) +{ + char bytes[2]; + + if (read (fd, bytes, 2) != 2) + goto lseek_back; + + if (bytes[0] != 'P' || bytes[1] != 'K') + goto lseek_back; + + /* This could be compressed data! */ + return -1; + + lseek_back: + /* Seek back to offset 0. If this fails, return -1. */ + if (lseek (fd, 0, SEEK_SET) != 0) + { + close (fd); + return -1; + } + + return fd; +} + /* `open' and such are modified even though they exist on Android, because Emacs treats "/assets/" as a special directory that must contain all assets in the application package. */ @@ -1095,7 +1128,7 @@ android_open (const char *filename, int oflag, int mode) { const char *name; AAsset *asset; - int fd; + int fd, oldfd; off_t out_start, out_length; bool fd_hacked; @@ -1118,8 +1151,12 @@ android_open (const char *filename, int oflag, int mode) return -1; } + /* If given AASSET_MODE_BUFFER (which is what Emacs probably + does, given that a file descriptor is not always available), + the framework fails to uncompress the data before it returns + a file descriptor. */ asset = AAssetManager_open (asset_manager, name, - AASSET_MODE_BUFFER); + AASSET_MODE_STREAMING); if (!asset) { @@ -1132,6 +1169,11 @@ android_open (const char *filename, int oflag, int mode) fd = AAsset_openFileDescriptor (asset, &out_start, &out_length); + /* The platform sometimes returns a file descriptor to ZIP + compressed data. Detect that and fall back to creating a + shared memory file descriptor. */ + fd = android_check_compressed_file (fd); + if (fd == -1) { /* The asset can't be accessed for some reason. Try to @@ -1152,7 +1194,13 @@ android_open (const char *filename, int oflag, int mode) which will close the original file descriptor. */ if (!fd_hacked) - fd = fcntl (fd, F_DUPFD_CLOEXEC); + { + oldfd = fd; + fd = fcntl (oldfd, F_DUPFD_CLOEXEC); + + /* Close the original file descriptor. */ + close (oldfd); + } if (fd >= ANDROID_MAX_ASSET_FD || fd < 0) { @@ -1978,6 +2026,25 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object, return event_serial; } +extern JNIEXPORT jlong JNICALL +NATIVE_NAME (sendExpose) (JNIEnv *env, jobject object, + jshort window, jint x, jint y, + jint width, jint height) +{ + union android_event event; + + event.xexpose.type = ANDROID_EXPOSE; + event.xexpose.serial = ++event_serial; + event.xexpose.window = window; + event.xexpose.x = x; + event.xexpose.y = y; + event.xexpose.width = width; + event.xexpose.height = height; + + android_write_event (&event); + return event_serial; +} + #ifdef __clang__ #pragma clang diagnostic pop #else @@ -4222,7 +4289,14 @@ android_readdir (struct android_dir *dir) dirent.d_ino = 0; dirent.d_off = 0; dirent.d_reclen = sizeof dirent; - dirent.d_type = DT_UNKNOWN; + + /* If this is not a directory, return DT_UNKNOWN. Otherwise, + return DT_DIR. */ + + if (android_is_directory (dir->asset_dir)) + dirent.d_type = DT_DIR; + else + dirent.d_type = DT_UNKNOWN; /* Note that dir->asset_dir is actually a NULL terminated string. */ diff --git a/src/androidgui.h b/src/androidgui.h index 3b9a74dc0b0..619c5e44f15 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -234,6 +234,7 @@ enum android_event_type ANDROID_ICONIFIED, ANDROID_DEICONIFIED, ANDROID_CONTEXT_MENU, + ANDROID_EXPOSE, }; struct android_any_event @@ -332,6 +333,15 @@ struct android_button_event unsigned int button; }; +struct android_expose_event +{ + enum android_event_type type; + unsigned long serial; + android_window window; + int x, y; + int width, height; +}; + struct android_touch_event { /* Type of the event. */ @@ -415,6 +425,7 @@ union android_event struct android_crossing_event xcrossing; struct android_motion_event xmotion; struct android_button_event xbutton; + struct android_expose_event xexpose; /* This has no parallel in X, since the X model of having monotonically increasing touch IDs can't work on Android. */ diff --git a/src/androidselect.c b/src/androidselect.c new file mode 100644 index 00000000000..4a71b376e28 --- /dev/null +++ b/src/androidselect.c @@ -0,0 +1,249 @@ +/* Communication module for Android terminals. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#include +#include + +#include "lisp.h" +#include "blockinput.h" +#include "coding.h" +#include "android.h" +#include "androidterm.h" + +/* Selection support on Android is confined to copying and pasting of + plain text from the clipboard. There is no primary selection. + + While newer versions of Android are supposed to have the necessary + interfaces for transferring other kinds of selection data, doing so + is too complicated, and involves registering ``content providers'' + and all kinds of other stuff. */ + + + +/* Structure describing the EmacsClipboard class. */ + +struct android_emacs_clipboard +{ + jclass class; + jmethodID set_clipboard; + jmethodID owns_clipboard; + jmethodID clipboard_exists; + jmethodID get_clipboard; + jmethodID make_clipboard; +}; + +/* Methods associated with the EmacsClipboard class. */ +static struct android_emacs_clipboard clipboard_class; + +/* Reference to the EmacsClipboard object. */ +static jobject clipboard; + + + +static void +android_init_emacs_clipboard (void) +{ + jclass old; + + clipboard_class.class + = (*android_java_env)->FindClass (android_java_env, + "org/gnu/emacs/EmacsClipboard"); + eassert (clipboard_class.class); + + old = clipboard_class.class; + clipboard_class.class + = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, + old); + ANDROID_DELETE_LOCAL_REF (old); + + if (!clipboard_class.class) + emacs_abort (); + +#define FIND_METHOD(c_name, name, signature) \ + clipboard_class.c_name \ + = (*android_java_env)->GetMethodID (android_java_env, \ + clipboard_class.class, \ + name, signature); \ + assert (clipboard_class.c_name); + + FIND_METHOD (set_clipboard, "setClipboard", "([B)V"); + FIND_METHOD (owns_clipboard, "ownsClipboard", "()I"); + FIND_METHOD (clipboard_exists, "clipboardExists", "()Z"); + FIND_METHOD (get_clipboard, "getClipboard", "()[B"); + + clipboard_class.make_clipboard + = (*android_java_env)->GetStaticMethodID (android_java_env, + clipboard_class.class, + "makeClipboard", + "()Lorg/gnu/emacs/" + "EmacsClipboard;"); + assert (clipboard_class.make_clipboard); + +#undef FIND_METHOD +} + + + + +DEFUN ("android-clipboard-owner-p", Fandroid_clipboard_owner_p, + Sandroid_clipboard_owner_p, 0, 0, 0, + doc: /* Return whether or not Emacs owns the clipboard. +Alternatively, return the symbol `lambda' if that could not be +determined. */) + (void) +{ + jint rc; + + block_input (); + rc = (*android_java_env)->CallIntMethod (android_java_env, + clipboard, + clipboard_class.owns_clipboard); + android_exception_check (); + unblock_input (); + + /* If rc is 0 or 1, then Emacs knows whether or not it owns the + clipboard. If rc is -1, then Emacs does not. */ + + if (rc < 0) + return Qlambda; + + return rc ? Qt : Qnil; +} + +DEFUN ("android-set-clipboard", Fandroid_set_clipboard, + Sandroid_set_clipboard, 1, 1, 0, + doc: /* Set the clipboard text to STRING. */) + (Lisp_Object string) +{ + jarray bytes; + + CHECK_STRING (string); + string = ENCODE_UTF_8 (string); + + bytes = (*android_java_env)->NewByteArray (android_java_env, + SBYTES (string)); + android_exception_check (); + + (*android_java_env)->SetByteArrayRegion (android_java_env, bytes, + 0, SBYTES (string), + (jbyte *) SDATA (string)); + (*android_java_env)->CallVoidMethod (android_java_env, + clipboard, + clipboard_class.set_clipboard, + bytes); + android_exception_check (); + + ANDROID_DELETE_LOCAL_REF (bytes); + return Qnil; +} + +DEFUN ("android-get-clipboard", Fandroid_get_clipboard, + Sandroid_get_clipboard, 0, 0, 0, + doc: /* Return the current contents of the clipboard. +Value is a multibyte string containing decoded clipboard +text. +Alternatively, return nil if the clipboard is empty. */) + (void) +{ + Lisp_Object string; + jarray bytes; + jmethodID method; + size_t length; + jbyte *data; + + method = clipboard_class.get_clipboard; + bytes + = (*android_java_env)->CallObjectMethod (android_java_env, + clipboard, + method); + + if (!bytes) + { + android_exception_check (); + return Qnil; + } + + length = (*android_java_env)->GetArrayLength (android_java_env, + bytes); + data = (*android_java_env)->GetByteArrayElements (android_java_env, + bytes, NULL); + android_exception_check (); + + string = make_unibyte_string ((char *) data, length); + + (*android_java_env)->ReleaseByteArrayElements (android_java_env, + bytes, data, + JNI_ABORT); + ANDROID_DELETE_LOCAL_REF (bytes); + + /* Now decode the resulting string. */ + return code_convert_string_norecord (string, Qutf_8, Qnil); +} + +DEFUN ("android-clipboard-exists-p", Fandroid_clipboard_exists_p, + Sandroid_clipboard_exists_p, 0, 0, 0, + doc: /* Return whether or not clipboard contents exist. */) + (void) +{ + jboolean rc; + jmethodID method; + + method = clipboard_class.clipboard_exists; + rc = (*android_java_env)->CallBooleanMethod (android_java_env, + clipboard, + method); + android_exception_check (); + + return rc ? Qt : Qnil; +} + + + +void +init_androidselect (void) +{ + jobject tem; + jmethodID make_clipboard; + + android_init_emacs_clipboard (); + + make_clipboard = clipboard_class.make_clipboard; + tem + = (*android_java_env)->CallStaticObjectMethod (android_java_env, + clipboard_class.class, + make_clipboard); + if (!tem) + emacs_abort (); + + clipboard = (*android_java_env)->NewGlobalRef (android_java_env, tem); + + if (!clipboard) + emacs_abort (); + + ANDROID_DELETE_LOCAL_REF (tem); +} + +void +syms_of_androidselect (void) +{ + defsubr (&Sandroid_clipboard_owner_p); + defsubr (&Sandroid_set_clipboard); + defsubr (&Sandroid_get_clipboard); + defsubr (&Sandroid_clipboard_exists_p); +} diff --git a/src/androidterm.c b/src/androidterm.c index 1141f50f266..d5dafe9b0d7 100644 --- a/src/androidterm.c +++ b/src/androidterm.c @@ -818,6 +818,28 @@ handle_one_android_event (struct android_display_info *dpyinfo, goto OTHER; + case ANDROID_EXPOSE: + + f = any; + + if (f) + { + if (!FRAME_VISIBLE_P (f)) + { + f->output_data.android->has_been_visible = true; + SET_FRAME_GARBAGED (f); + } + + if (!FRAME_GARBAGED_P (f)) + { + expose_frame (f, event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height); + show_back_buffer (f); + } + } + + goto OTHER; + case ANDROID_BUTTON_PRESS: case ANDROID_BUTTON_RELEASE: /* If we decide we want to generate an event to be seen diff --git a/src/androidterm.h b/src/androidterm.h index 11b24d40b73..8cc31f1ab57 100644 --- a/src/androidterm.h +++ b/src/androidterm.h @@ -432,6 +432,15 @@ extern void sfntfont_android_shrink_scanline_buffer (void); extern void init_sfntfont_android (void); extern void syms_of_sfntfont_android (void); +/* Defined in androidselect.c */ + +#ifndef ANDROID_STUBIFY + +extern void init_androidselect (void); +extern void syms_of_androidselect (void); + +#endif + #define RGB_TO_ULONG(r, g, b) (((r) << 16) | ((g) << 8) | (b)) diff --git a/src/emacs.c b/src/emacs.c index 994a4d1db93..02016e53c45 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -2409,6 +2409,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_fontset (); #if !defined ANDROID_STUBIFY syms_of_androidfont (); + syms_of_androidselect (); syms_of_sfntfont (); syms_of_sfntfont_android (); #endif /* !ANDROID_STUBIFY */ @@ -2514,6 +2515,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY init_androidfont (); + init_androidselect (); init_sfntfont (); init_sfntfont_android (); #endif -- 2.39.5