原文网址:http://hualang.iteye.com/blog/1141315

Android build system就是编译系统的意思

在我们需要向自己编译的源代码中增加模块的时候,需要一些规则,当然这个规则都是类似的。

Android.mk文件解析

让我们来看一个 Android.mk 文件的样子

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

①     LOCAL_PATH :=$(call my-dir)

固定写法, LOCAL_PATH 表示此时位于工程目录的根目录中, (call my-dir) 的功能由编译器提供,被用来返回当前目录的地址(包含 Android.mk 本身)

②     include $(CLEAR_VARS)

固定写法, CLEAR_VARS 这个变量由编译系统提供,并且要执行一个 GNU makefile 文件,这个功能会清理掉所有以 LOCAL_ 开头的内容(比如 LOCAL_MODULE 、 LOCAL_SRC_FILES 等),除了 LOCAL_PATH。这句话也是必须的,因为如果所有变量都是全局变量的话,所有的可控的编译文件都需要在一个单独的GNU 中被解析并执行

③     LOCAL_MODULE :=Hello

LOCAL_MODLE 变量必须被定义,用来区分 Android.mk 中的每一个模块。文件名必须是唯一的,不能有空格。注意,编译器会为你自动加上一些前缀和后缀,来保证文件是一致的。比如:这里表明一个动态链接库模块被命名为“ Hello ”,但是最后会生成“ libHello.so ”文件。但是在 java 中装载这个库的时候还要使用“ Hello ”名称。

④     LOCAL_SRC_FILES :=hello.c

LOCAL_SRC_FILES 变量必须包含一个 C 和 C++ 源文件的列表,这些会被编译并聚合到一个模块中

注意:这里并不需要列头文件和被包含的文件,因为编译系统会自动为你计算相关的属性,源代码的列表会直接传递给编译器

⑤     include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY 这个变量由系统提供,并且指定给 GNU makefile 的脚本,它可以收集所有你定义的 ”include $(CLEAR_VARS)” 中以 LOCAL_ 开头的变量,并且决定哪些要编译,哪些应该做的更加准确。我们同样可以使用 BUILD_STATIC_LIBRARY 来生成一个静态库,如果使用 BUILD_STATIC_LIBRARY 编译系统便会生成一个以“ lib$(LOCAL_MODULE).a ”为文件名的文件来提供动态库的调用

⑥     TARGET_ARCH

TARGET_ARCH 是指架构中 CPU 的名字已经被 Android 开源代码明确指出了,这里的 arm 包含了任何ARM- 独立结构的架构,以及每个独立的 CPU 版本

⑦    TARGET_PLATFORM

Android 平台的名字在 Android.mk 文件中被解析,比如 ”android-2.3”

⑧     TARGET_ROOT_OUT :表示根文件系统

用法: CAL_MODULE_PATH:=$(TARGET_ROOT_OUT)

⑨     TARGET_OUT: 表示 system 文件系统

⑩    TARGET_OUT_DATA: 表示 data 文件系统

⑪         TARGET_ABI

TARGET_ABI 平台目标板和 abi 的链接,这里要定义 $(TARGET_PLATFORM)-$(TARGET_ARCH_ABI) ,它们都非常有用,特变是当你想测试一个具体的系统镜像在几个真实设备的时候

下面是 GNU 编译出来的宏,并且它们都必须使用“ $(call <function>) ”才能返回文字化的信息。

all-subdir-makefiles :返回一个 Android.mk 文件所在位置的列表,以及当前 my-dir 的路径。

比如: include $(call all-subdir-makefiles)

this-makefile :返回当前 makefile 的路径(就是哪个功能被调用了)

parent-makefile :返回 makefile 的包含树,也就是包含 makefile 的当前文件

Application.mk

要讲 C\C++ 编译为 so 文件,光有 Android.mk 文件是不行的,还需要 Application.mk 文件。

Application.mk 文件存放的位置是 NDK 工程的根目录, Application.mk 文件就是用来描述应用程序中所需要的原生的模块(也就是静态库和动态库),每一个 Application.mk 文件都必须放在应用目录下的子目录,例如$NDK/apps/HelloNdk/Application.mk ,作为 GNU makefile 的一部分, Application.mk 文件必须要定义以下部分

1、  APP_MODULES

APP_MODULES 变量是强制性的,并且会列出所有你所需要的模块(通过 Android.mk )

2、  APP_PROJECT_PATH

APP_PROJECT_PATH 变量也是强制性的,并且会给出应用程序工程的根目录一个绝对路径。这是用来复制或者安装一个没有任何版本限制的 JNI 库,从而给 APK 生成工具一个详细的路径。

例如: \HelloNDK\Application.mk

APP_PROJECT_PATH := $(call my-dir)/project

APP_MODULES := HelloNdk

这里定义了工程路径为 $(call my-dir)/project ,而要编译的模块则是 HelloNdk ,这样编译系统才会找到我们要编译的库和原文件

3、  APP_CFLAGS 则是当要编译模块中有任何 C 文件的时候, C 编译器的信号就会被发出

4、  APP_OPTIM

这个变量是可选的,可以定义为发布版或者测试版

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

在Android.mk中:

include $(BUILD_EXECUTABLE)表示生成二进制可执行文件

include $(BUILD_STATIC_LIBRARY)表示生成静态库.a文件,名字叫做lib<工程名>.a

include $(BUILD_SHARED_LIBRARY)表示生成动态库.so文件,名字叫做lib<工程名>.so

另外需要注意的是,生成的文件需要放在手机的data/local目录下,才可以有执行的权限(未root),如果root了,则会有些目录是可以执行,但是某些目录依然不能执行,当然可以用umount命令解决。SD卡是没有执行权限的,所以当你生成的比如二进制可执行文件放到sdcard中时,是无法运行的。

可以这样测试一下哪些是有执行权限,哪些是没有的:

*将手机插入电脑,并打开USB调试

*在终端输入adb shell进入

*su(root了的手机)

*mount:可以看到一大堆的列表,如果对应的目录的信息中有noexec,说明这个目录就没有执行权限,剩下的都可以执行二进制等文件。

Android.mk文件的具体语法参见我的博客:http://hualang.iteye.com/blog/1140414

向Android源代码中增加模块主要有如下几种:

1、增加可执行文件

增加可执行文件,这些可执行文件一般都是由C/C++生成,下面简单的介绍一些如何向源代码中生成可执行文件

假设我的源代码在~/mydroid目录下

在external/loulijun/test目录下,创建两个文件,一个C,一个Android.mk

hello.c

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. printf("Hello world!\n");
  5. return 0;
  6. }

Android.mk

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_SRC_FILES :=hello.c
  4. LOCAL_MODULE_TAGS :=optional
  5. LOCAL_MODULE :=test
  6. include $(BUILD_EXECUTABLE)

首先退出到mydroid目录下,执行

  1. . build/envsetup.sh
  2. 或者
  3. source build/envsetup.sh

进行环境变量的配置

然后进入到test目录下,执行“mm”(mm表示编译当前项目),如果想重新执行,可以"mm -B"

这样,会在out/target/product/generic/obj/EXECUTABLES/test_intermediates/LINKED/目录下生成可执行文件test

然后将test文件用adb push test /data/local 到data/local目录下。

下面开始执行,你可以在手机中用terminal emulator来执行,也可以以adb shell后,执行

  1. ./test
  2. 显示:Hello world!

2、增加静态库(.a)

Android.mk文件

  1. LOCAL_PATH :=$(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_SRC_FILES := \
  4. hello.c
  5. LOCAL_MODULE :=test
  6. include $(BUILD_STATIC_LIBRARY)

编译:

mydroid#. build/envsetup.sh

test#mm

生成的结果在out/target/product/generic/obj/STATIC_LIBRARY

目标文件夹{XXX}_static_intermediates下,XXX为你定义的模块名称test

假如这个静态库是由hello.c生成的,但是生成的静态库是不能直接使用的,而是由动态库调用它

3、增加动态库(.so)

编译动态库其实可以用NDK的,那样生成非常方便,但是有时候还是需要掌握其他的方法的

Android.mk

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

编译的放法都差不多,只不过Android.mk不同的是最后一句,如果比较一下就会发现那句话决定了生成的是什么

不过要想生成动态库,绝非是这么简单的,有时候只需要Android.mk和源文件即可,但是有时候还需要Application.mk文件。Application.mk文件的具体语法很快会在博客中更新

下面是使用 NDK 来生成 .so 文件的,环境是在 ubuntu11.04 下面

1、 下载 Android-NDK-r6 ,将其解压到 ~/android/android-ndk-r6 目录下

2、  配置 .bash_profile 文件,加入

NDK=~/android/android-ndk-r6

export NDK

3、  cd $NDK 后,进入 ndk 的目录,我以它自带的项目为例,进入 samples/hello-jni

在终端输入 $NDK/ndk-build

系统会自动编译这个文件,并将生成的 libhello-jni.so 文件存放在当前目录的 libs/armeabi 目录下

4、  我们可以将这个生成的 libhello-jni.so 放在 Android 源代码的适当的位置即可使用了

下面是相应的文件

hello-jni.c

  1. #include <string.h>
  2. #include <jni.h>
  3. jstring
  4. Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
  5. jobject thiz )
  6. {
  7. return (*env)->NewStringUTF(env, "Hello from JNI !");
  8. }

Android.mk 文件

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

由于这里只是使用了一个简单的 C 文件,所以没用用到 Application.mk 文件

然后将 hello-jni 导入到 eclipse 中,运行模拟器,即可显示

下面再看一个例子 native-activity

1、  进入目录后执行 $NDK/ndk-build

2、  生成 libnative_activity.so 并存于当前目录的 lib/armeabi 目录下,另外由源代码生成的还有静态库,存放于obj/local/armeabi/ libandroid_native_app_glue.a

这里,由于 main.c 比较大,就不贴上了

Android.mk

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE    := native-activity
  4. LOCAL_SRC_FILES := main.c
  5. LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv1_CM
  6. LOCAL_STATIC_LIBRARIES := android_native_app_glue
  7. include $(BUILD_SHARED_LIBRARY)
  8. $(call import-module,android/native_app_glue)

Application.mk

  1. APP_PLATFORM := android-10<span style="white-space: normal;"> </span>

运行结果:颜色会逐渐变浅,然后再次从这个颜色变浅

4、增加apk文件(有源代码)

如果将 android 程序的源代码加入到 build system 中呢

(1)       在 eclipse 开发环境中创建你的 android 工程,比如叫做 Success

(2)       将工程拷贝到源代码的 package/apps 目录下

(3)       进入 Success 目录下,创建一个 Android.mk 文件,内容如下

  1. LOCAL_PATH :=$(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE_TAGS :=optional
  4. LOCAL_SRC_FILES :=$(call all-java-files-under, src)
  5. LOCAL_PACKAGE_NAME :=(工程名字)
  6. LOCAL_CERTIFICATE :=platform
  7. include $(BUILD_PACKAGE)

(4)       退回到 android 源代码目录下,执行

#. build/envsetup.sh

#mmm packages/apps/Success

编译成功之后,会在 out/target/product/generic/system/app/Success.apk

(5)       如果要在真机上测试, system 的目录是在 out/target/product/crespo 目录下,编译的时候需要设置一些参数。为了测试,将 crespo 中的 system 记其他内核等文件放入到一个叫做 samsung 的文件夹中,再将Success.apk 放到 system/app 中

(6)       用 #zip –r update.zip . 命令将其打包为 zip ,也可以用 zip 直接压缩

(7)      用 #java –jar testsign.jar Samsung/update.zip update.zip 将 zip 包签名

(8)       打开手机的 usb 调试,连接到电脑上,在终端输入 #adb push update.zip /sdcard/update.zip ,将 zip包上传到设备的 sdcard 目录下

(9)       输入 #adb reboot bootloader 进入 bootloader 界面

(10)   输入 #fastboot flash recovery recovery.img 刷 recovery, 我刷的是 Recovery 3.0

(11)   进入 Recovery 选项,刷机,重启后就可以见到 Success.apk 程序了

注意:修改 AndroidManifest.xml ,在 manifest 标签中加入 android:sharedUserId=”media” ,当然这个 media只是个 id ,它的名字随便一般类似包名。我们知道,在不同的 apk 包中默认是不能相互访问数据的,但是如果在 AndroidManifest.xml 中设置 sharedUserId 并且相同的话,那么这两个包就可以相互访问数据。由于我写的只是个测试程序,所以没有加入这条

5、增加apk文件(无源代码)

(1)      这种方式最简单,就是将 ***.apk 文件拷贝到编译 android 源代码时候生成的out/target/product/crespo/system/app 中,执行 make snod 后就可以把 apk 添加到 system.img 中了,然后将system 目录及其他的几个文件打包成 zip 并签名后即可,刷机后可以看到这个内置的系统程序。

(2)       上一种方式在 make clean 之后,再次 make 以后才能执行上述的操作,比较麻烦

①     新建一个目录,在 packages/apps 下面,专门用来存放 apk 文件

#mkdir packages/apps/apks

#cd packages/apps/apks

在这个目录中新建一个 Android.mk 文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_POST_PROCESS_COMMAND := (shell cp –r $(LOCAL_PATH)/*.apk $(TARGET_OUT)/app/)

保存退出

②     把需要编译的 apk 拷贝到 apks 目录中,执行 make ,在 apks 中的 apk 就会被拷贝到out/target/product/generic/system/app 中

③    执行 make snod 即可

这样,在执行 make clean 之后,再次 make ,只需要 make snod 即可了

【转】Android ROM研究---Android build system增加模块的更多相关文章

  1. Android ROM 备书

    1. Android ROM 目录接口 我们经常说的刷ROM是刷系统的意思,但是ROM的原意并不是这样,ROM的全称是read only memory只读储存器,正因为它是“只读”的,而且系统文件通常 ...

  2. Android JNI的Android.mk文件语法详解

    Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build System解 ...

  3. Android Build System

    归类一些Android build system 相关的知识. http://elinux.org/Android_Build_System make <local_module> - m ...

  4. Gradle: The New Android Build System

    Gradle: The New Android Build System Google selected Gradle as the foundation of the Android SDK bui ...

  5. Android uiautomator gradle build system

    This will guide you through the steps to write your first uiautomator test using gradle as it build ...

  6. Android Build System Ultimate Guide

    Android Build System Ultimate Guide April 8,2013 Lately, Android Open Source Project has gone throug ...

  7. android build system resource links

    总体结构,参见这里:http://www.jayway.com/2012/10/24/a-practical-approach-to-the-aosp-build-system/ 一般应用的Andro ...

  8. Android安全研究经验谈

    安全研究做什么 从攻击角度举例,可以是:对某个模块进行漏洞挖掘的方法,对某个漏洞进行利用的技术,通过逆向工程破解程序.解密数据,对系统或应用进行感染.劫持等破坏安全性的攻击技术等. 而防御上则是:查杀 ...

  9. Android ROM 制作教程

    本文来自: 起点手机论坛 具体文章參考:http://www.qdppc.com/forum.php?mod=viewthread&tid=43751&fromuid=1 1.Andr ...

随机推荐

  1. ASP.NET 资料下载

    public void downloadfile(string s_fileName) { HttpContext.Current.Response.ContentType = "appli ...

  2. [图文]centos6.3搭建FTP服务器教程

    我一开始是参照这个教程做的 http://www.linuxren.net/better/centos63-ftp.html 可是问题总是免不了的,我遇到几个问题. 一开始使用terminal的时候一 ...

  3. 类似与三元表达式的 json 读取值

    需要先在项目中添加 json的dll json 序列里面的key在item.feeType里面必须存在 否则会报 未将对象引用到实例 myDr["feeType"] = Newto ...

  4. 在 Mac OS X 中建立加密的 Zip 压缩 -- 让机密资料加上密码

    在 Mac OS X 中要压缩档案的話,基本上就用滑鼠点右鍵选「压缩...」就可以制作 Zip 格式的压缩档,很方便.但如果是机密的资料要透过 Email 等管道传送时,常常会需要建立加密的 Zip ...

  5. 对有状态bean和无状态bean的理解(转)

    现实中,很多朋友对两种session bean存在误解,认为有状态是实例一直存在,保存每次调用后的状态,并对下一次调用起作用,而认为无状态是每次调用实例化一次,不保留用户信息.仔细分析并用实践检验后, ...

  6. MySQL设置

    在MySQL的使用中很容易出现乱码的情况. 实际上在MySQL中有个地方表明了系统中所用到的所有的字符集. 例如: 从中可以看出,对于server和database的默认字符集都是latin1,这样很 ...

  7. demo_03HTML5中的动画效果

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. Source kit service terminated Editor functionality temporarily limited

    这下可好. Source kit service terminated Editor functionality temporarily limited 运行以下代码出现了以上的提示...另外,还压根 ...

  9. 关于java reflect

    反射的基石 Class类 对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人, Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class.对比 ...

  10. pyqt5 窗体布局

    窗体布局 1使用qtdesigner新建一个对话框,然后拖放几个按钮和文本框,按钮使用水平布局,效果如下: 鼠标选中水平布局再选中文本框,进行垂直布局,如下: 垂直布局后的效果如下: 然后,如何让窗体 ...