1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 18:40:39 -08:00

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.
This commit is contained in:
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'. # Built by `aapt'.
java/org/gnu/emacs/R.java 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'. # Built by `config.status'.
java/AndroidManifest.xml 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/\.\.\/admin\/charsets/..\/..\/admin\/charsets/g' \
-e 's/^libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/g' \ -e 's/^libsrc =.*$$/libsrc = \.\.\/\.\.\/lib-src/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 > $@ < $(top_builddir)/src/Makefile.android > $@
src/epaths.h: $(top_builddir)/src/epaths.h 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_ANY_CXX_MODULE = @NDK_BUILD_ANY_CXX_MODULE@
NDK_BUILD_SHARED = NDK_BUILD_SHARED =
NDK_BUILD_STATIC = NDK_BUILD_STATIC =
NDK_BUILD_READELF = @NDK_BUILD_READELF@
define uniqify define uniqify
$(if $1,$(firstword $1) $(call uniqify,$(filter-out $(firstword $1),$1))) $(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. # code. Instead, it is automatically included by the Java compiler.
RESOURCE_FILE := $(srcdir)/org/gnu/emacs/R.java 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 # CLASS_FILES is what should actually be built and included in the
# resulting Emacs executable. The Java compiler might generate more # resulting Emacs executable. The Java compiler might generate more
# than one class file for each source file, so this only serves as a # 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 \ -J $(dir $@) -M AndroidManifest.xml \
-S $(top_srcdir)/java/res -S $(top_srcdir)/java/res
# Make all class files depend on R.java being built. # Generate a list of libemacs's dependencies with each item ordered
$(CLASS_FILES): $(RESOURCE_FILE) # 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 .SUFFIXES: .java .class
$(CLASS_FILES) &: $(JAVA_FILES) $(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 # N.B. that find must be called all over again in case javac generated
# nested classes. # 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) classes.dex: $(CLASS_FILES) $(if $(IS_D8_R8), $(srcdir)/proguard.conf)
$(AM_V_D8) $(D8) --classpath $(ANDROID_JAR) \ $(AM_V_D8) $(D8) --classpath $(ANDROID_JAR) \
$(subst $$,\$$,$(shell find $(srcdir) -type f \ $(ALL_CLASS_FILES) \
-name *.class)) --output $(builddir) \ --output $(builddir) \
--min-api $(ANDROID_MIN_SDK) \ --min-api $(ANDROID_MIN_SDK) \
$(if $(filter false,$(ANDROID_DEBUGGABLE)),--release, \ $(if $(filter false,$(ANDROID_DEBUGGABLE)),--release, \
--debug) \ --debug) \
$(if $(IS_D8_R8),--pg-conf $(srcdir)/proguard.conf) $(if $(IS_D8_R8),--pg-conf $(srcdir)/proguard.conf)
# When emacs.keystore expires, regenerate it with: # When emacs.keystore expires, regenerate it with:
@ -345,7 +423,8 @@ TAGS: $(ETAGS) $(tagsfiles)
$(AM_V_GEN) $(ETAGS) $(tagsfiles) $(AM_V_GEN) $(ETAGS) $(tagsfiles)
clean: 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 rm -rf install-temp $(RESOURCE_FILE) TAGS
find . -name '*.class' $(FIND_DELETE) find . -name '*.class' $(FIND_DELETE)

View file

@ -321,39 +321,35 @@ public final class EmacsNative
static static
{ {
/* Older versions of Android cannot link correctly with shared /* A library search path misconfiguration prevents older versions of
libraries that link with other shared libraries built along Android from successfully loading application shared libraries
Emacs unless all requisite shared libraries are explicitly unless all requisite shared libraries provided by the application
loaded from Java. 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, libraryDeps = EmacsConfig.EMACS_SHARED_LIBRARIES;
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", };
for (String dependency : libraryDeps) for (String dependency : libraryDeps)
{ {
try /* Remove the "lib" prefix, if any. */
{ if (dependency.startsWith ("lib"))
System.loadLibrary (dependency); dependency = dependency.substring (3);
}
catch (UnsatisfiedLinkError exception) /* If this library is provided by the operating system, don't
{ link to it. */
/* Ignore this exception. */ 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"); System.loadLibrary ("emacs");
}; };
}; };

View file

@ -339,6 +339,16 @@ NDK_BUILD_NASM=
AS_IF([test "$ndk_ARCH" = "x86" || test "$ndk_ARCH" = "x86_64"], AS_IF([test "$ndk_ARCH" = "x86" || test "$ndk_ARCH" = "x86_64"],
[AC_CHECK_PROGS([NDK_BUILD_NASM], [nasm])]) [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 # Search for a C++ compiler. Upon failure, pretend the C compiler is a
# C++ compiler and use that instead. # 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_CXX_LDFLAGS])
AC_SUBST([NDK_BUILD_ANY_CXX_MODULE]) AC_SUBST([NDK_BUILD_ANY_CXX_MODULE])
AC_SUBST([NDK_BUILD_CFLAGS]) AC_SUBST([NDK_BUILD_CFLAGS])
AC_SUBST([NDK_BUILD_READELF])
AC_CONFIG_FILES([$ndk_DIR/Makefile]) AC_CONFIG_FILES([$ndk_DIR/Makefile])
AC_CONFIG_FILES([$ndk_DIR/ndk-build.mk]) AC_CONFIG_FILES([$ndk_DIR/ndk-build.mk])