您的位置:首页 > 移动开发 > Android开发

基于 Android NDK 的学习之旅目录

2012-01-05 17:09 405 查看

基于 Android NDK 的学习之旅目录

来源:Linux社区  作者:Linux
Android是一个专为移动设备设计的软件平台,它包括一个操作系统、中间件和一些关键性的平台应用。目前发布的Android SDK提供了使用Java语言开发Android平台应用的必要工具和API。

基于
Android NDK 的学习之旅目录


基于 Android NDK 的学习之旅-----序言http://www.linuxidc.com/Linux/2011-08/40814.htm

基于 Android NDK 的学习之旅-----环境搭建http://www.linuxidc.com/Linux/2011-08/40812.htm

基于 Android NDK 的学习之旅-----Android.mk 介绍http://www.linuxidc.com/Linux/2011-08/40811.htm

基于 Android NDK 的学习之旅-----HelloWorld (附源码)http://www.linuxidc.com/Linux/2011-08/40816.htm

基于 Android NDK 的学习之旅-----JNI LOG 打印(附源码)http://www.linuxidc.com/Linux/2011-08/40817.htm

基于 Android NDK 的学习之旅-----JNI 数据类型http://www.linuxidc.com/Linux/2011-08/40815.htm

基于 Android NDK 的学习之旅-----Java 调用 C(附源码)http://www.linuxidc.com/Linux/2011-08/40810.htm

基于 Android NDK 的学习之旅----- C调用Java(附源码) http://www.linuxidc.com/Linux/2011-08/41173.htm

基于 Android NDK 的学习之旅----- Java 方法映射到C中的签名(附源码)http://www.linuxidc.com/Linux/2011-08/41174.htm

基于 Android NDK 的学习之旅-----数据传输一(基本数据类型和数组传输)(附源码)http://www.linuxidc.com/Linux/2011-08/41175.htm

基于 Android NDK 的学习之旅-----数据传输二(引用数据类型)(附源码)http://www.linuxidc.com/Linux/2011-08/41176.htm
基于 Android NDK 的学习之旅-----资源释放http://www.linuxidc.com/Linux/2011-08/41278.htm

以下是一些GNU
Make的宏‘函数’,必须通过这样的形式调用:'$(call<function>)'。

函数返回文本信息。

        

my-dir

   返回放置当前Android.mk的文件夹相对于NDK生成系统根目录的路径。可用来

   在Android.mk的开始处定义LOCAL_PATH的值:

    

      LOCAL_PATH := $(callmy-dir)      
        

all-subdir-makefiles

     返回‘my-dir’子目录下的所有Android.mk。比如,代码的结构如下:

    sources/foo/Android.mk

       sources/foo/lib1/Android.mk

       sources/foo/lib2/Android.mk

        

   如果sources/foo/Android.mk里有这样一行:

        

       include $(call all-subdir-makefiles)

    

   那么,它将会自动地includesources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk

    

   这个函数能将深层嵌套的代码文件夹提供给生成系统。注意,默认情况下,NDK仅在

   source/*/Android.mk里寻找文件。
    

this-makefile

    返回当前Makefile(译者注:指的应该是GNU Makefile)的路径(即,这个函数是在哪里调用的)

parent-makefile

    返回在列入树(inclusion tree)中的父makefile的路径。

   即,包含当前makefile的那个makefile的路径。  

grand-parent-makefile

   猜猜看...(译者注:原文为Guess what...)

组件描述相关的变量:

- - - - - - - - - -

以下的变量是用来向生成系统描述你的组件的。你应该在'include $(CLEAR_VARS)'

和'include$(BUILD_XXXXX)'之间定义其中的一些变量。正如在前面所说的,$(CLEAR_VARS)

是一个将会取消所有这些变量的脚本,除非在对变量的描述时有显式的说明。
    

LOCAL_PATH

  这个变量用来设置当前文件的路径。你必须在Android.mk的开始处定义它,比如:

     

    LOCAL_PATH:= $(call my-dir)

    

  这个变量不会被$(CLEAR_VARS)消除,所以每个Android.mk仅需一个定义(以防你在

   同一个文件里定义几个组件)。

  

    

LOCAL_MODULE

  定义组件的名称。对于所有的组件名,它必须是唯一,且不能包含空格。

   在include$(BUILD_XXX)之前你必须定义它。

  

  这个组件名决定生成的文件(译者注:即库名)。比如,lib<foo>,即这个组件的名称

  为<foo>。但是在你的NDK生成文件(不管是Android.mk还是Application.mk)中

  你只能通过‘正常’的名称(如,<foo>)来引用其它的组件。

  

          

LOCAL_SRC_FILES

  用它来定义所有用来生成组件的源文件。仅须列出传给编译器的文件,因为

   生成系统会自动地计算它们的相互依赖关系。

  

  注意,所有文件名都是相对于LOCAL_PATH的,你可以用到路径组件(path component)

   如:

    LOCAL_SRC_FILES := foo.c \ (译者注:‘\’为连接符)

                        toto/bar.c
        

LOCAL_CPP_EXTENSION

  这是一个可选的变量,可用它来指明C++源文件的扩展名。默认情况下是'.cpp',

   但你可以改变它。比如:

    

    LOCAL_CPP_EXTENSION := .cxx
      

    

LOCAL_C_INCLUDES

  一个相对于相对于NDK*根*目录可选的路径名单,当编译所有的源文件(C,C++和汇编)时,

  它将被添加进include搜索路径。例如:

   

     LOCAL_C_INCLUDES := sources/foo

  

    或者甚至:

     

     LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

LOCAL_CFLAGS

   一个可选的编译标记集,在生成C与C++源文件时,将解析它。

    

   对指定额外的宏定义或编译选项很有用。

               

   重要:不要试图改变你Android.mk里的optimization/debuggin level,通过

         在你的Android.mk里指定合适的信息,它将被自动处理,并使NDK生成

         调试时可用的有用的数据文件。

          

   注意:在android-ndk-1.5_r1,相应的标记(flags)只适用于C源文件,对C++

      源文件并不适用。为了适用于完整的Android生成系统的特性,已作了修

      正。(现在,你可以使用LOCAL_CPPFLAGS为C++文件指定标记)
LOCAL_CXXFLAGS

   LOCAL_CPPFLAGS的别名。注意,不建议使用这个变量,因为在未来的NDK版本中,

    它可能会消失。
LOCAL_CPPFLAGS

    一个可选的编译标记集,*仅*在生成C++源文件时解析它。在编译器的命令行里

    它将在LOCAL_CFLAGS之后出现。
   注意:在android-ndk-1.5_r1,相应的标记(flags)适用于C与C++源文件。

      为了适用于完整的Android生成系统的特性,已作了修

      正。(现在,你可以使用LOCAL_CFLAGS为C和C++源文件指定标记)
LOCAL_STATIC_LIBRARIES

    一份staticlibraries组件的名单(以BUILD_STATIC_LIBRARY的方式生成),它将被

   连接到欲生成的组件上。这仅在生成shared library组件时有意义。(译者注:将指定

    的一个或多个staticlibrary module转化为一个shared library module)
LOCAL_SHARED_LIBRARIES

   一份该组件在运行期依赖于它的shared libraries *组件*。在连接时间(link time)里

   与及为该生成的文件嵌入相应的信息都要用到它。
   注意,它并不将这份组件名单添加入生成图表(build graph)。即,在你的Android.mk

   里,你仍应该将它们加入到你的应用程序要求的组件。
LOCAL_LDLIBS

   一份能在生成你的组件时用到的额外的连接器标记(linkerflags)的名单。在传递

   有“-l”前缀的特殊系统库的名称时很有用。比如,下面的语句会告诉连接器在装载 

    时间(loadtime)里生成连接到/system/lib/libz.so的组件。
     LOCAL_LDLIBS := -lz
   若想知道在这个NDK版本可以连接哪些暴露的系统库(exposed system libraries),

   请参见docs/STABLE-APIS。
LOCAL_ALLOW_UNDEFINED_SYMBOLS

   缺省值情况下,当尝试生成一个shared library遇到没有定义的引用时,会导致“undefined 

   symbol”error。这对在你的源代码里捕捉bugs有很大的帮助。

    

   但是,因为一些原因你须要disable这个检查,将这个变量设置为'true’。注意,相应

    的sharedlibrary可能在运行期装载失败。
LOCAL_ARM_MODE

   缺省值情况下,ARM目标二进制将会以‘thumb’模式生成,这时每个指令都是16-bit宽的。

   如果你想强迫组件的object文件以‘arm’(32位的指令)的模式生成,你可以将这个变量

   定义为'arm'。即:
     LOCAL_ARM_MODE := arm
   注意,你也可以通过将‘.arm’后缀添加到源文件名字的后面指示生成系统将指定的

   源文件以arm模式生成。例如:

   
      LOCAL_SRC_FILES := foo.c bar.c.arm
   告诉生成系统总是以arm模式编译‘bar.c’,但根据LOCAL_ARM_MODE的值生成foo.c
   注意:在你的Application.mk里将APP_OPTIM设置为'debug',这也会强迫生成ARM二进制

   代码。这是因为工具链的调度器有bugs,它对thumb码的处理不是很好。
 
 
////////////////////////////////////////////////////////////////////////
怎样添加一个模块

LOCAL_PATH:= $(call my-dir)

#编译静态库

include $(CLEAR_VARS)

LOCAL_MODULE = libhellos

LOCAL_CFLAGS = $(L_CFLAGS)

LOCAL_SRC_FILES = hellos.c

LOCAL_C_INCLUDES = $(INCLUDES)

LOCAL_SHARED_LIBRARIES := libcutils

LOCAL_COPY_HEADERS_TO := libhellos

LOCAL_COPY_HEADERS := hellos.h

include $(BUILD_STATIC_LIBRARY)
#编译动态库

include $(CLEAR_VARS)

LOCAL_MODULE = libhellod

LOCAL_CFLAGS = $(L_CFLAGS)

LOCAL_SRC_FILES = hellod.c

LOCAL_C_INCLUDES = $(INCLUDES)

LOCAL_SHARED_LIBRARIES := libcutils

LOCAL_COPY_HEADERS_TO := libhellod

LOCAL_COPY_HEADERS := hellod.h

include $(BUILD_SHARED_LIBRARY)
BUILD_TEST=true

ifeq ($(BUILD_TEST),true)

#使用静态库

include $(CLEAR_VARS)

LOCAL_MODULE := hellos

LOCAL_STATIC_LIBRARIES := libhellos

LOCAL_SHARED_LIBRARIES :=

LOCAL_LDLIBS += -ldl

LOCAL_CFLAGS := $(L_CFLAGS)

LOCAL_SRC_FILES := mains.c

LOCAL_C_INCLUDES := $(INCLUDES)

include $(BUILD_EXECUTABLE)
#使用动态库

include $(CLEAR_VARS)

LOCAL_MODULE := hellod

LOCAL_MODULE_TAGS := debug

LOCAL_SHARED_LIBRARIES := libc libcutils libhellod

LOCAL_LDLIBS += -ldl

LOCAL_CFLAGS := $(L_CFLAGS)

LOCAL_SRC_FILES := maind.c

LOCAL_C_INCLUDES := $(INCLUDES)

include $(BUILD_EXECUTABLE)

endif # ifeq ($(WPA_BUILD_SUPPLICANT),true)
########################

#local_target_dir := $(TARGET_OUT)/etc/wifi

#include $(CLEAR_VARS)

#LOCAL_MODULE := wpa_supplicant.conf

#LOCAL_MODULE_TAGS := user

#LOCAL_MODULE_CLASS := ETC

#LOCAL_MODULE_PATH := $(local_target_dir)

#LOCAL_SRC_FILES := $(LOCAL_MODULE)

#include $(BUILD_PREBUILT)

########################

系统变量解析

LOCAL_MODULE - 编译的目标对象

LOCAL_SRC_FILES - 编译的源文件

LOCAL_C_INCLUDES - 需要包含的头文件目录

LOCAL_SHARED_LIBRARIES - 链接时需要的外部库

LOCAL_PRELINK_MODULE - 是否需要prelink处理

BUILD_SHARED_LIBRARY - 指明要编译成动态库

LOCAL_PATH - 编译时的目录

$(call 目录,目录….) 目录引入操作符

如该目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径
include $(CLEAR_VARS) -清除之前的一些系统变量

CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

在 build/core/config.mk 定义 CLEAR_VARS:=$(BUILD_SYSTEM)/clear_vars.mk

通过include 包含自定义的.mk文件(即是自定义编译规则)或是引用系统其他的.mk文件(系统定义的编译规则)。
LOCAL_SRC_FILES - 编译的源文件

可以是.c, .cpp, .java, .S(汇编文件)或是.aidl等格式

不同的文件用空格隔开。如果编译目录子目录,采用相对路径,如子目录/文件名。也可以通过$(call目录),指明编译某目录

下所有.c/.cpp/.java/.S/ .aidl文件.追加文件 LOCAL_SRC_FILES += 文件
LOCAL_C_INCLUDES - 需要包含的头文件目录

可以是系统定义路径,也可以是相对路径. 如该编译目录下有个include目录,写法是include/*.h
LOCAL_SHARED_LIBRARIES - 链接时需要的外部共享库

LOCAL_STATIC_LIBRA RIES - 链接时需要的外部外部静态

LOCAL_JAVA_LIBRARIES 加入jar包
LOCAL_MODULE - 编译的目标对象

module 是指系统的 native code,通常针对c,c++代码

./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh

./system/core/libcutils/Android.mk:71:LOCAL_MODULE :=libcutils

./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs

./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE :=mkbootimg

./system/core/toolbox/Android.mk:61:LOCAL_MODULE:=toolbox

./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat

./system/core/adb/Android.mk:65:LOCAL_MODULE := adb

./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd

./system/core/init/Android.mk:20:LOCAL_MODULE:= init

./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold

./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd
LOCAL_PACKAGE_NAME 

Java 应用程序的名字用该变量定义

./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME :=Music

./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME :=Browser

./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME :=Settings

./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME :=Stk

./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME :=Contacts

./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME :=Mms

./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME :=Camera

./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME :=Phone

./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME :=VoiceDialer

BUILD_SHARED_LIBRARY - 指明要编译成动态库。

编译的目标,用include 操作符

UILD_STATIC_LIBRARY来指明要编译成静态库。

如果是java文件的话,会用到系统的编译脚本host_java_library.mk,用BUILD_PACKAGE来指明。三个编译

-------------------

include $(BUILD_STATIC_LIBRARY)

BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

-------------------

include $(BUILD_SHARED_LIBRARY)

./build/core/config.mk:50:BUILD_SHARED_LIBRARY:=$(BUILD_SYSTEM)/shared_library.mk

-------------------

include $(BUILD_HOST_SHARED_LIBRARY)

BUILD_HOST_SHARED_LIBRARY:=$(BUILD_SYSTEM)/host_shared_library.mk

-------------------

include $(BUILD_EXECUTABLE)

build/core/config.mk:51:BUILD_EXECUTABLE:=$(BUILD_SYSTEM)/executable.mk

-------------------

include $(BUILD_HOST_EXECUTABLE)

./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:=$(BUILD_SYSTEM)/host_executable.mk

-------------------

BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk

-------------------

BUILD_JAVA_LIBRARY

./build/core/config.mk:58:BUILD_JAVA_LIBRARY:=$(BUILD_SYSTEM)/java_library.mk

------------------

BUILD_STATIC_JAVA_LIBRARY 编译静态JAVA库

./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:=$(BUILD_SYSTEM)/static_java_library.mk

------------------

BUILD_HOST_JAVA_LIBRARY 编译本机用的JAVA库

./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk

------------------
BUILD_HOST_STATIC_LIBRARY:=$(BUILD_SYSTEM)/host_static_library.mk

BUILD_HOST_SHARED_LIBRARY:=$(BUILD_SYSTEM)/host_shared_library.mk

BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk

BUILD_RAW_STATIC_LIBRARY :=$(BUILD_SYSTEM)/raw_static_library.mk

BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk

BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk

BUILD_HOST_EXECUTABLE:=$(BUILD_SYSTEM)/host_executable.mk

BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk

BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk

BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk

BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk

BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk

BUILD_STATIC_JAVA_LIBRARY:=$(BUILD_SYSTEM)/static_java_library.mk

BUILD_HOST_JAVA_LIBRARY:=$(BUILD_SYSTEM)/host_java_library.mk

BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk

BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk

BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk
============

LOCAL_PRELINK_MODULE

Prelink利用事先链接代替运行时链接的方法来加速共享库的加载,它不仅可以加快起动速度,还可以减少部分内存开销,

是各种Linux架构上用于减少程序加载时间、缩短系统启动时间和加快应用程序启动的很受欢迎的一个工具。程序运行时的

动态链接尤其是重定位(relocation)的开销对于大型系统来说是很大的。

动态链接和加载的过程开销很大,并且在大多数的系统上, 函数库并不会常常被更动, 每次程序被执行时所进行的链接

动作都是完全相同的,对于嵌入式系统来说尤其如此。因此,这一过程可以改在运行时之前就可以预先处理好,即花一些时间

利用Prelink工具对动态共享库和可执行文件进行处理,修改这些二进制文件并加入相应的重定位等信息,节约了本来在程序

启动时的比较耗时的查询函数地址等工作,这样可以减少程序启动的时间,同时也减少了内存的耗用。 

Prelink的这种做法当然也有代价:每次更新动态共享库时,相关的可执行文件都需要重新执行一遍Prelink才能保

证有效,因为新的共享库中的符号信息、地址等很可能与原来的已经不同了,这就是为什么 androidframework代码一改动,

这时候就会导致相关的应用程序重新被编译。

这种代价对于嵌入式系统的开发者来说可能稍微带来一些复杂度,不过好在对用户来说几乎是可以忽略的。

--------------------

变量设置为false那么将不做prelink操作

LOCAL_PRELINK_MODULE := false

默认是需要prlink的,同时需要在 build/core/prelink-linux-arm.map 中加入

libhellod.so 0x96000000

这个map文件好像是制定动态库的地址的,在前面注释上面有一些地址范围的信息,注意库与库之间的间隔数,

如果指定不好的话编译的时候会提示说地址空间冲突的问题。另外,注意排序,这里要把数大的放到前面去,

按照大小降序排序。

解析 LOCAL_PRELINK_MODULE 变量

build/core/dynamic_binary.mk:94:ifeq($(LOCAL_PRELINK_MODULE),true)

ifeq ($(LOCAL_PRELINK_MODULE),true)

$(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP)$(APRIORI)

$(transform-to-prelinked)

transform-to-prelinked定义:

./build/core/definitions.mk:1002:definetransform-to-prelinked

define transform-to-prelinked

@mkdir -p $(dir $@)

@echo "target Prelink: $(PRIVATE_MODULE) ($@)"

$(hide) $(APRIORI) \

--prelinkmap $(TARGET_PRELINKER_MAP) \

--locals-only \

--quiet \

$< \

--output $@

endef

./build/core/config.mk:183:APRIORI :=$(HOST_OUT_EXECUTABLES)/apriori$(HOST_EXECUTABLE_SUFFIX)

prelink工具不是常用的prelink而是apriori,其源代码位于”<your_android>/build/tools/apriori”

参考文档:

动态库优化——Prelink(预连接)技术
http://www.eefocus.com/article/09-04/71629s.html

===============

LOCAL_ARM_MODE := arm

目前Android大部分都是基于Arm处理器的,Arm指令用两种模式Thumb(每条指令两个字节)和arm指令(每条指令四个字节)
LOCAL_CFLAGS += -O3 -fstrict-aliasing-fprefetch-loop-arrays

通过设定编译器操作,优化级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高

LOCAL_CFLAGS += -W -Wall

LOCAL_CFLAGS += -fPIC -DPIC

LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall-Wno-unused-parameter

LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE-DSH_HISTORY

LOCAL_CFLAGS += -DUSEOVERLAY2

根据条件选择相应的编译参数

ifeq ($(TARGET_ARCH),arm)

LOCAL_CFLAGS += -DANDROID_GADGET=1

LOCAL_CFLAGS := $(PV_CFLAGS)

endif

ifeq ($(TARGET_BUILD_TYPE),release)

LOCAL_CFLAGS += -O2

endif
LOCAL_LDLIBS := -lpthread

LOCAL_LDLIBS += -ldl
ifdef USE_MARVELL_MVED

LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_mpeg4aspdecmved_wmmx2lnxlib_il_h264decmved_wmmx2lnx

LOCAL_SHARED_LIBRARIES += libMrvlMVED

else

LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnxlib_il_mpeg4aspdec_wmmx2lnx

endif
============================================
 

添加Android.mk

完成了上一步,可以知道,Android.mk在编译中起着至关重要的作用,这其实就是Android编译环境中的makefile。为了完成我们的工作,需要在源代码中添加Android.mk。添加自己的Android.mk可以仿照SimpleJNI中的Android.mk,稍微修改即可。我们首先看看SimpleJNI目录下的两个Android.mk的内容:
 目录下的Android.mk 


TOP_LOCAL_PATH:= $(call my-dir)

# Build activity

LOCAL_PATH:= $(TOP_LOCAL_PATH)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := samples

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := SimpleJNI

LOCAL_JNI_SHARED_LIBRARIES := libsimplejni

LOCAL_PROGUARD_ENABLED := disabled

include $(BUILD_PACKAGE)

#============================================================

# Also build all of the sub-targets under this one: the sharedlibrary.

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

     根目录下的Android.mk决定了整个工程编译的配置,其中,
     LOCAL_PATH 定义了当前的目录

     LOCAL_MUDULE_TAGS定义了当前模块的类型,编译器在编译时会根据类型的不同有些差别,有些tags的module甚至不会被编译至系统中。LOCAL_MUDULE_TAGS主要有如下几种:user debug eng tests optional samplesshell_ashshell_mksh。optional表示在所有版本的编译条件下都被编译至image中,剩下的表示在该版本中才会被编译只image中,如user表示在user版本下才会被编译至image中。

对于包含LOCAL_PACKAGE_NAME的mk文件,该项默认为optinal,具体可以参看build/core/package.mk。SimpleJNI中定义为samples的具体作用我也不太清楚,为了保险起见,我自己的apk一般定义为optional。

     LOCAL_SRC_FILES 定义了编译apk所需要的java代码的目录

     LOCAL_PACKAGE_NAME 这里需要改成自己的package的名字

     LOCAL_JNI_SHARED_LIBRARIES定义了要包含的so库文件的名字,如果你的程序没有采用JNI,这行不需要。

     LOCAL_PROGUARD_ENABLED定义了Java开发中的ProGuard压缩方法,主要用来分析压缩程序的,在我自己的应用中我没有加这行。

     include $(BUILD_PACKAGE) 这行是build的关键,表示当前java代码build成apk

     include $(call all-makefiles-under,$(LOCAL_PATH))表示需要build该目录下的子目录的文件,这样编译系统就会在当前目录下的子目录寻找Android.mk来编译so等其它程序。
     根据上述所写,创建我自己的Android.mk如下:

TOP_LOCAL_PATH:= $(call my-dir)

# Build activity

LOCAL_PATH:= $(TOP_LOCAL_PATH)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := TestJniApp

LOCAL_JNI_SHARED_LIBRARIES := libtestjniapp

include $(BUILD_PACKAGE)

#============================================================

# Also build all of the sub-targets under this one: the sharedlibrary.

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

     看起来很简单吧,基本不需要改动即可。
Jni目录下的Android.mk 

     由于我们的TestJniApp是用JNI完成的,包含C源代码,因此也需要一个jni目录下的Android.mk。同样首先看看SimpleJNI中jni目录下的Android.mk的内容:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := samples

# This is the target being built.

LOCAL_MODULE:= libsimplejni

# All of the source files that we will compile.

LOCAL_SRC_FILES:= /

  native.cpp

# All of the shared libraries we link against.

LOCAL_SHARED_LIBRARIES := /

       libutils

# No static libraries.

LOCAL_STATIC_LIBRARIES :=

# Also need the JNI headers.

LOCAL_C_INCLUDES += /

       $(JNI_H_INCLUDE)

# No special compiler flags.

LOCAL_CFLAGS +=

# Don't prelink this library.  For more efficientcode, you may want

# to add this library to the prelink map and set this to true.However,

# it's difficult to do this for applications that are not suppliedas

# part of a system image.

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

     LOCAL_MODULE 当前模块的名字,即编译后的so文件的名字

     LOCAL_SRC_FILES 所要编译的文件

     LOCAL_SHARED_LIBRARIES, LOCAL_STATIC_LIBRARIES该模块要链接的动态库和静态库。

     LOCAL_C_INCLUDES 要包含的头文件

     LOCAL_CFLAGS  C语言编译选项

     LOCAL_PRELINK_MODULE定义是否使用prelink工具,它用事先链接代替运行时链接的方法来加速共享库的加载,不仅可以加快起动速度,还可以减少部分内存开销。

     经过修改后,我自己的TestJniApp中jni目录下的Android.mk如下:
 

LOCAL_PATH := $(callmy-dir)
 
include$(CLEAR_VARS)
 
LOCAL_MODULE    :=libtestjniapp
LOCAL_SRC_FILES :=com_test_app_Jni.c
LOCAL_C_INCLUDES +=$(JNI_H_INCLUDE)
 
LOCAL_PRELINK_MODULE :=false
 
include$(BUILD_SHARED_LIBRARY)
 
 

  这里有一点需要注意,如果要将so文件编译入image,必须要修改LOCAL_MODULE_TAGS,将原有的值samples修改为user,或者可以直接删掉 。删掉是因为对于包含LOCAL_MODULE的mk文件,如果没有指定LOCAL_MODULE_TAGS,该项默认为user,而只有定义为user的情况下,才会将so文件编译入image,具体定义可以参看build/core/base_rule.mk。

4.   修改/bulid/target/product/generic.mk 把工程编译到系统中

     至此,还有最后一部工作。为了将工程编译进入image,还需要在/bulid/target/product/generic.mk文件中将packagename添加进去 

PRODUCT_PACKAGES := /

   AccountAndSyncSettings /

    CarHome/

    DeskClock/

    ……

    SyncProvider/

    TestJniApp

       完成上面这些步骤后,在 sourcetree 根目录下编译 image 就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息