Android編譯系統(tǒng)(Android.mk文件詳解-僅供參考)

轉(zhuǎn)載聲明

原文地址 作者 發(fā)布時間 作者主頁
Android 編譯系統(tǒng) (一)
Android 編譯系統(tǒng) (二)
haicom 2012-03-13 22:02:38 haicom的博客

注:原作內(nèi)容為2012年所發(fā)布,與最新版本的aosp有些區(qū)別

主要是沒有一個完整的Android Build System 中文版帖族,所以寫了一個也可以以后作為參考态兴。

Makefile & Android build system

在進行講述Android編譯系統(tǒng)之前辫樱,應(yīng)該先了解一下編譯時所使用的Makefile簇宽,或者說復(fù)習下這方面的知識弧满,這樣才能更好的了解Android build system的原理静暂。

Makefile

Makefile的規(guī)則

首先介紹Makefile的規(guī)則:

target ... : prerequisites ...
    command
...

target也就是一個目標文件,可以是Object File谱秽,也可以是執(zhí)行文件洽蛀。還可以是一個標簽(Label)摹迷。prerequisites就是要生成那個target所需要(依賴)的文件或是目標。

command也就是make需要執(zhí)行的命令(任意的Shell命令)郊供。這是一個文件的依賴關(guān)系峡碉,也就是說,target這一個或多個的目標文件依賴于prerequisites中的文件驮审,其生成規(guī)則定義在command中鲫寄。就是說,prerequisites中如果有一個以上的文件比target文件要新的話疯淫,command所定義的命令就會被執(zhí)行地来。

這就是Makefile的規(guī)則。也就是Makefile中最核心的內(nèi)容熙掺,Android編譯系統(tǒng)符合GNU make的標準未斑,當然這也是Android編譯系統(tǒng)最核心的內(nèi)容。

編譯helloworld

下面用一個最簡單的例子來說明這個規(guī)則币绩,當然就是我們最喜歡寫的helloworld蜡秽,創(chuàng)建一個簡單的helloworld.c,下面就是編譯helloworld的makefile:

helloworld : helloworld.o
    cc -o helloworld helloworld .o
helloworld.o : helloworld.c
    cc -c main.c
clean:
    rm helloworld helloworl.o

執(zhí)行make就可以編譯helloworld.c了缆镣,執(zhí)行make clean就可以清除編譯結(jié)果了(其實就是刪除helloworld helloworl.o)芽突。

Android build ystem

Makefile文件用來告訴make命令需要怎么樣的去編譯和鏈接程序。在編譯時董瞻,需要根據(jù)編譯環(huán)境和編譯目標選擇編譯工具寞蚌,編譯參數(shù),以及選擇編譯安裝哪些模塊钠糊。同時Makefile指定了構(gòu)建目標所需的依賴性以及生成規(guī)則睬澡。

在Android中,主要的Makefile文件存在于build/core/目錄下眠蚂,它的表現(xiàn)形式為多個后綴為*.mk的文件組成煞聪,也稱為build systemAndroid build system主要有兩大部分構(gòu)成:配置部分和目標構(gòu)建部分逝慧。

Build system的主流程文件為build/core/main.mk文件昔脯,有它以及所需要的其它*.mk文件共同完成一次Build的任務(wù)。

下面以表格的形式概要描述幾個重要的*.mk的文件的作用:

文件名 作用
Android.mk module/package的設(shè)置文件笛臣,每個module/package的目錄下都會有一個Android.mk
AndroidProducts.mk 即為Android build system提供給廠商的接口文件云稚,通過此文件即可定義所需編譯和安裝的packages,默認為generic
base_rules.mk 對一些Makefile的變量規(guī)則化
BoardConfig.mk 是為product主板做設(shè)定沈堡,例如driver選擇設(shè)定静陈,選擇CPU架構(gòu)等等
Binary.mk 控制如何生成目標文件
buildspec.mk 位于根目錄下,可在此選擇要產(chǎn)生的product 、平臺鲸拥、額外的module/package等拐格。build/buildspec.mk.default是樣板
Clear_vars.mk 清除編譯系統(tǒng)中用到的臨時變量
Copy_headers.mk 將頭文件拷貝到指定目錄
config.mk 定義了編譯目標程序所需的工具鏈及編譯參數(shù)
definations.mk 定義了很多編譯系統(tǒng)中用到的宏,相當于函數(shù)庫
envsetup.mk 初始化編譯環(huán)境刑赶,定義一些實用的shell函數(shù)捏浊,方便編譯
main.mk 實際的主控Makefile,例如找到TOP目錄下所有Android.mk文件
Makefile 輔助main.mk
主要控制生成 system.img,ramdisk.img,userdata.img
build/envsetup.sh 提供了幾個有用的命令撞叨,如:執(zhí)行. build/envsetup.sh
Combo/linux-arm.mk 控制如何生成linux-arm二進制文件金踪,包括ARM相關(guān)的編譯器,編譯參數(shù)等的設(shè)置

Android.mk

Android.mk是Android編譯系統(tǒng)中最重要的一個文件牵敷,下面將詳細介紹:

概述

Android.mk在編譯中起著至關(guān)重要的作用胡岔,這其實就是Android編譯環(huán)境中的makefile。Android.mk文件是為了向生成系統(tǒng)描述你的源代碼枷餐。更明確的說:這個文件實際上是GNU Make文件的一小片段靶瘸,它會被生成系統(tǒng)解析一次或多次。因此尖淘,你應(yīng)該在Android.mk里盡量少地聲明變量。

下面是在NDK中Android.mk網(wǎng)頁中引用的一段:

An Android.mk file is written to describe your sources to thebuild system. More specifically:

  1. The file is really a tiny GNU Makefile fragment that will be parsed one or more times by the build system. As such, you should try to minimize the variables you declare there and do not assume that anything is not defined during parsing.

  2. The file syntax is designed to allow you to group your sources into 'modules'. A module is one of the following:

    • a static library

    • a shared library

Only shared libraries will be installed/copied to your application package. Static libraries can be used to generate shared libraries though.You can define one or more modules in each Android.mk file, and you can use the same source file in several modules.

  1. The build system handles many details for you. For example, you don't need to list header files or explicit dependencies between generated files in your Android.mk. The NDK build system will compute these automatically for you. This also means that, when updating to newer releases of the NDK, you should be able to benefit from new toolchain/platform support without having to touch your Android.mk files.

詳細說明

首先著觉,對這些變量的命名做一說明:

LOCAL_XXX變量:在每個module中都要設(shè)置以LOCAL_開頭的變量村生。它們會被include $(CLEAR_VARS)命令來清除,你會在你的很多module中使用這些LOCAL_開頭的變量饼丘。

PRIVATE_XXX變量:這些變量是make-target-specific(編譯具體目標)的變量趁桃。

INTERNAL_XXX變量:這些變量是編譯系統(tǒng)所使用的變量,所以你最好不要將你的變量用此來命名肄鸽,而且最好也不要在你的makefile中見到這些變量卫病。

HOST_XXX變量和TARGET_XXX變量:這些變量包含或者定義了一些特定的host或者target編譯。所以不要在你的makefile中設(shè)置以開頭HOST_TARGET_的變量典徘。

BUILD_XXX變量和CLEAR_VARS:這些變量都包含在那些清晰的makefile模板中了蟀苛,比如CLEAR_VARSBUILD_HOST_PACKAGE

當然逮诲,你還可以在你的Android.mk文件中使用其它你所需要的命名變量帜平。但是,要記住的是Android是一個非遞歸的編譯系統(tǒng)梅鹦,所以很有可能裆甩,你的變量可能會被其它的Android.mk改變,當你的module執(zhí)行命令是齐唆,這些變量可能已經(jīng)不同了嗤栓。

說明:為保證可參考性,也將英語原文記錄如下箍邮。

But first, a note on variable naming:

LOCAL_ These variables are set per-module. They are cleared by the include $(CLEAR_VARS) line, so you can rely on them being empty after including that file. Most of the variables you'll use in most modules are LOCAL_ variables.

PRIVATE_ These variables are make-target-specific variables. That means they're only usable within the commands for that module. It also means that they're unlikely to change behind your back from modules that are included after yours. This link to the make documentation describes more about target-specific variables. Please note that there are a couple of these laying around the tree that aren't prefixed with PRIVATE_. It is safe, and they will be fixed as they are discovered. Sorry for the confusion.

INTERNAL_ These variables are critical to functioning of the build system, so you shouldn't create variables named like this, and you probably shouldn't be messing with these variables in your makefiles.

HOST_ and TARGET_ These contain the directories and definitions that are specific to either the host or the target builds. Do not set variables that start with HOST_ or TARGET_ in your makefiles.

BUILD_ and CLEAR_VARS These contain the names of well-defined template makefiles to include. Some examples are CLEAR_VARS and BUILD_HOST_PACKAGE.

Any other name is fair-game for you to use in your Android.mk. However, remember that this is a non-recursive build system, so it is possible that your variable will be changed by another Android.mk included later, and be different when the commands for your rule / module are executed

下面對Android.mk文件中涉及到的變量做詳細說明:

LOCAL_XXX變量

LOCAL_XXX變量用于向編譯系統(tǒng)描述你的模塊中所使用的變量,你應(yīng)該在include $(CLEAR_VARS)include $(BUILD_XXXXX)語句之間來定義你想要使用的變量雹仿。

下面來詳細說明以LOCAL_開頭的變量:

  1. LOCAL_ASSET_FILES
    LOCAL_ASSET_FILES在Android.mk文件中編譯應(yīng)用程序(BUILD_PACKAGE)時設(shè)置此變量私恬,表示引用資源文件,通常會定義成:

    LOCAL_ASSET_FILES += $(call find-subdir-assets)
    

    說明:為保證可參考性摔敛,也將英語原文記錄如下(下同,不再說明)全封。

    In Android.mk files that include $(BUILD_PACKAGE) set this to the set of files you want built into your app. Usually:

    LOCAL_ASSET_FILES += $(call find-subdir-assets)
    

    This will probably change when we switch to ant for the apps' build system.

  2. LOCAL_CC
    如果你想在你的module中使用不同的C編譯器马昙,可以設(shè)置這個變量。如果LOCAL_CC是空的刹悴,它就使用默認的編譯器行楞。

    If you want to use a different C compiler for this module, set LOCAL_CC to the path to the compiler. If LOCAL_CC is blank, the appropriate default compiler is used.

  3. LOCAL_CXX
    如果你想在你的module中使用不同的C++編譯器,可以設(shè)置這個變量土匀。如果LOCAL_CXX是空的子房,它就使用默認的編譯器。

    If you want to use a different C++ compiler for this module, set LOCAL_CXX to the path to the compiler. If LOCAL_CXX is blank, the appropriate default compiler is used.

  4. LOCAL_CFLAGS
    LOCAL_CFLAGS變量為C/C++編譯器定義額外的標志就轧,當編譯C/C++源文件時傳遞一個可選的編譯器標志证杭,這對于指定額外的宏定義或編譯選項很有用。例如:

    LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1
    

    If you have additional flags to pass into the C or C++ compiler, add them here. For example:

    LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1
    

    重要提示:
    盡量不要改變Android.mk中的優(yōu)化/調(diào)試級別妒御,這個可以通過在Application.mk中設(shè)置相應(yīng)的信息來自動為你處理解愤,并且會會讓NDK生成在調(diào)試過程中使用的有用的數(shù)據(jù)文件。注意:在Android-ndk-1.5_r1中乎莉,只使用于C源文件送讲,而不適用于C++源文件。在匹配所有Android build system的行為已經(jīng)得到了糾正惋啃。(現(xiàn)在你可以為C++源文件使用LOCAL_CPPFLAGS來指定標志)它可以用LOCAL_CFLAGS += -I<path>來指定額外的包含路徑哼鬓,然而,如果使用LOCAL_C_INCLUDES會更好边灭,因為用ndk-gdk進行本地調(diào)試的時候异希,那些路徑依然是需要使用的。

  5. LOCAL_CPPFLAGS
    LOCAL_CPPFLAGS變量和LOCAL_CFLAGS變量類似绒瘦,如果你只想要增加一些標記(flag)在你的C++編譯器中宠互,使用LOCAL_CPPFLAGS變量來增加它們,例如:

    LOCAL_CPPFLAGS += -ffriend-injection
    

    LOCAL_CPPFLAGS必須在LOCAL_CFLAGS變量命令行的后面使用椭坚,所以你可以用它來重寫你在LOCAL_CFLAGS定義的標記予跌。

    If you have additional flags to pass into only the C++ compiler, add them here. For example:

    LOCAL_CPPFLAGS += -ffriend-injection
    

    LOCAL_CPPFLAGS is guaranteed to be after LOCAL_CFLAGS on the compile line, so you can use it to override flags listed in LOCAL_CFLAGS.

    注意:
    在Android NDK-1.5_r1版本中,相應(yīng)的標志可以應(yīng)用于C或C++源文件上善茎。在配合完整的Android build system的時候券册,這已經(jīng)得到了糾正(你可以使用LOCAL_CFLAGS去指定C或C++源文件)。

  6. LOCAL_CPP_EXTENSION
    如果你的C++文件不是以cpp為文件后綴,通過LOCAL_CPP_EXTENSION指定C++文件后綴名例如:

    LOCAL_CPP_EXTENSION := .cc
    

    需要注意的是在module中給出的所有的C++文件必須具有相同的擴展名烁焙,它是不允許混合使用不同擴展名的航邢。

    If your C++ files end in something other than ".cpp", you can specify the custom extension here. For example:

    LOCAL_CPP_EXTENSION := .cc
    

    Note that all C++ files for a given module must have the same extension; it is not currently possible to mix different extensions.

    注意:統(tǒng)一模塊中C++文件后綴必須保持一致。

  7. LOCAL_C_INCLUDES
    LOCAL_C_INCLUDES變量可以指定額外的目錄來指引C/C++編譯器來尋找頭文件骄蝇。這些路徑必須是最頂端的目錄路徑九火,使用LOCAL_PATH來包含你的子目錄路徑下的文件虑鼎,例如:

    LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
    LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
    

    注意:
    如果你在代碼(main.c)中引用了一些頭文件匾七,而在編譯時如果找不到這些頭文件划址,就會報如下圖的錯誤:


    所以要確保你所包含的路徑目錄下,有你所需要的頭文件署穗,以避免編譯時出現(xiàn)錯誤。

    Additional directories to instruct the C/C++ compilers to look for header files in. These paths are rooted at the top of the tree. Use LOCAL_PATH if you have subdirectories of your own that you want in the include paths. For example:

    LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
    LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
    

    You should not add subdirectories of include to LOCAL_C_INCLUDES, instead you should reference those files in the #include statement with their subdirectories. For example:

    #include <utils/KeyedVector.h>
    not #include <KeyedVector.h>
    

    There are some components that are doing this wrong, and should be cleaned up.

    補充1:
    如果在你的頭文件目錄include下有以下*.h文件:

    /include/
        utils/ KeyedVector.h
        log.h
    

    你不應(yīng)該在LOCAL_C_INCLUDES變量中包含子目錄糕档,相反,你應(yīng)該在使用#include來聲明這些文件的引用茴晋,以及它們的子目錄路徑舷丹。例如:

    #include <utils/KeyedVector.h>
    

    而不是:

    #include <KeyedVector.h>
    

    如果你想引用log.h文件抒钱,那么你應(yīng)該這么寫:

    #include <log.h>
    

    補充2:
    如果你在編譯JNI時,在你的JNI代碼中要引用jni.h時颜凯,既當你的代碼(helloneon.c)中寫道:

    #include <jni.h>
    

    如果你沒有在該目錄下的Android.mk中定義:

    # Also need the JNI headers
    LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
    

    那么就會在編譯時報如下圖所示的錯誤:



    如果你能預(yù)先定義該變量的值谋币,那么就不會出現(xiàn)上述的錯誤。

  8. LOCAL_MODULE_TAGS
    可以用空白的空格來分開一些標簽症概,可以設(shè)置LOCAL_MODULE_TAGS蕾额,如果這個標簽列表是空的或者包含有droid,這個module就會當作droid來編譯彼城,否則诅蝶,它只能用make <your-module>來編譯和安裝你的module逼友,或者使用make all

    Set LOCAL_MODULE_TAGS to any number of whitespace-separated tags. If the tag list is empty or contains droid, the module will get installed as part of a make droid. Otherwise, it will only get installed by running make <your-module>or with the make all pseudotarget.

    補充:
    LOCAL_MODULE_TAGS:模塊標記,一般的取值范圍為debug秤涩、eng帜乞、testoptional筐眷,如果不定義則默認為optional黎烈。對這幾個模式的解釋為:user:指該模塊只在user版本下才編譯;eng:指該模塊只在eng版本下才編譯匀谣;tests:指該模塊只在tests版本下才編譯照棋;optional:指該模塊在所有版本下都編譯。

  9. LOCAL_REQUIRED_MODULES
    可以用空格來分開不同的module的名字武翎,以用來設(shè)置LOCAL_REQUIRED_MODULES烈炭,像libblah或者Email。如果安裝了這個module宝恶,那么同時也會安裝這個module所必需的模塊符隙。確保所需要的共享庫和必須已經(jīng)安裝好,當所給的程序安裝時垫毙。

    Set LOCAL_REQUIRED_MODULES to any number of whitespace-separated module names, like "libblah" or "Email". If this module is installed, all of the modules that it requires will be installed as well. This can be used to, e.g., ensure that necessary shared libraries or providers are installed when a given app is installed.

  10. LOCAL_FORCE_STATIC_EXECUTABLE
    如果編譯的可執(zhí)行程序要進行靜態(tài)鏈接(執(zhí)行時不依賴于任何動態(tài)庫)霹疫,則設(shè)置:

    LOCAL_FORCE_STATIC_EXECUTABLE:=true
    

    目前只有l(wèi)ibc有靜態(tài)庫形式,這個只有文件系統(tǒng)中/sbin目錄下的應(yīng)用程序會用到综芥,這個目錄下的應(yīng)用程序在運行時通常文件系統(tǒng)的其它部分還沒有加載丽蝎,所以必須進行靜態(tài)鏈接。

    If your executable should be linked statically, set

    LOCAL_FORCE_STATIC_EXECUTABLE:=true.
    

    There is a very short list of libraries that we have in static form (currently only libc). This is really only used for executables in /sbin on the root filesystem.

  11. LOCAL_JAVA_LIBRARIES
    LOCAL_JAVA_LIBRARIES編譯java應(yīng)用程序和庫的時候指定包含的java類庫膀藐,目前有core和framework兩種情況下定義成:
    注意:LOCAL_JAVA_LIBRARIES不是必須的屠阻,而且編譯APK時不允許定義(系統(tǒng)會自動添加)

    When linking Java apps and libraries, LOCAL_JAVA_LIBRARIES specifies which sets of java classes to include. Currently there are two of these: core and framework. In most cases, it will look like this:

    LOCAL_JAVA_LIBRARIES := core framework
    

    Note that setting LOCAL_JAVA_LIBRARIES is not necessary (and is not allowed) when building an APK with include $(BUILD_PACKAGE). The appropriate libraries will be included automatically.

  12. LOCAL_LDFLAGS
    你可以通過設(shè)置LOCAL_LDFLAGS來增加額外的標記傳遞給連接器。不過要記住额各,這些參數(shù)對ld來說是非常重要的国觉,所以你最好在所有的平臺都測試下。

    You can pass additional flags to the linker by setting LOCAL_LDFLAGS. Keep in mind that the order of parameters is very important to ld, so test whatever you do on all platforms.

  13. LOCAL_LDLIBS
    LOCAL_LDLIBS允許你在你編譯你的可執(zhí)行程序或者庫的時候臊泰,添加一些指定的額外的庫蛉加。用lxxx的格式來指定你要引用的庫蚜枢,它們會被連接命令行直接解析缸逃。然而,要知道它不會為這些庫生成附屬厂抽。這在使用模擬器編譯而又想使用庫預(yù)編譯在主機上時是非常有用的需频。例如:

    LOCAL_LDLIBS += -lcurses -lpthread
    LOCAL_LDLIBS += -Wl,-z,origin
    

    LOCAL_LDLIBS allows you to specify additional libraries that are not part of the build for your executable or library. Specify the libraries you want in -lxxx format; they're passed directly to the link line. However, keep in mind that there will be no dependency generated for these libraries. It's most useful in simulator builds where you want to use a library preinstalled on the host. The linker (ld) is a particularly fussy beast, so it's sometimes necessary to pass other flags here if you're doing something sneaky. Some examples:

    LOCAL_LDLIBS += -lcurses -lpthread
    LOCAL_LDLIBS += -Wl,-z,origin
    

    補充1:
    LOCAL_LDLIBS:生成你的模塊時用到的額外的連接器標記(linkerflags)的名單,在傳遞有“-l”前綴的特殊系統(tǒng)庫的名稱時很有用筷凤。例如:

    LOCAL_LDLIBS := -labc
    

    上面的語句會告訴連接器在load time時生成連接到/system/lib/目錄下名字叫做libabc.so的動態(tài)庫昭殉。
    補充2:
    如果在你的Android.mk代碼中定義了LOCAL_LDLIBS變量苞七,例如:

    LOCAL_LDLIBS := -lGLESv1_CM -ldl -llog
    

    但是,如果在編譯的過程中找不到這個庫挪丢,或者說這個庫并沒有存在與你編譯環(huán)境下蹂风,那么在編譯的時候就會出現(xiàn)如下圖所示的錯誤:

    所以,在對LOCAL_LDLIBS變量賦值時乾蓬,要確保其正確性以及存在性惠啄,避免出現(xiàn)上圖的編譯錯誤。

  14. LOCAL_NO_MANIFEST
    如果你的Package沒有Manifest(AndroidManifest.xml)任内,你可以設(shè)置

    LOCAL_NO_MANIFEST:=true.
    

    If your package doesn't have a manifest (AndroidManifest.xml), then set

    LOCAL_NO_MANIFEST:=true.
    

    The common resources package does this.

  15. LOCAL_PACKAGE_NAME
    LOCAL_PACKAGE_NAME變量是一個App的名字撵渡,例如:Dialer、Contacts等等死嗦。它可能在我們使用ant編譯系統(tǒng)編譯App時會發(fā)生改變。

    LOCAL_PACKAGE_NAME is the name of an app. For example, Dialer, Contacts, etc. This will probably change or go away when we switch to an ant-based build system for the apps.

  16. LOCAL_PATH
    LOCAL_PATH := $(call my-dir):每個Android.mk文件都必須以定義LOCAL_PATH變量開始越除,其目的是為了定位源文件的位置节腐。例如:

    LOCAL_PATH := $(my-dir)
    

    my-dir宏函數(shù)使用的是MAKEFILE_LIST變量,你必須在include其它任何makefile之前來調(diào)用它摘盆。另外铜跑,考慮到當你include任何子目錄時都要重新設(shè)置LOCAL_PATH,你必須在include它們之前設(shè)置它骡澈。

    The directory your Android.mk file is in. You can set it by putting the following as the first line in your Android.mk:

    LOCAL_PATH := $(my-dir)
    

    The my-dir macro uses the MAKEFILE_LIST variable, so you must call it before you include any other makefiles. Also, consider that any subdirectories you inlcude might reset LOCAL_PATH, so do your own stuff before you include them. This also means that if you try to write several include lines that reference LOCAL_PATH, it won't work, because those included makefiles might reset LOCAL_PATH.

  17. LOCAL_PREBUILT_EXECUTABLES
    LOCAL_PREBUILT_EXECUTABLES預(yù)編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要復(fù)制的可執(zhí)行文件锅纺。

    When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to executables that you want copied. They're located automatically into the right bin directory.

  18. LOCAL_PREBUILT_LIBS
    LOCAL_PREBUILT_LIBS變量是在預(yù)編譯including $(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用, 指定需要復(fù)制的庫.

    When including $(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to libraries that you want copied. They're located automatically into the right lib directory.

  19. LOCAL_SHARED_LIBRARIES
    LOCAL_SHARED_LIBRARIES變量用來列出模塊所需的共享庫的列表,不需要加上.so后綴肋殴。例如:

    LOCAL_SHARED_LIBRARIES := /
        libutils /
        libui /
        libaudio /
        libexpat /
        libsgl
    

    These are the libraries you directly link against. You don't need to pass transitively included libraries. Specify the name without the suffix:

    LOCAL_SHARED_LIBRARIES := \
       libutils \
       libui \
       libaudio \
       libexpat \
       libsgl
    
  20. LOCAL_SRC_FILES
    LOCAL_SRC_FILES變量必須包含一系列將被構(gòu)建和組合成模塊的C/C++源文件囤锉。
    注意:不需要列出頭文件或include文件,因為生成系統(tǒng)會為你自動計算出源文件的依賴關(guān)系护锤。默認的C++源文件的擴展名是.cpp官地,但你可以通過定義LOCAL_DEFAULT_EXTENSION來指定一個擴展名。

    The build system looks at LOCAL_SRC_FILES to know what source files to compile -- .cpp .c .y .l .java. For lex and yacc files, it knows how to correctly do the intermediate .h and .c/.cpp files automatically. If the files are in a subdirectory of the one containing the Android.mk, prefix them with the directory name:

    LOCAL_SRC_FILES := \
       file1.cpp \
       dir/file2.cpp
    
  21. LOCAL_STATIC_LIBRARIES
    LOCAL_STATIC_LIBRARIES變量和LOCAL_SHARED_LIBRARIES類似烙懦,用來列出你的模塊中所需的靜態(tài)庫的列表驱入,你可以在你的module中包含一些想使用的靜態(tài)庫,通常我們使用共享庫氯析,但是有些地方亏较,像在sbin下的可執(zhí)行程序和主機上的可執(zhí)行程序我們要使用靜態(tài)庫。例如:

    LOCAL_STATIC_LIBRARIES := /
        libutils /
        libtinyxml
    

    These are the static libraries that you want to include in your module. Mostly, we use shared libraries, but there are a couple of places, like executables in sbin and host executables where we use static libraries instead.

       LOCAL_STATIC_LIBRARIES := \
           libutils \
           libtinyxml
    
  22. LOCAL_MODULE
    LOCAL_MODULE變量必須定義掩缓,用來標識在Android.mk文件中描述的每個模塊雪情。名稱必須是唯一的,而且不包含任何空格你辣。如果有其它moudle中已經(jīng)定義了該名稱巡通,那么你在編譯時就會報類似這樣的錯誤:

    libgl2jni already defined by frameworks/base/opengl/tests/gl2_jni/jni. Stop.
    

    下面就是該錯誤的截圖:



    接下來就是修改你的module的名字了尘执,或者找到跟你重名的module把它干掉,但不建議你那么做宴凉,因為有可能會帶來未知的錯誤(你修改了別人的module的名字誊锭,而別人不一定知道,當他再編譯或者做其它時弥锄,就會出錯)炉旷。

    LOCAL_MODULE is the name of what's supposed to be generated from your Android.mk. For exmample, for libkjs, the LOCAL_MODULE is "libkjs" (the build system adds the appropriate suffix -- .so .dylib .dll).

    注意:編譯系統(tǒng)會自動產(chǎn)生合適的前綴和后綴,例如:

    LOCAL_MODULE := screenshot
    

    一個被命名為“screenshot”的共享庫模塊叉讥,將會生成“l(fā)ibscreenshot.so”文件窘行。
    補充1:變量命名的規(guī)范性
    如果LOCAL_MODULE變量定義的值可能會被其它module調(diào)用時,就要考慮為其變量命名的規(guī)范性了图仓。特別是在使用JNI時罐盔,既在LOCAL_JNI_SHARED_LIBRARIES變量中定義的值,最好要和LOCAL_MODULE變量定義的值保存一致(具體請參考LOCAL_JNI_SHARED_LIBRARIES變量的使用說明)救崔。
    這時的LOCAL_MODULE變量的命名最好以lib開頭惶看,既libxxx,例如:

    LOCAL_MODULE := libscreenshot
    
  23. LOCAL_MODULE_PATH
    通知編譯系統(tǒng)將module放到其它地方而不是它通常的類型六孵。如果你重寫這個變量纬黎,確保你還要再設(shè)置LOCAL_UNSTRIPPED_PATH變量的值。如果你忘了設(shè)置LOCAL_UNSTRIPPED_PATH變量的值的話劫窒,就會報錯本今。

    Instructs the build system to put the module somewhere other than what's normal for its type. If you override this, make sure you also set LOCAL_UNSTRIPPED_PATH if it's an executable or a shared library so the unstripped binary has somewhere to go. An error will occur if you forget to.

  24. LOCAL_WHOLE_STATIC_LIBRARIES
    LOCAL_WHOLE_STATIC_LIBRARIES 指定模塊所需要載入的完整靜態(tài)庫(這些靜態(tài)庫在鏈接是不允許鏈接器刪除其中無用的代碼)。通常這在你想往共享庫中增加一個靜態(tài)庫時是非常有用的主巍,共享庫就會接受到靜態(tài)庫暴露出的content冠息,例如:

    LOCAL_WHOLE_STATIC_LIBRARIES := /
        libsqlite3_android
    

    These are the static libraries that you want to include in your module without allowing the linker to remove dead code from them. This is mostly useful if you want to add a static library to a shared library and have the static library's content exposed from the shared library.

    LOCAL_WHOLE_STATIC_LIBRARIES := \
       libsqlite3_android
    
  25. LOCAL_REQUIRED_MODULES
    LOCAL_REQUIRED_MODULES 指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊)

    Set LOCAL_REQUIRED_MODULES to any number of whitespace-separated module names, like "libblah" or "Email". If this module is installed, all of the modules that it requires will be installed as well. This can be used to, e.g., ensure that necessary shared libraries or providers are installed when a given app is installed.

  26. LOCAL_PRELINK_MODULE
    LOCAL_PRELINK_MODULE變量用來規(guī)定是否需要預(yù)連接處理(默認需要,用來做動態(tài)庫優(yōu)化)孕索。LOCAL_PRELINK_MODULE只有在編譯.so的時候才會有的選項逛艰,主要是通過預(yù)鏈接的方式來加快程序啟動和執(zhí)行的速度,如果在你的代碼(/jni/Android.mk)中有下面一條語句:

    LOCAL_PRELINK_MODULE := true
    

    那么你要在build/core/prelink-linux-arm.map中定義你的庫所需要使用的空間搞旭,如果不定義或者空間不夠的話散怖,在編譯的時候就會報錯。如下圖所示:


    當在build/core/prelink-linux-arm.map中定義了我們這里使用的libhello-jni.so庫的空間之后肄渗,既在該文件中加入一條語句:

    libhello-jni.so                   0x99E00000
    

    注意:在prelink-linux-arm.map文件的開頭部分有明確的規(guī)定镇眷,指定的內(nèi)存取值范圍分配給不同的部分使用,而我們的App的庫也給指定了一個范圍:

    0x90000000 - 0x9FFFFFFF Prelinked App Libraries
    

    重新編譯恳啥,就不會再報錯了偏灿,下面的截圖中很清晰地看到已經(jīng)將libhello-jni.so庫預(yù)編譯成功了:


    注意:
    在給我們的應(yīng)用庫分配地址空間時丹诀,最好以1M為邊界钝的,地址空間大小按照由大到小的降序進行排序翁垂。

    下面是對于Prelink的說明:

    Prelink利用事先鏈接代替運行時鏈接的方法來加速共享庫的加載,它不僅可以加快起動速度硝桩,還可以減少部分內(nèi)存開銷沿猜。程序運行時的動態(tài)鏈接尤其是重定位(relocation)的開銷對于大型系統(tǒng)來說是很大的。動態(tài)鏈接和加載的過程開銷很大碗脊,并且在大多數(shù)的系統(tǒng)上啼肩,函數(shù)庫并不會常常被更動,每次程序被執(zhí)行時所進行的鏈接動作都是完全相同的衙伶,對于嵌入式系統(tǒng)來說尤其如此祈坠。因此,這一過程可以改在運行時之前就可以預(yù)先處理好矢劲,即花一些時間利用Prelink工具對動態(tài)共享庫和可執(zhí)行文件進行處理赦拘,修改這些二進制文件并加入相應(yīng)的重定位等信息,節(jié)約了本來在程序啟動時的比較耗時的查詢函數(shù)地址等工作芬沉,這樣可以減少程序啟動的時間躺同,同時也減少了內(nèi)存的耗用。

    Prelink的這種做法當然也有代價的丸逸,每次更新動態(tài)共享庫時蹋艺,相關(guān)的可執(zhí)行文件都需要重新執(zhí)行一遍Prelink才能保證有效,因為新的共享庫中的符號信息黄刚、地址等很可能與原來的已經(jīng)不同了捎谨,這就是為什么android framework代碼一改動,這時候就會導(dǎo)致相關(guān)的應(yīng)用程序重新被編譯憔维。

  27. LOCAL_EXPORT_CFLAGS
    LOCAL_JNI_SHARED_LIBRARIES變量主要是用在JNI的編譯中侍芝,如果你要在你的Java代碼中引用JNI中的共享庫*.so,此變量就是共享庫的名字埋同。
    那么你要注意的一點是:在你的Project根目錄下的Android.mk中要定義此變量用來引用你要使用的JNI中的共享庫*.so州叠。例如:

    $(Project)/Android.mk
    LOCAL_JNI_SHARED_LIBRARIES := libsanangeles
    

    而在你的jni目錄下的Android.mk中則要定義LOCAL_MODULE變量的值,一定要讓這兩個變量的值相同凶赁。假如你沒有這么做咧栗,而是像這樣:

    $(Project)/jni/Android.mk
    LOCAL_MODULE := sanangeles
    

    那么,在編譯的時候就會出現(xiàn)下圖的錯誤:


    這說明在編譯libsanangeles.so找不到其規(guī)則虱肄,因為在上面的代碼中定義的是sanangeles致板。重新修改LOCAL_MODULE變量的值:

    $(Project)/jni/Android.mk
    LOCAL_MODULE := libsanangeles
    

    即可正常編譯。

  28. LOCAL_EXPORT_CPPFLAGS
    定義這個變量用來記錄C/C++編譯器標志集合咏窿,并且會被添加到其他任何以LOCAL_STATIC_LIBRARIESLOCAL_SHARED_LIBRARIES的模塊的LOCAL_CFLAGS定義中斟或。例如:這樣定義"foo"模塊:

    #  foo/Android.mk
    include $(CLEAR_VARS)
    LOCAL_MODULE :=foo
    LOCAL_SRC_FILES :=foo/foo.c
    LOCAL_EXPORT_CFLAGS :=-DFOO=1
    include $(BUILD_STATIC_LIBRARY)
    

    另一個模塊,叫做"bar"集嵌,并且依賴于上面的模塊:

    # bar/Android.mk
    include $(CLEAR_VARS)
    LOCAL_MODULE :=bar
    LOCAL_SRC_FILES :=bar.c
    LOCAL_CFLAGS:=-DBAR=2
    LOCAL_STATIC_LIBRARIES:=foo
    include $(BUILD_SHARED_LIBRARY)
    

    然后萝挤,當編譯bar.c的時候御毅,標志"-DFOO=1 -DBAR=2"將被傳遞到編譯器。輸出的標志被添加到模塊的LOCAL_CFLAGS上怜珍,所以你可以很容易重寫它們端蛆。它們也有傳遞性:如果"zoo"依賴"bar",“bar”依賴"foo"酥泛,那么"zoo"也將繼承"foo"輸出的所有標志今豆。
    最后,當編譯模塊輸出標志的時候柔袁,這些標志并不會被使用呆躲。在上面的例子中,當編譯foo/foo.c時捶索,-DFOO=1將不會被傳遞給編譯器歼秽。

  29. LOCAL_EXPORT_C_INCLUDES
    類似LOCAL_EXPORT_CFLAGS,但適用于C++標志情组。
    具體請參考LOCAL_EXPORT_CFLAGS條目燥筷。

  30. LOCAL_EXPORT_LDLIBS
    類似于LOCAL_EXPORT_CFLAGS,但是只用于鏈接標志院崇。注意肆氓,引入的鏈接標志將會被追加到模塊的LOCAL_LDLIBS,這是由UNIX連接器的工作方式?jīng)Q定的底瓣。
    當模塊foo是一個靜態(tài)庫的時候并且代碼依賴于系統(tǒng)庫時會很有用的谢揪。LOCAL_EXPORT_LDLIBS可以用于輸出依賴,例如:

    # Frist build the static library libfoo.a
    include $(CLEAR_VARS)
    LOCAL_MODULE := foo
    LOCAL_SRC_FILES := foo/foo.c
    LOCAL_EXPORT_LDLIBS := -llog
    include $(BUILD_STATIC_LIBRARY)
    
    # Then build the shared library libbar.so
    include $(CLEAR_VARS)
    LOCAL_MODULE := bar
    LOCAL_SRC_FILES := bar.c
    LOCAL_STATIC_LIBRARIES := foo
    include $(BUILD_SHARED_LIBRARY)
    

    這里捐凭,在連接器命令最后拨扶,libbar.so將以”-llog”參數(shù)進行編譯來表明它依賴于系統(tǒng)日志庫,因為它依賴于foo茁肠。

  31. LOCAL_ALLOW_UNDEFINED_SYMBOLS
    默認情況下患民,當試圖編譯一個共享庫的時候遇到任何未定義的引用都可能導(dǎo)致"未定義符號"(undefined symbol)的錯誤。這在你的源代碼中捕獲bug會很有用垦梆。
    然而匹颤,但是由于某些原因,你需要禁用此檢查的話托猩,設(shè)置變量為"true"即可印蓖。需要注意的是,相應(yīng)的共享庫在運行時可能加載失敗京腥。

  32. LOCAL_ARM_MODE
    LOCAL_ARM_MODE變量主要是應(yīng)用與嵌入式產(chǎn)品的編譯系統(tǒng)中赦肃,可以指定為arm模式。例如:

    LOCAL_ARM_MODE := arm
    

    注意:你需要執(zhí)行編譯系統(tǒng)為在ARM模式下通過文件的名字增加后綴的方式編譯指定的源文件。例如:

    LOCAL_SRC_FILES :=foo.c bar.c.arm
    

    這會告訴編譯系統(tǒng)一直以ARM模式編譯"bar.c"他宛,并且通過LOCAL_ARM_MODE的值編譯foo.c船侧。

BUILD_XXX變量

  1. BUILD_SHARED_LIBRARY
    BUILD_SHARED_LIBRARY:指明要編譯生成動態(tài)共享庫。指向一個生成腳本堕汞,這個腳本通過LOCAL_XXX變量收集關(guān)于組件的信息勺爱,并決定如何根據(jù)你列出來的源文件生成目標共享庫晃琳。
    注意:在include這個腳本文件之前你必須至少已經(jīng)定義了LOCAL_MODULELOCAL_SRC_FILES讯检。例如:

    include $(BUILD_SHARED_LIBRARY)
    

    注意:這會生成一個名為lib$(LOCAL_MODULE).so的動態(tài)庫。

  2. BUILD_STATIC_LIBRARY
    BUILD_STATIC_LIBRARYBUILD_SHARED_LIBRARY類似卫旱,但用來生成目標靜態(tài)庫人灼。靜態(tài)庫不會被拷貝至你的project/packages文件夾下,但可用來生成共享庫顾翼。
    例如:

    include $(BUILD_STATIC_LIBRARY)
    

    注意:這會生成一個靜態(tài)庫投放,名叫lib$(LOCAL_MODULE).a的靜態(tài)庫。

  3. BUILD_PACKAGE
    BUILD_PACKAGE變量用于在最好編譯時生成*.apk适贸,例如:

    include $(BUILD_STATIC_LIBRARY)
    

    注意:這會生成一個apk安裝包灸芳,名字就叫$(LOCAL_MODULE).apk的安裝包。

其它變量

  1. CLEAR_VARS
    CLEAR_VARS變量是生成系統(tǒng)提供的拜姿,它指向一個特殊的GNU Makefile烙样,它將會為你自動清除許多名為LOCAL_XXX的變量(比如:LOCAL_MODULELOCAL_SRC_FILES蕊肥、LOCAL_STATIC_LIBRARIES等)谒获,但LOCAL_PATH是例外,它不會被清除壁却。
    注意:這些變量的清除是必須的批狱,因為所有的控制文件是在單一的Makefile,執(zhí)行環(huán)境中解析的展东,在這里所有的變量都是全局的赔硫。

  2. TARGET_PLATFORM
    TARGET_PLATFORM:當解析該Android.mk文件時用它來指定Andoid目標平臺的名稱。例如:android-3Android 1.5相對應(yīng)盐肃。

NDK提供的宏函數(shù)

下面是GNU Make的宏函數(shù)卦停,必須通過這樣的形式調(diào)用:

$(call <function>)
  1. my-dir
    my-dir:返回放置當前Android.mk的文件夾相對于NDK生成系統(tǒng)根目錄的路徑∧张睿可用來在Android.mk的開始處定義LOCAL_PATH的值:

    LOCAL_PATH := $(call my-dir)
    
  2. all-subdir-makefiles
    all-subdir-makefiles:返回my-dir子目錄下的所有Android.mk惊完。例如:
    代碼的結(jié)構(gòu)如下:

    sources/foo/Android.mk
    sources/foo/lib1/Android.mk
    sources/foo/lib2/Android.mk
    

    如果sources/foo/Android.mk里有這樣一行:

    include $(call all-subdir-makefiles)
    

    那么,它將會自動地包含sources/foo/lib1/Android.mksources/foo/lib2/Android.mk处硬。這個函數(shù)能將深層嵌套的代碼文件夾提供給生成系統(tǒng)小槐。
    注意:默認情況下,NDK僅在source/*/Android.mk里尋找文件。

  3. this-makefile
    this-makefile:返回當前Makefile所在目錄的路徑凿跳。

  4. parent-makefile
    parent-makefile:返回父Makefile所在目錄makefile的路徑件豌。

  5. import-module
    一個允許你通過名字找到并包含另一個模塊的的Android.mk的功能,例如:

    $(call import-module,<name>)
    

    這將會找到通過NDK_MODULE_PATH環(huán)境變量引用的模塊<name>的目錄列表控嗜,并且將其自動包含到Android.mk中茧彤。

Application.mk

作用

Application.mk目的是描述在你的應(yīng)用程序中所需要的模塊(即靜態(tài)庫或動態(tài)庫)。
Application.mk文件通常被放置在$PROJECT/jni/Application.mk下疆栏,$PROJECT指的是您的項目曾掂。另一種方法是將其放在頂層的子目錄下,既$NDK/apps目錄下壁顶,例如:

$NDK/apps/<myapp>/Application.mk

<myapp>是一個簡稱珠洗,用于描述你的NDK編譯系統(tǒng)的應(yīng)用程序(這個名字不會生成共享庫或者最終的包),這個方法是Android NDK r4以前的若专,現(xiàn)在仍然兼容许蓖。但是我們強烈建議你使用第一種方法,因為它更簡單并且不用修改NDK安裝樹的目錄调衰。

詳細說明

下面是Application.mk中定義的幾個變量:

  1. APP_MODULES
    APP_MODULES 變量是強制性的膊爪,并且會列出所有你所需要的模塊。它不允許用一個空格來分隔其模塊列表嚎莉,這個模塊名字被定義在Android.mk文件中的LOCAL_MODULE中米酬。

  2. APP_PROJECT_PATH
    APP_PROJECT_PATH變量也是強制性的,并且會給出應(yīng)用程序工程的根目錄一個絕對路徑萝喘。這是用來復(fù)制或者安裝一個沒有任何版本限制的JNI庫淮逻,從而給 APK 生成工具一個詳細的路徑。例如:

    # \HelloNDK\Application.mk
    APP_PROJECT_PATH := $(call my-dir)/project
    APP_MODULES := HelloNdk
    

    這里定義了工程路徑為$(call my-dir)/project阁簸,而要編譯的模塊則是HelloNdk爬早,這樣編譯系統(tǒng)才會找到我們要編譯的庫和源文件。

  3. APP_CFLAGS
    APP_CFLAGS則是當要編譯模塊中有任何C文件或者C++文件的時候启妹,C編譯器的信號就會被發(fā)出筛严。這里可以在你的應(yīng)用中需要這些模塊時,進行編譯的調(diào)整饶米,這樣就不許要直接更改Android.mk為文件本身了桨啃。

  4. APP_OPTIM
    這個變量是可選的,可以定義成兩個值release或者debug檬输,用于修改編譯程序模塊時的優(yōu)化層級照瘾。release模式是默認的,會產(chǎn)生高優(yōu)化的文件丧慈,debug模式會生成不優(yōu)化的文件析命,使得調(diào)試更容易進行主卫。
    注意:調(diào)試releasedebug文件都是可能的,但是release版在調(diào)試節(jié)提高的信息很少鹃愤,一些變量被優(yōu)化輸出簇搅,無法檢查,代碼被重排序软吐,使得跟蹤代碼很困難瘩将,堆棧追蹤也不可靠,等等凹耙。

  5. APP_CPPFLAGS
    當編譯的只有C++源文件的時候姿现,可以通過這個C++編譯器來設(shè)置。
    注意:在Android NDK-1.5_r1中使兔,這個標志可以應(yīng)用于CC++源文件中建钥。并且得到了糾正藤韵,以建立完整的與系統(tǒng)相匹配的Android編譯系統(tǒng)虐沥。你先可也可以使用APP_CFLAGS來應(yīng)用于C或者C++源文件中。建議使用APP_CFLAGS泽艘。

補充

兩種不同級別的應(yīng)用apk

目前我所理解是在Android開發(fā)中我們會遇到兩種不同級別的應(yīng)用apk:系統(tǒng)級應(yīng)用apk和普通級應(yīng)用apk欲险。
下面分別描述兩種apk

  1. 編譯系統(tǒng)級應(yīng)用apk
    將應(yīng)用程序的代碼放到武當源代碼目錄路徑下,然后進行編譯匹涮。將編譯生成的*.apk通過adb或者其它方式放到/system/app目錄下即可天试。

  2. 編譯普通級應(yīng)用apk
    應(yīng)用程序的代碼并沒有放到平臺的源代碼目錄下,然后通過編譯生成的*.apk通過adb install的方式放到/data/app目錄下然低,就是普通級的apk喜每。

參考資料

  1. Android ndk r7b for linux/ Android ndk r6b for windows
  2. Android NDK 概覽: $(NDK)/doc/OVERVIEW.html
  3. NDK使用方法: $(NDK)/doc/HOWTO.html
  4. Android.mk 文件: $(NDK)/doc/ANDROID-MK.html
  5. Application.mk 文件: $(NDK)/doc/APPLICATION-MK.html
  6. Android Building System 總結(jié)
  7. build-system.html: Android 源碼下platform/build/core/build-system.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雳攘,隨后出現(xiàn)的幾起案子带兜,更是在濱河造成了極大的恐慌,老刑警劉巖吨灭,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刚照,死亡現(xiàn)場離奇詭異,居然都是意外死亡喧兄,警方通過查閱死者的電腦和手機无畔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吠冤,“玉大人浑彰,你說我怎么就攤上這事≌蓿” “怎么了郭变?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我饵较,道長拍嵌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任循诉,我火速辦了婚禮横辆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茄猫。我一直安慰自己狈蚤,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布划纽。 她就那樣靜靜地躺著脆侮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勇劣。 梳的紋絲不亂的頭發(fā)上嫁艇,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音筷厘,去河邊找鬼驼修。 笑死,一個胖子當著我的面吹牛命咐,可吹牛的內(nèi)容都是我干的篡九。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼醋奠,長吁一口氣:“原來是場噩夢啊……” “哼榛臼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窜司,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤沛善,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后例证,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體路呜,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年织咧,在試婚紗的時候發(fā)現(xiàn)自己被綠了胀葱。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡笙蒙,死狀恐怖抵屿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捅位,我是刑警寧澤轧葛,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布搂抒,位于F島的核電站,受9級特大地震影響尿扯,放射性物質(zhì)發(fā)生泄漏求晶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一衷笋、第九天 我趴在偏房一處隱蔽的房頂上張望芳杏。 院中可真熱鬧,春花似錦辟宗、人聲如沸爵赵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽空幻。三九已至,卻和暖如春容客,著一層夾襖步出監(jiān)牢的瞬間秕铛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工耘柱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留如捅,地道東北人棍现。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓调煎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親己肮。 傳聞我的和親對象是個殘疾皇子士袄,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android.mk簡介: Android.mk文件用來告知NDK Build系統(tǒng)關(guān)于Source的信息。Andr...
    愛因私談閱讀 19,946評論 0 19
  • 一谎僻、Android.mk介紹 Android.mk是Android提供的一種makefile文件娄柳,用來指定諸如編譯...
    晨北北閱讀 10,483評論 0 3
  • 一、Android.mk介紹 Android.mk是Android提供的一種makefile文件艘绍,用來指定諸如編譯...
    晨北北閱讀 1,676評論 0 0
  • ————————————————版權(quán)聲明:本文為CSDN博主「ytempest」的原創(chuàng)文章赤拒,遵循 CC 4.0 B...
    Zephyr_07閱讀 1,005評論 0 1
  • 1. LOCAL_PATH:= $(callmy-dir) 每個Android.mk文件必須以定義LOCAL_PA...
    蘇恨閱讀 6,072評論 0 9