不然你要我怎么样

彪悍的代码不需要注释

Archive for 六月, 2009

【转贴】Android编译环境(1) – 编译Native C的helloworld模块

one comment

原文点击这里

———————————————————

Android 编译环境本身比较复杂,且不像普通的编译环境:只有顶层目录下才有Makefile文件,而其他的每个component都使用统一标准的 Android.mk. Android.mk文件本身是比较简单的,不过它并不是我们熟悉的Makefile,而是经过了Android自身编译系统的很多处理,因此要真正理清楚其中的联系还比较复杂,不过这种方式的好处在于,编写一个新的Android.mk来给Android增加一个新的Component会比较简单。编译Java程序可以直接采用Eclipse的集成环境来完成,这里就不重复了。我们主要针对C/C++来说明,下面通过一个小例子来说明,如何在Android 中增加一个C程序的Hello World:

1. 在$(YOUR_ANDROID)/development目录下创建hello目录,其中$(YOUR_ANDROID)指Android源代码所在的目录。

$ mkdir $(YOUR_ANDROID)/development/hello

2. 在$(YOUR_ANDROID)/development/hello/目录编写hello.c文件,hello.c的内容当然就是经典的HelloWorld程序:

int main()
{
printf("Hello World!\n");
return 0;
}

3.在$(YOUR_ANDROID)/development/hello/目录编写Android.mk文件。这是Android Makefile的标准命名,不要更改。Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对helloworld程序的Android.mk文件内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
hello.c

LOCAL_MODULE := helloworld
include $(BUILD_EXECUTABLE)

注意上面LOCAL_SRC_FILES用来指定源文件,LOCAL_MODULE指定要编译的模块的名字,下一步骤编译时就要用到。include $(BUILD_EXECUTABLE)表示要编译成一个可执行文件,如果想编译成动态库则可用BUILD_SHARED_LIBRARY,这些可以在$(YOUR_ANDROID)/build/core/config.mk查到。

4. 回到Android源代码顶层目录进行编译:

# cd $(YOUR_ANDROID) && make helloworld

注意make helloworld中的目标名helloworld就是上面Android.mk文件中由LOCAL_MODULE指定的模块名。编译结果如下:

target thumb C: helloworld <= development/hello/hello.c
target Executable: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld)
target Non-prelinked: helloworld (out/target/product/generic/symbols/system/bin/helloworld)
target Strip: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld)
Install: out/target/product/generic/system/bin/helloworld

5.如上面的编译结果所示,编译后的可执行文件存放在out/target/product/generic/system/bin/helloworld,通过”adb push”将它传送到模拟器上,再通过”adb shell”登录到模拟器终端,就可以执行了

转载请注明: 转载自不然你要我怎么样
本文链接地址: 【转贴】Android编译环境(1) – 编译Native C的helloworld模块

Written by xiangmocheng

六月 14th, 2009 at 8:37 下午

Posted in Android

Tagged with ,

【转贴】如何构建Android 1.5系统映像

leave a comment

本文转自William Hua的Blog,原文在此

———————————————–

上一篇文章讲到如何构建Android的kernel映像,我们都知道,系统要运行起来光有kernel映像是不够的,今天我就来说一说如何构建Android的系统映像。

请先参考如何取得Android源代码一文,通过repo来取得当前最新的android主线代码(或者拿名为android-SDK-1.5_r1的tag也无妨)。

1、Host OS编译环境准备
在取得android源代码和编译内核的过程中,我们已经至少安装了cURL、 git-core、ncurses-dev、
build-essential等软件包(Python2.5已经捆绑在Ubuntu8.04中),不过这还不够,要完成Android代码树的编译,我
们还需要flex、bison、gperf、valgrind(可选)、libsdl-dev、libesd0-dev、libwxgtk2.6-
dev、zlib1g-dev等软件包,好在apt-get可以帮我们一次搞定。
sudo apt-get install flex bison gperf valgrind libsdl-dev libesd0-dev libwxgtk2.6-dev zlib1g-dev

另外,编译过程中还需要用到JDK 5.0(注意JDK6.0不被支持),请到Sun的官方网站下载后安装。

2、工具链和环境变量
把JDK5.0加进$PATH,如:
$export PATH=$PATH:/home/william/jdk5.0/bin
然后可以用java -version来确认java的版本

除此之外,编译内核所作的环境变量和工具链的设置在编译系统映像时并不需要,这都由android的编译脚本搞定了。

3、关于编译选项
在build/core目录下的envsetup.mk定义了target的体系结构和OS,默认为arm和linux,我们暂时不涉及移植,所以不需要修改。

4、开始编译
做完上面的准备,在代码树的根目录下敲make就可以了,编译的过程大约需要持续1~2个小时,总计需要大约3.5G的可用空间。

5、测试生成的image
编译完成以后如果想在模拟器中运行,除了kernel的映像文件以外,所需的其他3个映像文件分别是:(位于out/target/product/generic/目录)
ramdisk.img: 包含了在模拟器中启动Android所需的文件系统
system.img: 初始的Android系统映像,包含了程序和库文件
userdata.img: 初始的用户数据映像文件
模拟器会首先到指定的AVD所在的目录查找是否有userdata映像存在,如果没有的话就会基于初始的userdata.img来创建一个,加载这3个
映像文件后,它会把system.img和userdata.img分别挂载载到ramdisk文件系统中的system和userdata目录下。所有
的用户数据都会被保存在AVD目录下的userdata-qemu.img中,初始的用户数据映像文件并不会被修改。

通过命令行参数启动模拟器,加载我们编译的系统映像的方法:
首先设定ANDROID_PRODUCT_OUT环境变量,指向out/target/product/generic/目录(Update:实验证明这一步是没有必要的),然后运行
emulator @1.5_L2 -system system.img -ramdisk ramdisk.img
或者我们加上-kernel参数,用自己编出来的kernel来启动

系统成功启动的截图:
android-emulator

编译Android系统映像虽然花费了不少的时间,不过总体来说还是比较简单的,Android的build system帮助我们搞定了大部分的设置。

转载请注明: 转载自不然你要我怎么样
本文链接地址: 【转贴】如何构建Android 1.5系统映像

Written by xiangmocheng

六月 14th, 2009 at 8:33 下午

Posted in Android

【转贴】如何构建Android 1.5 Linux内核映像

leave a comment

本文转自William Hua的Blog,原文在此

———————-

和一般的Linux系统开发流程一样,Android平台开发的一个很重要的基础工作就是对其内核的编译和移植。本文的目的就在于构建出可以在Android自带的ARM QEMU模拟器上运行的内核映像,希望对于大家做内核的移植和系统构建有帮助。

请先参考我的另一篇文章如何取得Android源代码,确保正确地拿到了Android kernel/common项目
Goldfish分支(该分支用于构建运行在emulator上的系统内核,而主线则是用于构建运行在实际设备上的内核代码)上的内核代码。另外,需要提
醒一下大家的是Android的sourcecode目前只能在Linux或者Mac
OS下做交叉编译编译,Windows并没有被支持,以下将以Ubuntu 8.04为Host OS来说明。

Android对Linux Kernel做了不少的改进,比如添加对yaffs2文件系统的支持,改进蓝牙的支持,改进电源管理机制,以及为模拟器版本添加的Goldfish平台等等,不过内核的编译方式和标准的kernel并没有区别。
这里唯一需要注意的是,Android 1.0_r2以后,整个项目的sourcecode就全部转移到git了,Google Code上不会再有更新,请确保从Git上拿到了android-goldfish-2.6.27分支上的内核代码。

1、在Host OS上准备编译环境
尽管很多人安装完Ubuntu后第一件事情就是装上build-essential,不过我在这里还是要提醒一下大家,另外做menuconfig的时候ncurses-devel库也是必须的。运行以下命令,一次搞定:
sudo apt-get install build-essential ncurses-dev

2、准备交叉编译工具链
Android代码树中有一个prebuilt项目,包含了我们编译内核所需的交叉编译工具,如果你拿了完整的Android 1.5代码树,它就会在prebuilt目录下。如果没有拿完整的代码树也没有关系,只要用Git clone一个或者到从GitWeb下载一个prebuilt项目,如果是从GitWeb下载的话记得解压缩就行。

3、设定环境变量
把刚才下载的prebuilt中的arm-eabi编译器加入$PATH
$export PATH=$PATH:/home/william/android-source/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin

设定目标arch为arm
$export ARCH=arm

4、设定交叉编译参数
打开kernel目录下的Makefile文件,把CROSS_COMPILE指向刚才下载的prebuilt中的arm-eabi编译器
CROSS_COMPILE ?= arm-eabi-


LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
$(call ld-option, -Wl$(comma)–build-id,))

这一行注释掉,并且添加一个空的LDFLAGS_BUILD_ID定义,如下:
LDFLAGS_BUILD_ID =
下面的这段解释来自陈罡的blog

把它注释掉的原因是目前android的内核还不支持这个选项。–build-id选项,主要是用于在生成的elf可执行
文件中加入一个内置的id,这样在core
dump,或者debuginfo的时候就可以很快定位这个模块是哪次build的时候弄出来的。这样就可以避免,每次都把整个文件做一遍效验,然后才能
得到该文件的是由哪次build产生的。对于内核开发者来说,这是很不错的想法,可以节约定位模块版本和其影响的时间。目前,该功能还出于early
stage的状态,未来的android或许会支持,但至少目前的版本是不支持的。
对这个–build-id选项感兴趣的朋友,可以访问下面的网址,它的作者已经解释得非常明白了:

http://fedoraproject.org/wiki/Releases/FeatureBuildId

5、从1.5_r1捆绑的SDK中获得内核配置文件
大家都知道,内核编译中有一步make menuconfig,用于配置kernel,这里我们可以先获取官方的配置,如果必要的话再作改动。先启动模拟器,然后通过adb pull命令(该命令用于从设备上复制文件到本地)即可完成。
$adb pull /proc/config.gz ~/
现在我们用gunzip把config.gz解开,把得到的config文件移动到kernel source所在的目录,然后重命名为.config即可。
$ gunzip config.gz
$ mv config ~/sources/goldfish-kernel/.config

6、开始编译
因为我们之前已经吧1.5_r1中的.config复制到了kernel目录下,如果需要修改配置,可以使用
make menuconfig
修改并保存配置,如果没有特殊需要的话就可以直接用
make
命令来编译内核了

7、测试生成的zImage
编译内核的过程应该很顺利,因为默认的配置对内核作了大幅的精简,大约5~6分钟就可以编译完成了,会在最终会在arch/arm/boot目录下面生成一个zImage,这个就是我们所要的运行在模拟器上的内核映像了。
下面我们就在模拟器中测试一下我们所生成的zImage。
emulator @1.5_L2 -kernel ./zImage
其中1.5_L2是我之前创建的AVD,如果想输出kernel log,请加上-show-kernel参数。

一切顺利的话,我们应该可以看到Android顺利启动了。

通过adb shell,我们可以查看version信息,如下图:

关于为实际设备编译kernel
如果要为一个实际的设备比如说G1重新编译内核映像,步骤和上述为一个运行在模拟器上的内核映像步骤基本一致,只是所需要的源代码应当来自主线而不是goldfish分支。另外,编译完成以后载入映像的方式也不同,需要通过USB将映像烧入nand flash。

转载请注明: 转载自不然你要我怎么样
本文链接地址: 【转贴】如何构建Android 1.5 Linux内核映像

Written by xiangmocheng

六月 14th, 2009 at 8:30 下午

Posted in Android

随想录(十三)——人生不外乎是爱自己爱的人,恨自己恨的人

leave a comment

常遇到分手的人打来电话(这么说我周围的人似乎很倒霉),久而久之,便习惯去帮他们分析感情世界里的基本要素,试图做一个爱情达人。我发现,所有的电话,无非分为两种:我还爱她,或者我不爱她。

而道理也似乎很简单:放弃,或者继续。忘记,或者逃离。

不过是个人都知道这做起来是多么的难。

有时在想,爱情的世界里真的有颠簸不灭的真理么?我们按图索骥,便能得到一份完美的爱情?

我想没有人会相信。

爱是如此的不可把握,而我们总习惯于把主动权掌握在自己手中。一旦对方变得不可预知,我们便焦虑,忧愁,食不下咽,更别提辛辛苦苦的付出到头来只得到一厢情愿。我们在爱情中发现真诚,关怀,背叛和欺骗,才明白人是如此的复杂多变,会犹豫,会软弱,会犯错。所有人都在小心翼翼的做出选择,即使这选择连自己都说不清楚。

在人性的面前,我只能永远的保持谦卑,保持理解和宽容。于是再传奇的故事,我都觉得还好,一切皆有可能,不是么?每个人的心中,早有了一份答案,只是还未发现,或者不愿承认。

其实电话的另一头,需要的只是倾诉而已。我应该学会,静静聆听。

转载请注明: 转载自不然你要我怎么样
本文链接地址: 随想录(十三)——人生不外乎是爱自己爱的人,恨自己恨的人

Written by xiangmocheng

六月 12th, 2009 at 11:57 下午

Posted in Life

Tagged with

【转贴】Android Building System 分析

leave a comment

by thinker,原文参见这里

—————————————-

想要了解一個系統,我常會從 makefile 或是 building system 下手,以了解系統組成元素為何? 目錄結構為何? 對於Android ,我也不例外。透過了解 building system,我們能知道如何新增、修改、刪除程式,並保有完整性,順利編譯出結果。

設定檔

Android building system包括幾種重要的設定檔,

  • Android.mk
  • AndroidProducts.mk
  • target_-.mk, host_-.mk and -.mk
  • BoardConfig.mk
  • buildspec.mk

Android.mk 是 module 和 package 的設定檔,每個 module/package的目錄下都會有一個 Android.mk。所謂的 module 是指系統的 native code ,相對於用 Java 寫成的 Androidapplication 稱為 package。

AndroidProducts.mk 則設定 product 配置。 product 即特定系統版本,透過編譯不同 product ,產生不同軟體配置內容,安裝不同的 application。Product 可視為特定專案,產生特定規格系統。

BoardConfig.mk 是為 product 主板做設定,像是 driver 選擇、設定。*-.mk 則是針對選擇的作業系統和 CPU 架構,進行相關設定。

buildspec.mk 是位於 source 根目錄下,為進行編譯者所做之額外設定。例如,可在此選擇要產生的 product 、平台、額外的 module/package 等。

參數

build/envsetup.sh 實作一個 mm 指令,以編譯單一 module,不需編譯整個 source tree。ONE_SHOT_MAKEFILE 這個 makefile 變數/參數就是用以實作這個功能。使用方法是在執行 make 時,將該變數指定為 module 的 Android.mk。

  • make ONE_SHOT_MAKEFILE=

透過定義 CREATE_MODULE_INFO_FILE , building system 會將所有 module 資訊列在 $(PRODUCT_OUT)/module-info.txt 檔案裡。

  • make CREATE_MODULE_INFO_FILE=true

設定 BUILD_TINY_ANDROID=true , building system 產生一個簡單的 image ,以測試硬體的可用度。此功能用於移植的早期階段,以快速 bring up 。

HOST_BUILD_TYPE 和 TARGET_BUILD_TYPE 指定 building system 產生 binary的目的為 debug 或 release 。透過設定此二變數,能產生包含 debug information的 binry 。

  • debug
  • release

這些參數,也可設於 buildspec.mk 裡,以避免開發過程不斷的重新指定。

Goals

一般編輯整個 Android 系統,就是使用 droid 這個 goal。 droid 會產生一個完整的系統,包括 bootloader、kernel、系統程式、模組和應用程式。

showcommands 和 droid 功能相同,但 droid 在編譯過程不顯示所使用的指令。透過 showcommands 這個 goal, building system 顯示過程中每一個步驟的詳細指令。

Makefile 的流程

  • 初始化相關變數
  • 偵測編譯環境和目標環境
  • 決定目標 product
  • 讀取 product 的設定
  • 讀取 product 所指定之目標平台架構設定
    • 選擇 toolchain
    • 指定編譯參數 (*-.mk)
  • 清除輸出目錄
  • 設定/檢查版本編號
  • 讀取所有 BoardConfig.mk 檔案
  • 讀取所有 module 的設定
  • 根據設定,產生必需的 rule
  • 產生 image

以上的主要流程都是由 build/core/main.mk 所安排。

初始化和偵測

由 build/core/config.mk 所進行。build/core/envsetup.mk 檢查 developer 的設定 (buildspec.mk) ,並檢查執行環境,以決定輸出目錄、項目。build/core/config.mk 本身還依據參數,決定解譯時的相關參數。像是 compiler的路徑、flags, lex 、yacc 的路徑參數等。

關於 product 的相關設定,則是由 build/core/product_config.mk 所處理,使用 build/core/product.mk 提供之 macro 載入。根據 AndroidProduct.mk 的內容,product_config.mk 決定了

  • PRODUCT_TAGS
  • OTA_PUBLIC_KEYS
  • PRODUCT_POLICY
  • ……

Product 設定的讀取

Android product 的設定來自於 build/target/product/AndroidProduct.mk 和vendor 子目錄下的 AndroidProduct.mk 。 building system 透過 find 指令,找出所有可能的 AndroidProduct.mk。 AndroidProduct.mk 裡定義PRODUCT_MAKEFILES 變數,列舉所有實際定義 product 的 makefile。

這些 makefile 各自定義獨立的 product 。product 相關參數,存成PRODUCTS. . 形式的變數。並將 makefile 路徑存在 PRODUCTS 變數。因此,透過 PRODUCTS 能取得所有的 product 路徑/名稱,並透過 PRODUCTS. . 形式的變數取得內容。

Module 設定的讀取

Module 是指 native code 的軟體元件,而 Java application 則被稱為 package。build/core/definitions.mk 定義 module/package 相關 macro ,讀取、檢查module/package 定義檔;分散 source tree 各處的 Android.mk 檔案。build/core/main.mk 使用 find 指令,在這些子目錄下找出所有 Android.mk ,並將路徑存在 subdir_makefiles 變數裡。最後,include 這些檔案。

這些 Android.mk 會 include 定義成變數 BUILD_SHARED_LIBRARY 、BUILD_PACKAGE 等,和其目的相配的 makefile。這些 makefile 會變 Android.mk 定義之內容,存成ALL_MODULES. Android.mk>. 形式。例如,Android.mk 定義了 LOCAL_MODULE_SUFFIX ,變會存成ALL_MODULES. Android.mk>.LOCAL_MODULE_SUFFIX 。而 Android.mk 路徑,當樣會存於 ALL_MODULES 變數裡。

Search Android.mk 的路徑,基本上會是整個 source tree 。但會依特定的 goal ,選擇性只找尋特定目錄。例如 SDK 只需特定目錄下的 Android.mk 。

Board Level 設定

和目標平台主板相關之設定,例如使用了什麼裝置、driver 等,或是是否需要編譯bootloader 、 kernel 等,都是在BoardConfig.mk 裡設定。同樣,每張主板可以有不同設定,存在不同目錄下的 BoardConfig.mk ,以 find 尋找如下檔案:

  • build/target/board/$(TARGET_DEVICE)/BoardConfig.mk
  • vendor/*/$(TARGET_DEVICE)/BoardConfig.mk

TARGET_DEVICE 是 product 所定義,因此同一個 BoardConfig.mk 可被多個product 所使用。一個 TARGET_DEVICE ,通常只有一個 BoardConfig.mk 。BoardConfig.mk 會被直接 include 到 building system 的 name space 裡。因此,一些 module 的 enable/disable ,可以在 BoardConfig.mk 以對映不同的主板。

Rules

在 module 的定義檔 Android.mk 裡,可定義 module 的 tag, LOCAL_MODULE_TAGS,以分類這些 module。每一個 product 可以指定需要的 tag (PRODUCT_TAGS),使 building system只編譯標示這些 tag 的 module。在 build/core/main.mk 裡,所有標示特定 tag的 module 收集為 ALL_DEFAULT_INSTALLED_MODULES ,並 includebuild/core/Makefile 處理。build/core/Makefile 為這些 module 產生 rule ,並使產生 image 的 goal depend on這些 rule ,使這些 module 被編譯。

結論

Android 的 building system 其實不是那麼複雜。在了解之後,也不是那麼難修改。但, GNU make 的一些語法,所 building system 使用一些不是那麼直覺的用法,使的 building system 較難了解。但,花點心思就能克服。

转载请注明: 转载自不然你要我怎么样
本文链接地址: 【转贴】Android Building System 分析

Written by xiangmocheng

六月 10th, 2009 at 9:48 上午

Posted in Android