Generate Android shared library list automatically

* .gitignore: Ignore new generated files.

* cross/Makefile.in (src/Makefile): Remove leftover
specification of the source Gnulib directory.

* cross/ndk-build/ndk-build.mk.in (NDK_BUILD_READELF): New
variable.

* java/Makefile.in (CONFIG_FILE, ALL_DEPENDENCIES, READELF)
(cf-stamp-1, cf-stamp): New variables and rules; compute the set
of library files in the order of loading and generate a file
with this information.
(ALL_CLASS_FILES): New variable; if builddir is not srcdir,
$($(CONFIG_FILE), $(CLASS_FILES)): Depend on EmacsConfig.java.
add generated files in the build directory.
(classes.dex): Adjust to match.

* java/org/gnu/emacs/EmacsNative.java (EmacsNative)
<static initializer>: Load shared libraries from
EMACS_SHARED_LIBRARIES rather than a hard-coded list.

* m4/ndk-build.m4 (ndk_INIT): Search for readelf...
(ndk_CHECK_MODULES): ...and substitute its path as
NDK_BUILD_READELF.
scratch/lisp-func-type-decls
Po Lu 2024-04-22 16:27:30 +08:00
parent 4d9629b087
commit 3bcdf010a9
6 changed files with 125 additions and 34 deletions

4
.gitignore vendored
View File

@ -66,6 +66,10 @@ java/org/gnu/emacs/*.class
# Built by `aapt'.
java/org/gnu/emacs/R.java
# Built by `make'.
java/org/gnu/emacs/EmacsConfig.java
java/org/gnu/emacs/cf-stamp
# Built by `config.status'.
java/AndroidManifest.xml

View File

@ -140,7 +140,7 @@ src/Makefile: $(top_builddir)/src/Makefile.android
-e 's/\.\.\/admin\/charsets/..\/..\/admin\/charsets/g' \
-e 's/^libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' \
-e 's/libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' \
-e 's/-I\$$(top_srcdir)\/lib/-I..\/$(subst /,\/,$(srcdir))\/lib/g' \
-e 's/-I\$$(top_srcdir)\/lib//g' \
< $(top_builddir)/src/Makefile.android > $@
src/epaths.h: $(top_builddir)/src/epaths.h

View File

@ -27,6 +27,7 @@ NDK_BUILD_CXX_LDFLAGS = @NDK_BUILD_CXX_LDFLAGS@
NDK_BUILD_ANY_CXX_MODULE = @NDK_BUILD_ANY_CXX_MODULE@
NDK_BUILD_SHARED =
NDK_BUILD_STATIC =
NDK_BUILD_READELF = @NDK_BUILD_READELF@
define uniqify
$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1)))

View File

@ -83,6 +83,10 @@ RESOURCE_FILES := $(foreach file,$(wildcard $(srcdir)/res/*), \
# code. Instead, it is automatically included by the Java compiler.
RESOURCE_FILE := $(srcdir)/org/gnu/emacs/R.java
# EmacsConfig.java is a file that holds information regarding the set of
# shared libraries this binary links to, and similar build variables.
CONFIG_FILE := $(builddir)/org/gnu/emacs/EmacsConfig.java
# CLASS_FILES is what should actually be built and included in the
# resulting Emacs executable. The Java compiler might generate more
# than one class file for each source file, so this only serves as a
@ -294,8 +298,72 @@ $(RESOURCE_FILE): $(RESOURCE_FILES)
-J $(dir $@) -M AndroidManifest.xml \
-S $(top_srcdir)/java/res
# Make all class files depend on R.java being built.
$(CLASS_FILES): $(RESOURCE_FILE)
# Generate a list of libemacs's dependencies with each item ordered
# before its dependents for the startup process to load in advance, as
# older versions of the dynamic linker do not consider these libraries
# when resolving its imports. The several following statements are
# executed from a recursive `make' run after shared libraries are
# generated.
ALL_DEPENDENCIES :=
ifneq (,$(filter cf-stamp-1,$(MAKECMDGOALS)))
# Don't be sidetracked by dependencies of shared libraries outside the
# ndk-build directory.
define get-dependencies
$(foreach x, \
$(and $(wildcard $(top_builddir)/cross/ndk-build/$1.so), \
$(shell $(NDK_BUILD_READELF) -d \
$(wildcard $(top_builddir)/cross/ndk-build/$1.so) \
| sed -n 's/.*(NEEDED).*\[\(.*\.so\)\].*/\1/p')), \
$(basename $(notdir $(x))))
endef #get-dependencies
define resolve-one-dependency
$(foreach dependency,$(call get-dependencies,$1),\
$(if $(findstring "$(dependency)",$(ALL_DEPENDENCIES)),,\
$(call resolve-one-dependency,$(basename $(notdir $(dependency)))) \
$(eval ALL_DEPENDENCIES := $(ALL_DEPENDENCIES) "$(dependency)",)))
endef #resolve-one-dependency
DEPENDENCIES := $(foreach file,$(NDK_BUILD_SHARED),\
$(basename $(notdir $(file))))
$(foreach file,$(DEPENDENCIES),\
$(if $(findstring "$(file)",$(ALL_DEPENDENCIES)),,\
$(call resolve-one-dependency,$(file)) \
$(eval ALL_DEPENDENCIES := $(ALL_DEPENDENCIES) "$(file)",)))
endif
# EmacsConfig.java:
ifeq (${V},1)
AM_V_EMACSCONFIG =
else
AM_V_EMACSCONFIG = @$(info $. GEN org/gnu/emacs/EmacsConfig.java)
endif
.PHONY: cf-stamp-1
cf-stamp-1:
$(AM_V_at) echo 'package org.gnu.emacs;\
public class EmacsConfig\
{\
/* This is a generated file. Do not edit! */\
public static final String[] EMACS_SHARED_LIBRARIES\
= {$(ALL_DEPENDENCIES)};\
}' | sed 's/\\//g' > globals.tmp
$(AM_V_at) mkdir -p org/gnu/emacs
$(AM_V_at) $(top_srcdir)/build-aux/move-if-change \
globals.tmp org/gnu/emacs/EmacsConfig.java
# cf-stamp-1 is a phony target invoked in a second `make' instance after
# all shared libraries are compiled, because the computation of
# ALL_DEPENDENCIES cannot be postponed until that stage in this instance
# of Make.
cf-stamp: $(NDK_BUILD_SHARED) $(CROSS_LIBS)
$(AM_V_EMACSCONFIG) $(MAKE) cf-stamp-1
$(AM_V_at) touch $@
$(CONFIG_FILE): cf-stamp; @true
# Make all class files depend on R.java and EmacsConfig.java being
# built.
$(CLASS_FILES): $(RESOURCE_FILE) $(CONFIG_FILE)
.SUFFIXES: .java .class
$(CLASS_FILES) &: $(JAVA_FILES)
@ -305,13 +373,23 @@ $(CLASS_FILES) &: $(JAVA_FILES)
# N.B. that find must be called all over again in case javac generated
# nested classes.
ALL_CLASS_FILES = \
$(subst $$,\$$,$(shell find $(srcdir) -type f -name *.class))
ifneq ($(builddir),$(srcdir))
# If the build directory is distinct from the source directory, also
# include generated class files located there.
ALL_CLASS_FILES = $(ALL_CLASS_FILES) \
$(subst $$,\$$,$(shell find $(builddir) -type f -name *.class))
endif
classes.dex: $(CLASS_FILES) $(if $(IS_D8_R8), $(srcdir)/proguard.conf)
$(AM_V_D8) $(D8) --classpath $(ANDROID_JAR) \
$(subst $$,\$$,$(shell find $(srcdir) -type f \
-name *.class)) --output $(builddir) \
$(ALL_CLASS_FILES) \
--output $(builddir) \
--min-api $(ANDROID_MIN_SDK) \
$(if $(filter false,$(ANDROID_DEBUGGABLE)),--release, \
--debug) \
--debug) \
$(if $(IS_D8_R8),--pg-conf $(srcdir)/proguard.conf)
# When emacs.keystore expires, regenerate it with:
@ -345,7 +423,8 @@ TAGS: $(ETAGS) $(tagsfiles)
$(AM_V_GEN) $(ETAGS) $(tagsfiles)
clean:
rm -f *.apk emacs.apk-in *.dex *.unaligned *.class *.idsig
rm -f *.apk emacs.apk-in *.dex *.unaligned *.class *.idsig \
cf-stamp $(CONFIG_FILE)
rm -rf install-temp $(RESOURCE_FILE) TAGS
find . -name '*.class' $(FIND_DELETE)

View File

@ -321,39 +321,35 @@ public final class EmacsNative
static
{
/* Older versions of Android cannot link correctly with shared
libraries that link with other shared libraries built along
Emacs unless all requisite shared libraries are explicitly
loaded from Java.
/* A library search path misconfiguration prevents older versions of
Android from successfully loading application shared libraries
unless all requisite shared libraries provided by the application
are explicitly loaded from Java. The build process arranges that
EmacsConfig.EMACS_SHARED_LIBRARIES hold the names of each of
these libraries in the correct order, so load them now. */
Every time you add a new shared library dependency to Emacs,
please insert it here as well, before other shared libraries of
which it might be a dependency. */
libraryDeps = new String[] { "c++_shared", "gnustl_shared",
"stlport_shared", "gabi++_shared",
"png_emacs", "pcre_emacs",
"selinux_emacs", "crypto_emacs",
"packagelistparser_emacs",
"gmp_emacs", "nettle_emacs",
"p11-kit_emacs", "tasn1_emacs",
"hogweed_emacs", "gnutls_emacs",
"jpeg_emacs", "tiff_emacs",
"icuuc_emacs", "xml2_emacs",
"harfbuzz_emacs", "tree-sitter_emacs", };
libraryDeps = EmacsConfig.EMACS_SHARED_LIBRARIES;
for (String dependency : libraryDeps)
{
try
{
System.loadLibrary (dependency);
}
catch (UnsatisfiedLinkError exception)
{
/* Ignore this exception. */
}
/* Remove the "lib" prefix, if any. */
if (dependency.startsWith ("lib"))
dependency = dependency.substring (3);
/* If this library is provided by the operating system, don't
link to it. */
if (dependency.equals ("z")
|| dependency.equals ("c")
|| dependency.equals ("m")
|| dependency.equals ("dl")
|| dependency.equals ("log")
|| dependency.equals ("android"))
continue;
System.loadLibrary (dependency);
}
/* At this point, it should be alright to load Emacs. */
System.loadLibrary ("emacs");
};
};

View File

@ -339,6 +339,16 @@ NDK_BUILD_NASM=
AS_IF([test "$ndk_ARCH" = "x86" || test "$ndk_ARCH" = "x86_64"],
[AC_CHECK_PROGS([NDK_BUILD_NASM], [nasm])])
# Search for a suitable readelf binary, which is required to generate
# the shared library list loaded on old Android systems.
AC_PATH_PROGS([READELF], [readelf llvm-readelf $host_alias-readelf],
[], [$ndk_ranlib_search_path:$PATH])
AS_IF([test -z "$READELF"],
[AC_MSG_ERROR([A suitable `readelf' utility cannot be located.
Please verify that the Android NDK has been installed correctly,
or install a functioning `readelf' yourself.])])
NDK_BUILD_READELF="$READELF"
# Search for a C++ compiler. Upon failure, pretend the C compiler is a
# C++ compiler and use that instead.
@ -644,6 +654,7 @@ AC_DEFUN_ONCE([ndk_CONFIG_FILES],
AC_SUBST([NDK_BUILD_CXX_LDFLAGS])
AC_SUBST([NDK_BUILD_ANY_CXX_MODULE])
AC_SUBST([NDK_BUILD_CFLAGS])
AC_SUBST([NDK_BUILD_READELF])
AC_CONFIG_FILES([$ndk_DIR/Makefile])
AC_CONFIG_FILES([$ndk_DIR/ndk-build.mk])