Android.mk中APT使用

Android.mk中APT使用

  • 1. 注解工具
  • 2. Android.mk APT支持
    • 2.1 Android.mk配置
    • 2.2 Android build系统patch
  • 3. 编译生成源码

1. 注解工具

注解工具是java代码生成及对象注入的强大工具。注解包括源码可见、字节码可见及运行时可见。目前比较流行的APT技术,也即时编译成字节码时可见。下面以Dagger2及ButterKnife两款注解工具讲解如何在Android.mk中使用这两款工具。
通过gradle编译时,在build.gradle文件中通过如下方式引入

    api 'com.google.dagger:dagger:2.14.1'
    annotationProcessor "com.google.dagger:dagger-compiler:2.14.1"
    api 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

2. Android.mk APT支持

2.1 Android.mk配置

LOCAL_PATH:= $(call my-dir)

#######################################
# Create references to prebuilt libraries.
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_CERTIFICATE := platform

LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
    demo-dagger2-compiler:libs/dagger-compiler-2.14.1.jar \
    demo-dagger2:libs/dagger-2.14.1.jar \
    demo-dagger2-producers:libs/dagger-producers-2.14.1.jar \
    demo-dagger2-spi:libs/dagger-spi-2.14.1.jar \
    demo-butterknife:libs/butterknife-8.8.1.aar \
    demo-butterknife-anno:libs/butterknife-annotations-8.8.1.jar \
    demo-butterknife-compiler:libs/butterknife-compiler-8.8.1.jar \
    demo-support-anno:libs/support-annotations-28.0.0.jar \
    demo-javax-inject:libs/javax.inject-1.jar \
    demo-guava:libs/guava-27.1-jre.jar \
    demo-java-format:libs/google-java-format-1.4-all-deps.jar \
    demo-javax-api:libs/jsr250-api-1.0.jar \
    demo-javapoet:libs/javapoet-1.8.0.jar \
    demo-auto-common:libs/auto-common-0.8.jar

include $(BUILD_MULTI_PREBUILT)


include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_CERTIFICATE := platform

LOCAL_SRC_FILES := $(call all-java-files-under, java)

LOCAL_STATIC_JAVA_LIBRARIES := demo-dagger2 demo-butterknife demo-butterknife-anno \
                demo-support-anno demo-javax-inject

LOCAL_JAVA_LIBRARIES := gsframework

# Libraries needed by the compiler (JACK) to generate code.
PROCESSOR_LIBRARIES_TARGET := \
	demo-dagger2 \
	demo-dagger2-compiler \
	demo-dagger2-producers \
	demo-butterknife \
	demo-butterknife-anno \
	demo-butterknife-compiler \
	demo-javax-inject \
	demo-guava \
	demo-java-format \
	demo-javax-api \
	demo-dagger2-spi \
	demo-javapoet \
	demo-auto-common

# Libraries needed by the compiler (JACK) to generate code.
# Resolve the jar paths.
PROCESSOR_JARS := $(call java-lib-deps, $(PROCESSOR_LIBRARIES_TARGET))
# Necessary for annotation processors to work correctly.
LOCAL_ADDITIONAL_DEPENDENCIES += $(PROCESSOR_JARS)

LOCAL_JAVACFLAGS += -processorpath $(call normalize-path-list,$(PROCESSOR_JARS))

LOCAL_ANNOTATION_PROCESSOR_CLASSES := \
butterknife.compiler.ButterKnifeProcessor dagger.internal.codegen.ComponentProcessor

#LOCAL_JAVACFLAGS += $(foreach class,$(LOCAL_ANNOTATION_PROCESSOR_CLASSES),-processor $(class))

LOCAL_PACKAGE_NAME := InjectDemo

include $(BUILD_PACKAGE)

# Use the folloing include to make our test apk.

#include $(call all-makefiles-under,$(LOCAL_PATH))

可以看出,编译需要引入一堆jar包,包括编译时包和静态jar包,编译包只在编译时依赖,不会打入app中,而静态包则会打入APP中。

2.2 Android build系统patch

下面是针对Android6.0编译系统添加支持APT的patch,请注意 mm 模块编译时,请将JDK版本切换到1.8版本,否则无法生成注解代码。
在这里插入图片描述
Android build系统相关patch如下所示:
Android.mk中APT使用_第1张图片
Android.mk中APT使用_第2张图片
Android.mk中APT使用_第3张图片
Android.mk中APT使用_第4张图片
Android.mk中APT使用_第5张图片

3. 编译生成源码

执行mm命令后,在编译之前会处理注解生成java源码,生成的源码路径:

out/target/common/obj/APPS/InjectDemo_intermediates/anno

在编译前处理注解的主要是通过—processorpath选项完成的,如下是javac选项使用帮助文档:

$ javac
用法: javac  
其中, 可能的选项包括:
  -g                         生成所有调试信息
  -g:none                    不生成任何调试信息
  -g:{lines,vars,source}     只生成某些调试信息
  -nowarn                    不生成任何警告
  -verbose                   输出有关编译器正在执行的操作的消息
  -deprecation               输出使用已过时的 API 的源位置
  -classpath <路径>            指定查找用户类文件和注释处理程序的位置
  -cp <路径>                   指定查找用户类文件和注释处理程序的位置
  -sourcepath <路径>           指定查找输入源文件的位置
  -bootclasspath <路径>        覆盖引导类文件的位置
  -extdirs <目录>              覆盖所安装扩展的位置
  -endorseddirs <目录>         覆盖签名的标准路径的位置
  -proc:{none,only}          控制是否执行注释处理和/或编译。
  -processor [,,...] 要运行的注释处理程序的名称; 绕过默认的搜索进程
  -processorpath <路径>        指定查找注释处理程序的位置
  -parameters                生成元数据以用于方法参数的反射
  -d <目录>                    指定放置生成的类文件的位置
  -s <目录>                    指定放置生成的源文件的位置
  -h <目录>                    指定放置生成的本机标头文件的位置
  -implicit:{none,class}     指定是否为隐式引用文件生成类文件
  -encoding <编码>             指定源文件使用的字符编码
  -source <发行版>              提供与指定发行版的源兼容性
  -target <发行版>              生成特定 VM 版本的类文件
  -profile <配置文件>            请确保使用的 API 在指定的配置文件中可用
  -version                   版本信息
  -help                      输出标准选项的提要
  -A关键字[=值]                  传递给注释处理程序的选项
  -X                         输出非标准选项的提要
  -J<标记>                     直接将 <标记> 传递给运行时系统
  -Werror                    出现警告时终止编译
  @<文件名>                     从文件读取选项和文件名

在Android源码build系统中,javac编译是通过一个函数处理的,代码路径在

/build/core/definitions.mk

# Common definition to invoke javac on the host and target.
#
# Some historical notes:
# - below we write the list of java files to java-source-list to avoid argument
#   list length problems with Cygwin
# - we filter out duplicate java file names because eclipse's compiler
#   doesn't like them.
#
# $(1): javac
# $(2): bootclasspath
define compile-java
$(hide) rm -f $@
$(hide) rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
$(hide) mkdir -p $(dir $@)
$(hide) mkdir -p $(PRIVATE_CLASS_INTERMEDIATES_DIR) $(PRIVATE_ANNO_INTERMEDIATES_DIR)
$(call unzip-jar-files,$(PRIVATE_STATIC_JAVA_LIBRARIES),$(PRIVATE_CLASS_INTERMEDIATES_DIR))
$(call dump-words-to-file,$(PRIVATE_JAVA_SOURCES),$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list)
$(hide) if [ -d "$(PRIVATE_SOURCE_INTERMEDIATES_DIR)" ]; then \
          find $(PRIVATE_SOURCE_INTERMEDIATES_DIR) -name '*.java' >> $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list; \
fi
$(hide) tr ' ' '\n' < $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list \
    | sort -u > $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(hide) if [ -s $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq ] ; then \
    $(1) -encoding UTF-8 \
    $(strip $(PRIVATE_JAVAC_DEBUG_FLAGS)) \
    $(if $(findstring true,$(PRIVATE_WARNINGS_ENABLE)),$(xlint_unchecked),) \
    $(2) \
    $(addprefix -classpath ,$(strip \
        $(call normalize-path-list,$(PRIVATE_ALL_JAVA_LIBRARIES)))) \
    $(if $(findstring true,$(PRIVATE_WARNINGS_ENABLE)),$(xlint_unchecked),) \
    -extdirs "" -d $(PRIVATE_CLASS_INTERMEDIATES_DIR) -s $(PRIVATE_ANNO_INTERMEDIATES_DIR) \
    $(PRIVATE_JAVACFLAGS) \
    \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq \
    || ( rm -rf $(PRIVATE_CLASS_INTERMEDIATES_DIR) ; exit 41 ) \
fi
$(if $(PRIVATE_JAVA_LAYERS_FILE), $(hide) build/tools/java-layers.py \
    $(PRIVATE_JAVA_LAYERS_FILE) \@$(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq,)
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list
#$(hide) rm -f $(PRIVATE_CLASS_INTERMEDIATES_DIR)/java-source-list-uniq
$(if $(PRIVATE_JAR_EXCLUDE_FILES), $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) \
    -name $(word 1, $(PRIVATE_JAR_EXCLUDE_FILES)) \
    $(addprefix -o -name , $(wordlist 2, 999, $(PRIVATE_JAR_EXCLUDE_FILES))) \
    | xargs rm -rf)
$(if $(PRIVATE_JAR_PACKAGES), \
    $(hide) find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -mindepth 1 -type f \
        $(foreach pkg, $(PRIVATE_JAR_PACKAGES), \
            -not -path $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))/\*) -delete ; \
        find $(PRIVATE_CLASS_INTERMEDIATES_DIR) -empty -delete)
$(if $(PRIVATE_JAR_EXCLUDE_PACKAGES), $(hide) rm -rf \
    $(foreach pkg, $(PRIVATE_JAR_EXCLUDE_PACKAGES), \
        $(PRIVATE_CLASS_INTERMEDIATES_DIR)/$(subst .,/,$(pkg))))
$(if $(PRIVATE_RMTYPEDEFS), $(hide) $(RMTYPEDEFS) -v $(PRIVATE_CLASS_INTERMEDIATES_DIR))
$(if $(PRIVATE_JAR_MANIFEST), \
    $(hide) sed -e 's/%BUILD_NUMBER%/$(BUILD_NUMBER)/' \
            $(PRIVATE_JAR_MANIFEST) > $(dir $@)/manifest.mf && \
        jar -cfm $@ $(dir $@)/manifest.mf \
            -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) ., \
    $(hide) jar -cf $@ -C $(PRIVATE_CLASS_INTERMEDIATES_DIR) .)
$(if $(PRIVATE_EXTRA_JAR_ARGS),$(call add-java-resources-to,$@))
endef

define transform-java-to-classes.jar
@echo "--------------------start compile-java-------------------------"
@echo "class path = $(PRIVATE_CLASS_INTERMEDIATES_DIR), anno src path = $(PRIVATE_ANNO_INTERMEDIATES_DIR)"
@echo "private java libs = $(PRIVATE_ALL_JAVA_LIBRARIES)"
@echo "java layer files = $(PRIVATE_JAVA_LAYERS_FILE)"
@echo "private jar pkg = $(PRIVATE_JAR_MANIFEST)"

@echo -e ${CL_GRN}"target Java:"${CL_RST}" $(PRIVATE_MODULE) ($(PRIVATE_CLASS_INTERMEDIATES_DIR))"
$(call compile-java,$(TARGET_JAVAC),$(PRIVATE_BOOTCLASSPATH))
endef

有兴趣的话,可以通过echo打印调试。

你可能感兴趣的:(android系统分析)