android NDK編譯 中文版2
(2012-07-24 15:47:05)
分類(lèi):
androidLOCAL_NO_MANIFEST
如果你的Package沒(méi)有Manifest(AndroidManifest.xml),你可以設置
LOCAL_NO_MANIFEST:=true.
------分隔符,方便下次編輯修改------
If your packagedoesn't have a manifest (AndroidManifest.xml), thenset
LOCAL_NO_MANIFEST:=true.
The common resourcespackage does this.
LOCAL_PACKAGE_NAME
LOCAL_PACKAGE_NAME變量是一個(gè)App的名字,例如:Dialer、Contacts等等。它可能在我們使用ant編譯系統編譯App時(shí)會(huì )發(fā)生改變。
LOCAL_PACKAGE_NAME isthe name of an app. For example, Dialer, Contacts, etc. This willprobably change or go away when we switch to an ant-based buildsystem for the apps.
LOCAL_PATH
LOCAL_PATH := $(callmy-dir):每個(gè)Android.mk文件都必須以定義LOCAL_PATH變量開(kāi)始,其目的是為了定位源文件的位置。例如:
LOCAL_PATH :=$(my-dir)
my-dir宏函數使用的是MAKEFILE_LIST變量,你必須在include其它任何makefile之前來(lái)調用它。另外,考慮到當你include任何子目錄時(shí)都要重新設置LOCAL_PATH,你必須在include它們之前設置它。
The directory yourAndroid.mk file is in. You can set it by putting the following asthe first line in your Android.mk:
LOCAL_PATH :=$(my-dir)
The my-dir macro usesthe MAKEFILE_LIST variable, so you must call it before you includeany other makefiles. Also, consider that any subdirectories youinlcude might reset LOCAL_PATH, so do your own stuff before youinclude them. This also means that if you try to write severalinclude lines that reference LOCAL_PATH, it won't work, becausethose included makefiles might reset LOCAL_PATH.
LOCAL_PREBUILT_EXECUTABLES
LOCAL_PREBUILT_EXECUTABLES預編譯including$(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時(shí)所用,指定需要復制的可執行文件。
When including$(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these toexecutables that you want copied. They're located automaticallyinto the right bin directory.
LOCAL_PREBUILT_LIBS
LOCAL_PREBUILT_LIBS變量是在預編譯including$(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時(shí)所用, 指定需要復制的庫.
When including$(BUILD_PREBUILT) or $(BUILD_HOST_PREBUILT), set these to librariesthat you want copied. They're located automatically into the rightlib directory.
LOCAL_SHARED_LIBRARIES
LOCAL_SHARED_LIBRARIES變量用來(lái)列出模塊所需的共享庫的列表,不需要加上.so后綴。例如:
LOCAL_SHARED_LIBRARIES :=/
libutils /
libui /
libaudio /
libexpat /
libsgl
------分隔符,方便下次編輯修改------
These are thelibraries you directly link against. You don't need to passtransitively included libraries. Specify the name without thesuffix:
LOCAL_SHARED_LIBRARIES := \
libutils\
libui\
libaudio\
libexpat\
libsgl
LOCAL_SRC_FILES
LOCAL_SRC_FILES變量必須包含一系列將被構建和組合成模塊的C/C++源文件。
注意:不需要列出頭文件或include文件,因為生成系統會(huì )為你自動(dòng)計算出源文件的依賴(lài)關(guān)系。默認的C++源文件的擴展名是.cpp,但你可以通過(guò)定義LOCAL_DEFAULT_EXTENSION來(lái)指定一個(gè)擴展名。
The build systemlooks at LOCAL_SRC_FILES to know what source files to compile --.cpp .c .y .l .java. For lex and yacc files, it knows how tocorrectly do the intermediate .h and .c/.cpp files automatically.If the files are in a subdirectory of the one containing theAndroid.mk, prefix them with the directory name:
LOCAL_SRC_FILES :=\
file1.cpp\
dir/file2.cpp
LOCAL_STATIC_LIBRARIES
LOCAL_STATIC_LIBRARIES變量和LOCAL_SHARED_LIBRARIES類(lèi)似,用來(lái)列出你的模塊中所需的靜態(tài)庫的列表,你可以在你的module中包含一些想使用的靜態(tài)庫,通常我們使用共享庫,但是有些地方,像在sbin下的可執行程序和主機上的可執行程序我們要使用靜態(tài)庫。例如:
LOCAL_STATIC_LIBRARIES :=/
libutils /
libtinyxml
------分隔符,方便下次編輯修改------
These are the staticlibraries that you want to include in your module. Mostly, we useshared libraries, but there are a couple of places, likeexecutables in sbin and host executables where we use staticlibraries instead.
LOCAL_STATIC_LIBRARIES := \
libutils\
libtinyxml
LOCAL_MODULE
LOCAL_MODULE變量必須定義,用來(lái)標識在A(yíng)ndroid.mk文件中描述的每個(gè)模塊。名稱(chēng)必須是唯一的,而且不包含任何空格。如果有其它moudle中已經(jīng)定義了該名稱(chēng),那么你在編譯時(shí)就會(huì )報類(lèi)似這樣的錯誤:
libgl2jnialready defined by frameworks/base/opengl/tests/gl2_jni/jni.Stop.
下面就是該錯誤的截圖:
接下來(lái)就是修改你的module的名字了,或者找到跟你重名的module把它干掉,但不建議你那么做,因為有可能會(huì )帶來(lái)未知的錯誤(你修改了別人的module的名字,而別人不一定知道,當他再編譯或者做其它時(shí),就會(huì )出錯)。
LOCAL_MODULE is thename of what's supposed to be generated from your Android.mk. Forexmample, for libkjs, the LOCAL_MODULE is "libkjs" (the buildsystem adds the appropriate suffix -- .so .dylib.dll).
注意:編譯系統會(huì )自動(dòng)產(chǎn)生合適的前綴和后綴,例如:
LOCAL_MODULE :=screenshot
一個(gè)被命名為“screenshot”的共享庫模塊,將會(huì )生成“l(fā)ibscreenshot.so”文件。
補充1:變量命名的規范性
如果LOCAL_MODULE變量定義的值可能會(huì )被其它module調用時(shí),就要考慮為其變量命名的規范性了。特別是在使用JNI時(shí),既在LOCAL_JNI_SHARED_LIBRARIES變量中定義的值,最好要和LOCAL_MODULE變量定義的值保存一致(具體請參考LOCAL_JNI_SHARED_LIBRARIES變量的使用說(shuō)明)。
這時(shí)的LOCAL_MODULE變量的命名最好以lib開(kāi)頭,既“l(fā)ibxxx”,例如:
LOCAL_MODULE :=libscreenshot
LOCAL_MODULE_PATH
通知編譯系統將module放到其它地方而不是它通常的類(lèi)型。如果你重寫(xiě)這個(gè)變量,確保你還要再設置LOCAL_UNSTRIPPED_PATH變量的值。如果你忘了設置LOCAL_UNSTRIPPED_PATH變量的值的話(huà),就會(huì )報錯。
Instructs the buildsystem to put the module somewhere other than what's normal for itstype. If you override this, make sure you also setLOCAL_UNSTRIPPED_PATH if it's an executable or a shared library sothe unstripped binary has somewhere to go. An error will occur ifyou forget to.
LOCAL_WHOLE_STATIC_LIBRARIES
LOCAL_WHOLE_STATIC_LIBRARIES 指定模塊所需要載入的完整靜態(tài)庫(這些靜態(tài)庫在鏈接是不允許鏈接器刪除其中無(wú)用的代碼)。通常這在你想往共享庫中增加一個(gè)靜態(tài)庫時(shí)是非常有用的,共享庫就會(huì )接受到靜態(tài)庫暴露出的content,例如:
LOCAL_WHOLE_STATIC_LIBRARIES :=/
libsqlite3_android
------分隔符,方便下次編輯修改------
These are the staticlibraries that you want to include in your module without allowingthe linker to remove dead code from them. This is mostly useful ifyou want to add a static library to a shared library and have thestatic library's content exposed from the sharedlibrary.
LOCAL_WHOLE_STATIC_LIBRARIES :=\
libsqlite3_android
LOCAL_REQUIRED_MODULES
LOCAL_REQUIRED_MODULES 指定模塊運行所依賴(lài)的模塊(模塊安裝時(shí)將會(huì )同步安裝它所依賴(lài)的模塊)
SetLOCAL_REQUIRED_MODULES to any number of whitespace-separated modulenames, like "libblah" or "Email". If this module is installed, allof the modules that it requires will be installed as well. This canbe used to, e.g., ensure that necessary shared libraries orproviders are installed when a given app isinstalled.
LOCAL_PRELINK_MODULE
LOCAL_PRELINK_MODULE變量用來(lái)規定是否需要預連接處理(默認需要,用來(lái)做動(dòng)態(tài)庫優(yōu)化)。LOCAL_PRELINK_MODULE只有在編譯.so的時(shí)候才會(huì )有的選項,主要是通過(guò)預鏈接的方式來(lái)加快程序啟動(dòng)和執行的速度,如果在你的代碼(/jni/Android.mk)中有下面一條語(yǔ)句:
LOCAL_PRELINK_MODULE:= true
那么你要在build/core/prelink-linux-arm.map中定義你的庫所需要使用的空間,如果不定義或者空間不夠的話(huà),在編譯的時(shí)候就會(huì )報錯。如下圖所示:
當在build/core/prelink-linux-arm.map中定義了我們這里使用的libhello-jni.so庫的空間之后,既在該文件中加入一條語(yǔ)句:
libhello-jni.so 0x99E00000
注意:在prelink-linux-arm.map文件的開(kāi)頭部分有明確的規定,指定的內存取值范圍分配給不同的部分使用,而我們的App的庫也給指定了一個(gè)范圍:
0x90000000 -0x9FFFFFFF Prelinked App Libraries
重新編譯,就不會(huì )再報錯了,下面的截圖中很清晰地看到已經(jīng)將libhello-jni.so庫預編譯成功了:
注意:
在給我們的應用庫分配地址空間時(shí),最好以1M為邊界,地址空間大小按照由大到小的降序進(jìn)行排序。
下面是對于Prelink的說(shuō)明:
Prelink利用事先鏈接代替運行時(shí)鏈接的方法來(lái)加速共享庫的加載,它不僅可以加快起動(dòng)速度,還可以減少部分內存開(kāi)銷(xiāo)。程序運行時(shí)的動(dòng)態(tài)鏈接尤其是重定位(relocation)的開(kāi)銷(xiāo)對于大型系統來(lái)說(shuō)是很大的。動(dòng)態(tài)鏈接和加載的過(guò)程開(kāi)銷(xiāo)很大,并且在大多數的系統上,函數庫并不會(huì )常常被更動(dòng),每次程序被執行時(shí)所進(jìn)行的鏈接動(dòng)作都是完全相同的,對于嵌入式系統來(lái)說(shuō)尤其如此。因此,這一過(guò)程可以改在運行時(shí)之前就可以預先處理好,即花一些時(shí)間利用Prelink工具對動(dòng)態(tài)共享庫和可執行文件進(jìn)行處理,修改這些二進(jìn)制文件并加入相應的重定位等信息,節約了本來(lái)在程序啟動(dòng)時(shí)的比較耗時(shí)的查詢(xún)函數地址等工作,這樣可以減少程序啟動(dòng)的時(shí)間,同時(shí)也減少了內存的耗用。
Prelink的這種做法當然也有代價(jià)的,每次更新動(dòng)態(tài)共享庫時(shí),相關(guān)的可執行文件都需要重新執行一遍Prelink才能保證有效,因為新的共享庫中的符號信息、地址等很可能與原來(lái)的已經(jīng)不同了,這就是為什么androidframework代碼一改動(dòng),這時(shí)候就會(huì )導致相關(guān)的應用程序重新被編譯。
LOCAL_JNI_SHARED_LIBRARIES
LOCAL_JNI_SHARED_LIBRARIES變量主要是用在JNI的編譯中,如果你要在你的Java代碼中引用JNI中的共享庫*.so,此變量就是共享庫的名字。
那么你要注意的一點(diǎn)是:在你的Project根目錄下的Android.mk中要定義此變量用來(lái)引用你要使用的JNI中的共享庫*.so。例如:
$(Project)/Android.mk
LOCAL_JNI_SHARED_LIBRARIES :=libsanangeles
而在你的jni目錄下的Android.mk中則要定義LOCAL_MODULE變量的值,一定要讓這兩個(gè)變量的值相同。假如你沒(méi)有這么做,而是像這樣:
$(Project)/jni/Android.mk
LOCAL_MODULE :=sanangeles
那么,在編譯的時(shí)候就會(huì )出現下圖的錯誤:
這說(shuō)明在編譯libsanangeles.so找不到其規則,因為在上面的代碼中定義的是sanangeles。重新修改LOCAL_MODULE變量的值:
$(Project)/jni/Android.mk
LOCAL_MODULE :=libsanangeles
即可正常編譯。
LOCAL_EXPORT_CFLAGS
定義這個(gè)變量用來(lái)記錄C/C++編譯器標志集合,并且會(huì )被添加到其他任何以L(fǎng)OCAL_STATIC_LIBRARIES和LOCAL_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)
另一個(gè)模塊,叫做"bar",并且依賴(lài)于上面的模塊:
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的時(shí)候,標志"-DFOO=1 -DBAR=2"將被傳遞到編譯器。輸出的標志被添加到模塊的LOCAL_CFLAGS上,所以你可以很容易重寫(xiě)它們。它們也有傳遞性:如果"zoo"依賴(lài)"bar",“bar”依賴(lài)"foo",那么"zoo"也將繼承"foo"輸出的所有標志。
最后,當編譯模塊輸出標志的時(shí)候,這些標志并不會(huì )被使用。在上面的例子中,當編譯foo/foo.c時(shí),-DFOO=1將不會(huì )被傳遞給編譯器。
LOCAL_EXPORT_CPPFLAGS
類(lèi)似LOCAL_EXPORT_CFLAGS,但適用于C++標志。
具體請參考LOCAL_EXPORT_CFLAGS條目。
LOCAL_EXPORT_C_INCLUDES
類(lèi)似LOCAL_EXPORT_CFLAGS,但是只有C能包含路徑,如果"bar.c"想包含一些由"foo"模塊提供的頭文件的時(shí)候這會(huì )很有用。
具體請參考LOCAL_EXPORT_CFLAGS條目。
LOCAL_EXPORT_LDLIBS
類(lèi)似于LOCAL_EXPORT_CFLAGS,但是只用于鏈接標志。注意,引入的鏈接標志將會(huì )被追加到模塊的LOCAL_LDLIBS,這是由UNIX連接器的工作方式?jīng)Q定的。
當模塊foo是一個(gè)靜態(tài)庫的時(shí)候并且代碼依賴(lài)于系統庫時(shí)會(huì )很有用的。LOCAL_EXPORT_LDLIBS可以用于輸出依賴(lài),例如:
#Frist build thestatic 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 theshared 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”參數進(jìn)行編譯來(lái)表明它依賴(lài)于系統日志庫,因為它依賴(lài)于foo。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
默認情況下,當試圖編譯一個(gè)共享庫的時(shí)候遇到任何未定義的引用都可能導致"未定義符號"(undefinedsymbol)的錯誤。這在你的源代碼中捕獲bug會(huì )很有用。
然而,但是由于某些原因,你需要禁用此檢查的話(huà),設置變量為"true"即可。需要注意的是,相應的共享庫在運行時(shí)可能加載失敗。
LOCAL_ARM_MODE
LOCAL_ARM_MODE變量主要是應用與嵌入式產(chǎn)品的編譯系統中,可以指定為arm模式。例如:
LOCAL_ARM_MODE :=arm
注意:你需要執行編譯系統為在A(yíng)RM模式下通過(guò)文件的名字增加后綴的方式編譯指定的源文件。例如:
LOCAL_SRC_FILES:=foo.c bar.c.arm
這會(huì )告訴編譯系統一直以ARM模式編譯"bar.c",并且通過(guò)LOCAL_ARM_MODE的值編譯foo.c。
2.2.2.BUILD_XXX變量
2.2.2.1.BUILD_SHARED_LIBRARY
BUILD_SHARED_LIBRARY:指明要編譯生成動(dòng)態(tài)共享庫。指向一個(gè)生成腳本,這個(gè)腳本通過(guò)LOCAL_XXX變量收集關(guān)于組件的信息,并決定如何根據你列出來(lái)的源文件生成目標共享庫。
注意:在include這個(gè)腳本文件之前你必須至少已經(jīng)定義了LOCAL_MODULE和LOCAL_SRC_FILES。例如:
include$(BUILD_SHARED_LIBRARY)
注意:這會(huì )生成一個(gè)名為lib$(LOCAL_MODULE).so的動(dòng)態(tài)庫。
2.2.2.2.BUILD_STATIC_LIBRARY
BUILD_STATIC_LIBRARY與BUILD_SHARED_LIBRARY類(lèi)似,但用來(lái)生成目標靜態(tài)庫。靜態(tài)庫不會(huì )被拷貝至你的project/packages文件夾下,但可用來(lái)生成共享庫。
例如:
include$(BUILD_STATIC_LIBRARY)
注意:這會(huì )生成一個(gè)靜態(tài)庫,名叫lib$(LOCAL_MODULE).a的靜態(tài)庫。
2.2.2.3.BUILD_PACKAGE
BUILD_PACKAGE變量用于在最好編譯時(shí)生成*.apk,例如:
include$(BUILD_STATIC_LIBRARY)
注意:這會(huì )生成一個(gè)apk安裝包,名字就叫$(LOCAL_MODULE).apk的安裝包。
2.2.3.其它變量
2.2.3.1.CLEAR_VARS
CLEAR_VARS變量是生成系統提供的,它指向一個(gè)特殊的GNU Makefile,它將會(huì )為你自動(dòng)清除許多名為L(cháng)OCAL_XXX的變量(比如:LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等),但LOCAL_PATH是例外,它不會(huì )被清除。
注意:這些變量的清除是必須的,因為所有的控制文件是在單一的Makefile,執行環(huán)境中解析的,在這里所有的變量都是全局的。
2.2.3.2.TARGET_PLATFORM
TARGET_PLATFORM:當解析該Android.mk文件時(shí)用它來(lái)指定Andoid目標平臺的名稱(chēng)。例如:android-3與Android 1.5相對應。
2.2.4.NDK提供的宏函數
下面是GNU Make的宏函數,必須通過(guò)這樣的形式調用:
$(call<function>)
2.2.4.1.my-dir
my-dir:返回放置當前Android.mk的文件夾相對于NDK生成系統根目錄的路徑??捎脕?lái)在A(yíng)ndroid.mk的開(kāi)始處定義LOCAL_PATH的值:
LOCAL_PATH := $(callmy-dir)
2.2.4.2.all-subdir-makefiles
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 $(callall-subdir-makefiles)
那么,它將會(huì )自動(dòng)地包含sources/foo/lib1/Android.mk和
sources/foo/lib2/Android.mk。這個(gè)函數能將深層嵌套的代碼文件夾提供給生成系統。
注意:默認情況下,NDK僅在source/*/Android.mk里尋找文件。
2.2.4.3.this-makefile
this-makefile:返回當前Makefile所在目錄的路徑。
2.2.4.4.parent-makefile
parent-makefile:返回父Makefile所在目錄makefile的路徑。
2.2.4.5.import-module
一個(gè)允許你通過(guò)名字找到并包含另一個(gè)模塊的的Android.mk的功能,例如:
$(callimport-module,<name>)
這將會(huì )找到通過(guò)NDK_MODULE_PATH環(huán)境變量引用的模塊<name>的目錄列表,并且將其自動(dòng)包含到Android.mk中。