From 8e20ef6205b3c96135b1c1e4484d523dbecb1b98 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Tue, 24 Jun 2014 20:01:52 -0700 Subject: [PATCH] Support to add JNI of both archs in multilib build. Use "LOCAL_MULTILIB := both" to install jni libraries of both archs in multilib build. The build system will package jni of both archs to the apk, or install them to the right location on the system image and create symlinks, extract .so files from prebuilt apk, etc if appropriate. Bug: 15849902 Change-Id: I7e147b5a47db476584c38250de7b36c75ea40d81 --- core/clear_vars.mk | 2 + core/definitions.mk | 14 ++- core/install_jni_libs.mk | 152 ++++++++++++------------------ core/install_jni_libs_internal.mk | 104 ++++++++++++++++++++ core/package_internal.mk | 6 +- core/prebuilt_internal.mk | 2 +- 6 files changed, 184 insertions(+), 96 deletions(-) create mode 100644 core/install_jni_libs_internal.mk diff --git a/core/clear_vars.mk b/core/clear_vars.mk index c6a09d854..84aaa577c 100644 --- a/core/clear_vars.mk +++ b/core/clear_vars.mk @@ -167,6 +167,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES_$(TARGET_ARCH):= LOCAL_GENERATED_SOURCES_$(TARGET_ARCH):= LOCAL_REQUIRED_MODULES_$(TARGET_ARCH):= LOCAL_CLANG_$(TARGET_ARCH):= +LOCAL_PREBUILT_JNI_LIBS_$(TARGET_ARCH):= ifdef TARGET_2ND_ARCH LOCAL_SRC_FILES_$(TARGET_2ND_ARCH):= LOCAL_CFLAGS_$(TARGET_2ND_ARCH):= @@ -181,6 +182,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES_$(TARGET_2ND_ARCH):= LOCAL_GENERATED_SOURCES_$(TARGET_2ND_ARCH):= LOCAL_REQUIRED_MODULES_$(TARGET_2ND_ARCH):= LOCAL_CLANG_$(TARGET_2ND_ARCH):= +LOCAL_PREBUILT_JNI_LIBS_$(TARGET_2ND_ARCH):= endif LOCAL_SRC_FILES_$(HOST_ARCH):= LOCAL_CFLAGS_$(HOST_ARCH):= diff --git a/core/definitions.mk b/core/definitions.mk index c2c882379..441c18630 100644 --- a/core/definitions.mk +++ b/core/definitions.mk @@ -1723,10 +1723,20 @@ $(hide) $(AAPT) package -u $(PRIVATE_AAPT_FLAGS) \ -F $@ endef +# We need the extra blank line, so that the command will be on a separate line. +# $(1): the ABI name +# $(2): the list of shared libraies +define _add-jni-shared-libs-to-package-per-abi +$(hide) cp $(2) $(dir $@)lib/$(1) + +endef + define add-jni-shared-libs-to-package $(hide) rm -rf $(dir $@)lib -$(hide) mkdir -p $(dir $@)lib/$(PRIVATE_JNI_SHARED_LIBRARIES_ABI) -$(hide) cp $(PRIVATE_JNI_SHARED_LIBRARIES) $(dir $@)lib/$(PRIVATE_JNI_SHARED_LIBRARIES_ABI) +$(hide) mkdir -p $(addprefix $(dir $@)lib/,$(PRIVATE_JNI_SHARED_LIBRARIES_ABI)) +$(foreach abi,$(PRIVATE_JNI_SHARED_LIBRARIES_ABI),\ + $(call _add-jni-shared-libs-to-package-per-abi,$(abi),\ + $(patsubst $(abi):%,%,$(filter $(abi):%,$(PRIVATE_JNI_SHARED_LIBRARIES))))) $(hide) (cd $(dir $@) && zip -r $(notdir $@) lib) $(hide) rm -rf $(dir $@)lib endef diff --git a/core/install_jni_libs.mk b/core/install_jni_libs.mk index 700d106c8..918a83915 100644 --- a/core/install_jni_libs.mk +++ b/core/install_jni_libs.mk @@ -1,28 +1,16 @@ # Decides how to install the jni libraries needed by an apk. # Input variables: -# LOCAL_JNI_SHARED_LIBRARIES -# LOCAL_INSTALLED_MODULE +# my_module_multilib, LOCAL_2ND_ARCH_VAR_PREFIX (from package.mk or prebuilt.mk) # rs_compatibility_jni_libs (from java.mk) # my_module_path (from base_rules.mk) # partition_tag (from base_rules.mk) # my_prebuilt_src_file (from prebuilt_internal.mk) # # Output variables: -# jni_shared_libraries, jni_shared_libraries_abi, if we are going to embed the libraries into the apk; -# my_extracted_jni_libs, if we extract jni libs from prebuilt apk. +# jni_shared_libraries, jni_shared_libraries_abi, jni_shared_libraries_with_abis if we are going to embed the libraries into the apk; +# extracted_jni_libs, if we extract jni libs from prebuilt apk. # -jni_shared_libraries := \ - $(addprefix $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET_OUT_INTERMEDIATE_LIBRARIES)/, \ - $(addsuffix .so, \ - $(LOCAL_JNI_SHARED_LIBRARIES))) - -# Include RS dynamically-generated libraries as well -# Keep this ifneq, as the += otherwise adds spaces that need to be stripped. -ifneq ($(rs_compatibility_jni_libs),) -jni_shared_libraries += $(rs_compatibility_jni_libs) -endif - my_embed_jni := ifneq ($(TARGET_BUILD_APPS),) my_embed_jni := true @@ -35,87 +23,69 @@ ifeq ($(filter $(TARGET_OUT)/% $(TARGET_OUT_VENDOR)/% $(TARGET_OUT_OEM)/%, $(my_ my_embed_jni := true endif -# App-specific lib path. -my_app_lib_path := $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET$(partition_tag)_OUT_SHARED_LIBRARIES)/$(basename $(my_installed_module_stem)) -my_extracted_jni_libs := +jni_shared_libraries := +jni_shared_libraries_abis := +# jni_shared_libraries_with_abis is a list of : +jni_shared_libraries_with_abis := +extracted_jni_libs := -ifdef my_embed_jni -# App explicitly requires the prebuilt NDK stl shared libraies. -# The NDK stl shared libraries should never go to the system image. -ifneq ($(filter $(LOCAL_NDK_STL_VARIANT), stlport_shared c++_shared),) -ifndef LOCAL_SDK_VERSION -$(error LOCAL_SDK_VERSION must be defined with LOCAL_NDK_STL_VARIANT, \ - LOCAL_PACKAGE_NAME=$(LOCAL_PACKAGE_NAME)) +####################################### +# For TARGET_ARCH +my_2nd_arch_prefix := +my_add_jni := +# The module is built for TARGET_ARCH +ifeq ($(my_2nd_arch_prefix),$(LOCAL_2ND_ARCH_VAR_PREFIX)) +my_add_jni := true endif +# Or it explicitly requires both +ifeq ($(my_module_multilib),both) +my_add_jni := true endif -ifeq (stlport_shared,$(LOCAL_NDK_STL_VARIANT)) -jni_shared_libraries += \ - $(HISTORICAL_NDK_VERSIONS_ROOT)/current/sources/cxx-stl/stlport/libs/$(TARGET_$(LOCAL_2ND_ARCH_VAR_PREFIX)CPU_ABI)/libstlport_shared.so -else ifeq (c++_shared,$(LOCAL_NDK_STL_VARIANT)) -jni_shared_libraries += \ - $(HISTORICAL_NDK_VERSIONS_ROOT)/current/sources/cxx-stl/llvm-libc++/libs/$(TARGET_$(LOCAL_2ND_ARCH_VAR_PREFIX)CPU_ABI)/libc++_shared.so +ifeq ($(my_add_jni),true) +my_prebuilt_jni_libs := $(LOCAL_PREBUILT_JNI_LIBS_$(TARGET_ARCH)) +ifndef my_prebuilt_jni_libs +my_prebuilt_jni_libs := $(LOCAL_PREBUILT_JNI_LIBS) endif +include $(BUILD_SYSTEM)/install_jni_libs_internal.mk +jni_shared_libraries += $(my_jni_shared_libraries) +jni_shared_libraries_abis += $(my_jni_shared_libraries_abi) +jni_shared_libraries_with_abis += $(addprefix $(my_jni_shared_libraries_abi):,\ + $(my_jni_shared_libraries)) +extracted_jni_libs += $(my_extracted_jni_libs) -# Set the abi directory used by the local JNI shared libraries. -# (Doesn't change how the local shared libraries are compiled, just -# sets where they are stored in the apk.) -ifeq ($(LOCAL_JNI_SHARED_LIBRARIES_ABI),) - jni_shared_libraries_abi := $(TARGET_$(LOCAL_2ND_ARCH_VAR_PREFIX)CPU_ABI) -else - jni_shared_libraries_abi := $(LOCAL_JNI_SHARED_LIBRARIES_ABI) -endif +# Include RS dynamically-generated libraries as well +# TODO: Add multilib support once RS supports generating multilib libraries. +jni_shared_libraries += $(rs_compatibility_jni_libs) +endif # my_add_jni -else # not my_embed_jni +####################################### +# For TARGET_2ND_ARCH +ifdef TARGET_2ND_ARCH +my_2nd_arch_prefix := $(TARGET_2ND_ARCH_VAR_PREFIX) +my_add_jni := +# The module is built for TARGET_2ND_ARCH +ifeq ($(my_2nd_arch_prefix),$(LOCAL_2ND_ARCH_VAR_PREFIX)) +my_add_jni := true +endif +# Or it explicitly requires both +ifeq ($(my_module_multilib),both) +my_add_jni := true +endif +ifeq ($(my_add_jni),true) +my_prebuilt_jni_libs := $(LOCAL_PREBUILT_JNI_LIBS_$(TARGET_2ND_ARCH)) +ifndef my_prebuilt_jni_libs +my_prebuilt_jni_libs := $(LOCAL_PREBUILT_JNI_LIBS) +endif +include $(BUILD_SYSTEM)/install_jni_libs_internal.mk +jni_shared_libraries += $(my_jni_shared_libraries) +jni_shared_libraries_abis += $(my_jni_shared_libraries_abi) +jni_shared_libraries_with_abis += $(addprefix $(my_jni_shared_libraries_abi):,\ + $(my_jni_shared_libraries)) +extracted_jni_libs += $(my_extracted_jni_libs) +endif # my_add_jni +endif # TARGET_2ND_ARCH jni_shared_libraries := $(strip $(jni_shared_libraries)) -ifneq ($(jni_shared_libraries),) -# The jni libaries will be installed to the system.img. -my_jni_filenames := $(notdir $(jni_shared_libraries)) -# Make sure the JNI libraries get installed -$(LOCAL_INSTALLED_MODULE) : | $(addprefix $($(LOCAL_2ND_ARCH_VAR_PREFIX)TARGET$(partition_tag)_OUT_SHARED_LIBRARIES)/, $(my_jni_filenames)) - -# Create symlink in the app specific lib path -ifdef LOCAL_POST_INSTALL_CMD -my_leading_separator := ; -else -my_leading_separator := -endif -$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD += \ - $(my_leading_separator)mkdir -p $(my_app_lib_path) \ - $(foreach lib, $(my_jni_filenames), ;ln -sf ../$(lib) $(my_app_lib_path)/$(lib)) - -# Clear jni_shared_libraries to not embed it into the apk. -jni_shared_libraries := -endif # $(jni_shared_libraries) not empty -endif # my_embed_jni - -ifdef LOCAL_PREBUILT_JNI_LIBS -# Install prebuilt JNI libs to the app specific lib path. -# Files like @path/to/libfoo.so (path inside the apk) are JNI libs extracted from the prebuilt apk; -# Files like path/to/libfoo.so (path relative to LOCAL_PATH) are prebuilts in the source tree. -my_extracted_jni_libs := $(patsubst @%,%, \ - $(filter @%, $(LOCAL_PREBUILT_JNI_LIBS))) -ifdef my_extracted_jni_libs -ifndef my_prebuilt_src_file -$(error No prebuilt apk to extract prebuilt jni libraries $(my_extracted_jni_libs)) -endif -# We use the first jni lib file as dependency. -my_installed_prebuilt_jni := $(my_app_lib_path)/$(notdir $(firstword $(my_extracted_jni_libs))) -$(my_installed_prebuilt_jni): PRIVATE_JNI_LIBS := $(my_extracted_jni_libs) -$(my_installed_prebuilt_jni): $(my_prebuilt_src_file) - @echo "Extract JNI libs ($@ <- $<)" - @mkdir -p $(dir $@) - $(hide) unzip -j -o -d $(dir $@) $< $(PRIVATE_JNI_LIBS) && touch $@ - -$(LOCAL_INSTALLED_MODULE) : | $(my_installed_prebuilt_jni) -endif - -my_prebulit_jni_libs := $(addprefix $(LOCAL_PATH)/, \ - $(filter-out @%, $(LOCAL_PREBUILT_JNI_LIBS))) -ifdef my_prebulit_jni_libs -$(foreach lib, $(my_prebulit_jni_libs), \ - $(eval $(call copy-one-file, $(lib), $(my_app_lib_path)/$(notdir $(lib))))) - -$(LOCAL_INSTALLED_MODULE) : | $(addprefix $(my_app_lib_path)/, $(notdir $(my_prebulit_jni_libs))) -endif -endif # LOCAL_PREBULT_JNI_LIBS +jni_shared_libraries_abis := $(sort $(jni_shared_libraries_abis)) +jni_shared_libraries_with_abis := $(strip $(jni_shared_libraries_with_abis)) +extracted_jni_libs := $(strip $(extracted_jni_libs)) diff --git a/core/install_jni_libs_internal.mk b/core/install_jni_libs_internal.mk new file mode 100644 index 000000000..b50c21e26 --- /dev/null +++ b/core/install_jni_libs_internal.mk @@ -0,0 +1,104 @@ +# Install jni libraries for one arch. +# Input variables: +# my_2nd_arch_prefix: indicate if this is for TARGET_2ND_ARCH. +# my_embed_jni: indicate if we want to embed the jni libs in the apk. +# my_prebuilt_jni_libs +# my_installed_module_stem (from configure_module_stem.mk) +# partition_tag (from base_rules.mk) +# my_prebuilt_src_file (from prebuilt_internal.mk) +# +# Output variables: +# my_jni_shared_libraries, my_jni_shared_libraries_abi, if we are going to embed the libraries into the apk; +# my_extracted_jni_libs, if we extract jni libs from prebuilt apk. +# + +my_jni_shared_libraries := \ + $(addprefix $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/, \ + $(addsuffix .so, \ + $(LOCAL_JNI_SHARED_LIBRARIES))) + +# App-specific lib path. +my_app_lib_path := $($(my_2nd_arch_prefix)TARGET$(partition_tag)_OUT_SHARED_LIBRARIES)/$(basename $(my_installed_module_stem)) +my_extracted_jni_libs := + +ifdef my_embed_jni +# App explicitly requires the prebuilt NDK stl shared libraies. +# The NDK stl shared libraries should never go to the system image. +ifneq ($(filter $(LOCAL_NDK_STL_VARIANT), stlport_shared c++_shared),) +ifndef LOCAL_SDK_VERSION +$(error LOCAL_SDK_VERSION must be defined with LOCAL_NDK_STL_VARIANT, \ + LOCAL_PACKAGE_NAME=$(LOCAL_PACKAGE_NAME)) +endif +endif +ifeq (stlport_shared,$(LOCAL_NDK_STL_VARIANT)) +my_jni_shared_libraries += \ + $(HISTORICAL_NDK_VERSIONS_ROOT)/current/sources/cxx-stl/stlport/libs/$(TARGET_$(my_2nd_arch_prefix)CPU_ABI)/libstlport_shared.so +else ifeq (c++_shared,$(LOCAL_NDK_STL_VARIANT)) +my_jni_shared_libraries += \ + $(HISTORICAL_NDK_VERSIONS_ROOT)/current/sources/cxx-stl/llvm-libc++/libs/$(TARGET_$(my_2nd_arch_prefix)CPU_ABI)/libc++_shared.so +endif + +# Set the abi directory used by the local JNI shared libraries. +# (Doesn't change how the local shared libraries are compiled, just +# sets where they are stored in the apk.) +ifeq ($(LOCAL_JNI_SHARED_LIBRARIES_ABI),) + my_jni_shared_libraries_abi := $(TARGET_$(my_2nd_arch_prefix)CPU_ABI) +else + my_jni_shared_libraries_abi := $(LOCAL_JNI_SHARED_LIBRARIES_ABI) +endif + +else # not my_embed_jni + +my_jni_shared_libraries := $(strip $(my_jni_shared_libraries)) +ifneq ($(my_jni_shared_libraries),) +# The jni libaries will be installed to the system.img. +my_jni_filenames := $(notdir $(my_jni_shared_libraries)) +# Make sure the JNI libraries get installed +$(LOCAL_INSTALLED_MODULE) : | $(addprefix $($(my_2nd_arch_prefix)TARGET$(partition_tag)_OUT_SHARED_LIBRARIES)/, $(my_jni_filenames)) + +# Create symlink in the app specific lib path +ifdef LOCAL_POST_INSTALL_CMD +# Add a shell command separator +LOCAL_POST_INSTALL_CMD += ; +endif +LOCAL_POST_INSTALL_CMD += \ + mkdir -p $(my_app_lib_path) \ + $(foreach lib, $(my_jni_filenames), ;ln -sf ../$(lib) $(my_app_lib_path)/$(lib)) +$(LOCAL_INSTALLED_MODULE): PRIVATE_POST_INSTALL_CMD := $(LOCAL_POST_INSTALL_CMD) + +# Clear jni_shared_libraries to not embed it into the apk. +my_jni_shared_libraries := +endif # $(my_jni_shared_libraries) not empty +endif # my_embed_jni + +ifdef my_prebuilt_jni_libs +# Install prebuilt JNI libs to the app specific lib path. +# Files like @path/to/libfoo.so (path inside the apk) are JNI libs extracted from the prebuilt apk; +# Files like path/to/libfoo.so (path relative to LOCAL_PATH) are prebuilts in the source tree. +my_extracted_jni_libs := $(patsubst @%,%, \ + $(filter @%, $(my_prebuilt_jni_libs))) +ifdef my_extracted_jni_libs +ifndef my_prebuilt_src_file +$(error No prebuilt apk to extract prebuilt jni libraries $(my_extracted_jni_libs)) +endif +# We use the first jni lib file as dependency. +my_installed_prebuilt_jni := $(my_app_lib_path)/$(notdir $(firstword $(my_extracted_jni_libs))) +$(my_installed_prebuilt_jni): PRIVATE_JNI_LIBS := $(my_extracted_jni_libs) +$(my_installed_prebuilt_jni): $(my_prebuilt_src_file) + @echo "Extract JNI libs ($@ <- $<)" + @mkdir -p $(dir $@) + $(hide) unzip -j -o -d $(dir $@) $< $(PRIVATE_JNI_LIBS) && touch $@ + +$(LOCAL_INSTALLED_MODULE) : | $(my_installed_prebuilt_jni) +endif + +# prebuilt JNI exsiting as separate source files. +my_prebuilt_jni_libs := $(addprefix $(LOCAL_PATH)/, \ + $(filter-out @%, $(my_prebuilt_jni_libs))) +ifdef my_prebuilt_jni_libs +$(foreach lib, $(my_prebuilt_jni_libs), \ + $(eval $(call copy-one-file, $(lib), $(my_app_lib_path)/$(notdir $(lib))))) + +$(LOCAL_INSTALLED_MODULE) : | $(addprefix $(my_app_lib_path)/, $(notdir $(my_prebuilt_jni_libs))) +endif # inner my_prebuilt_jni_libs +endif # outer my_prebuilt_jni_libs diff --git a/core/package_internal.mk b/core/package_internal.mk index 528561668..d97ce2a59 100644 --- a/core/package_internal.mk +++ b/core/package_internal.mk @@ -336,8 +336,10 @@ $(LOCAL_BUILT_MODULE): PRIVATE_ADDITIONAL_CERTIFICATES := $(foreach c,\ # Define the rule to build the actual package. $(LOCAL_BUILT_MODULE): $(AAPT) | $(ZIPALIGN) -$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries) -$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES_ABI := $(jni_shared_libraries_abi) +# PRIVATE_JNI_SHARED_LIBRARIES is a list of :. +$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries_with_abis) +# PRIVATE_JNI_SHARED_LIBRARIES_ABI is a list of ABI names. +$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES_ABI := $(jni_shared_libraries_abis) ifneq ($(TARGET_BUILD_APPS),) # Include all resources for unbundled apps. LOCAL_AAPT_INCLUDE_ALL_RESOURCES := true diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk index 4bcd70a25..b5e51891e 100644 --- a/core/prebuilt_internal.mk +++ b/core/prebuilt_internal.mk @@ -165,7 +165,7 @@ include $(BUILD_SYSTEM)/dex_preopt_odex_install.mk # Sign and align non-presigned .apks. $(built_module) : $(my_prebuilt_src_file) | $(ACP) $(ZIPALIGN) $(SIGNAPK_JAR) $(transform-prebuilt-to-target) -ifdef my_extracted_jni_libs +ifdef extracted_jni_libs $(hide) zip -d $@ 'lib/*.so' # strip embedded JNI libraries. endif ifneq ($(LOCAL_CERTIFICATE),PRESIGNED)