Android.mk的用法

(1)Android.mk是什么?


Android.mk是Android提供的一种makefile文件。Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西。


你可以在每一个Android.mk file中定义一个或多个模块。每个模块属下列类型之一:

  1)APK程序,一般的Android程序,编译打包生成apk文件
  2)JAVA库,java类库,编译打包生成jar文件
  3)  C\C++应用程序,可执行的C\C++应用程序
  4)C\C++静态库,编译生成C\C++静态库,并打包成.a文件
  5)C\C++共享库, 编译生成共享库(动态链接库),并打包成.so, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。


使用它来编译程序时,不管是动态库、可执行的二进制文件,还是Jar库、APK包,只要沿着一个简单的思路来做三大步就可以了:清除旧变量,设置新变量,调用编译函数。


(2)举例子


(一)BUILD_SHARED_LIBRARY——动态库

chris/superuser/su.c 
chris/superuser/Android.mk
相应的Android.mk文件会像下面这样:

  1. LOCAL_PATH := $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_MODULE  
  4. := su  
  5. LOCAL_SRC_FILES := su.c  
  6. include $(BUILD_SHARED_LIBRARY)


1, LOCAL_PATH := $(call my-dir): 一个Android.mk file首先必须定义好LOCAL_PATH变量.它用于在开发树中查找源文件。在这个例子中,宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。


2,include $( CLEAR_VARS),CLEAR_VARS由编译系统提供((可以在 android 安装目录下的/build/core/config.mk 文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...) 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的


3,LOCAL_MODULE := su,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件


4,LOCAL_SRC_FILES := su.c,LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。


5,LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo


6,LOCAL_STATIC_LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。


7,LOCAL_SHARED_LIBRARIES:  表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息


8,include $(call all-subdir-makefiles):返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。


(二)BUILD_EXECUTABLE——二进制文件

LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= su.c
     LOCAL_MODULE:= su
     #LOCAL_C_INCLUDES :=
     #LOCAL_STATIC_LIBRARIES :=
     #LOCAL_SHARED_LIBRARIES :=
     include $(BUILD_EXECUTABLE)


(三) BUILD_STATIC_LIBRARY——静态库

LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= /
               helloworld.c
     LOCAL_MODULE:= libtest_static
     #LOCAL_C_INCLUDES :=
     #LOCAL_STATIC_LIBRARIES :=
     #LOCAL_SHARED_LIBRARIES :=
     include $(BUILD_STATIC_LIBRARY)


BUILD_STATIC_LIBRARY表示编译一个静态库.a文件。静态库不会复制到的APK包中,但是能够用于编译共享库



补充:include $(BUILD_PACKAGE)则是编译出一个apk,include $(BUILD_STATIC_JAVA_LIBRARY)则是编译出jar包


(a)以上三者的生成结果分别在

out/target/product/generic/obj/EXECUTABLE
out/target/product/generic/obj/STATIC_LIBRARY
out/target/product/generic/obj/SHARED_LIBRARY


(b)每个模块的目标文件夹分别为:
可执行程序:XXX_intermediates
静态库:      XXX_static_intermediates
动态库:      XXX_shared_intermediates


(c)在Android.mk文件中,还可以指定最后的目标安装路径,用LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH来指定。不同的文件系统路径用以下的宏进行选择:
TARGET_ROOT_OUT:表示根文件系统out/target/product/xxxxx/root。
TARGET_OUT:表示system文件系统out/target/product/xxxx/system。
TARGET_OUT_DATA:表示data文件系统out/target/product/xxxx/data。

TARGET_OUT_SHARED_LIBRARIES:表示out/target/product/xxxx/system/lib

TARGET_OUT_APPS:表示out/target/product/xxxx/system/app

ANDROID_PRODUCT_OUT:out/target/product/xxxx/

TARGET_OUT_JAVA_LIBRARIES:out/target/product/xxxx/system/framework


例如:LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/src 


(3)相关的编译指令

android源码目录下的build/envsetup.sh文件,描述编译的命令
- m:       Makes from the top of the tree. 
- mm:      Builds all of the modules in the current directory. 
- mmm:     Builds all of the modules in the supplied directories. 

所以要想使用这些命令,首先需要在android源码根目录执行build/envsetup.sh 脚本设置环境。


m:编译所有的模块 
mm:编译当前目录下的模块,当前目录下要有Android.mk文件 
mmm:编译指定路径下的模块,指定路径下要有Android.mk文件 

下面举个例子说明,假设我要编译android下的\hardware\libhardware_legacy\power模块,当前目录为源码根目录,方法如下: 
1、. build/envsetup.sh 
2、mmm hardware/libhardware_legacy/power/ 
或者 : 
1、. build/envsetup.sh 
2、cd hardware/libhardware_legacy/power/ 
3、mm 




实际开发中,并不需要每次都编译所有源代码,只需要编译自己修改的模块即可。Android的编译系统提供了强大的机制支持单独模块的编译,而且十分简单。Android提供三种方式用于编译单独模块:

make 模块名

mm (来自于envsetup.sh脚本中注册的函数)

mmm (来自于envsetup.sh脚本中注册的函数)

1.make 模块名

这种方法适合第一次编译,会把依赖模块一并编译。它需要在全部源代码中找到编译模块的Android.mk文件,并检查依赖模块是否有修改,因此编译时间较长。使用这种方法,我们只需要搜索源码目录下的Android.mk文件,找到模块名,然后指定给make即可。

对于应用层程序,需要查看Android.mk文件的LOCAL_PACKAGE_NAME变量

例如,要编译Phone应用程序的源码,先查看Phone的Android.mk文件

  1. ……(省略部分内容)  
  2. LOCAL_PATH:= $(call my-dir)  
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE :com.android.phone.common  
  5. ……(省略部分内容)  
  6. LOCAL_PACKAGE_NAME :Phone 
  7. ……(省略部分内容) 
得到编译参数后,在终端中运行如下命令便可单独编译Phone模块及其依赖模块:allong@android:~/android/.../***(Android.mk所在目录下编译)$ make Phone


2.mmm命令

                            

该命令是envsetup.sh中注册的函数,用于在源码根目录编译指定模块,参数为模块的相对路径。只能在第一次编译后使用。比如要编译Phone部分源码,需要在终端中执行以下命令:

 
  
  1. allong@android:~/android/jellybean$mmm packages/apps/phone

3.mm命令

该命令也是envsetup.sh中注册的函数,用于在模块根目录编译这个模块。只能在第一次编译后使用。例如要编译Phone部分源码,需要在终端中执行以下命令

注意 mmm和mm命令必须在执行“.build/envsetup.sh”之后才能使用,并且只编译发生变化的文件。
(4)Android 手工编译C程序的整个过程
1,先将你要编译的C代码模块 放入已经编译好的android源码目录下 Android.mk的用法_第1张图片
Android.mk的用法_第2张图片
有些头文件是android源码目录的,可能要在Android.mk中包含进来
Android.mk的用法_第3张图片 Android.mk的用法_第4张图片
2,初始化环境(每次编译模块前都要进行初始化环境!在这里耽误了一天时间才知道)
Android.mk的用法_第5张图片
Android.mk的用法_第6张图片
初始化之后进入你要编译的C模块目录,进行编译,编译成功会有提示
Android.mk的用法_第7张图片
Android.mk的用法_第8张图片
3,因为我编译的目标文件为include $(BUILD_EXECUTABLE),编译成功后默认路径为out/target/product/shamu/obj/EXECUTABLES/su(这里是相应的模块名称)_intermediates/su(相应的模块名称),在路径下可找到你的编译结果
Android.mk的用法_第9张图片

你可能感兴趣的:(android)