android NDK編譯 中文版2

(2012-07-24 15:47:05)分類:androidLOCAL_NO_MANIFEST如果你的Package沒有Manifest(AndroidManifest.xml),你可以設置LOCAL_NO_MANIFEST:=true.------分隔符,方便下次編輯修改------If your packagedoesn"t have a manifest (AndroidManifest.xml), thensetLOCAL_NO_MANIFEST:=true.The common resourcespackage does this.LOCAL_PACKAGE_NAMELOCAL_PACKAGE_NAME變數是一個App的名字,例如:Dialer、Contacts等等。它可能在我們使用ant編譯系統編譯App時會發生改變。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_PATHLOCAL_PATH := $(callmy-dir):每個Android.mk文件都必須以定義LOCAL_PATH變數開始,其目的是為了定位源文件的位置。例如:LOCAL_PATH :=$(my-dir)my-dir宏函數使用的是MAKEFILE_LIST變數,你必須在include其它任何makefile之前來調用它。另外,考慮到當你include任何子目錄時都要重新設置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_EXECUTABLESLOCAL_PREBUILT_EXECUTABLES預編譯including$(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要複製的可執行文件。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_LIBSLOCAL_PREBUILT_LIBS變數是在預編譯including$(BUILD_PREBUILT)或者$(BUILD_HOST_PREBUILT)時所用,指定需要複製的庫.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_LIBRARIESLOCAL_SHARED_LIBRARIES變數用來列出模塊所需的共享庫的列表,不需要加上.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 := libutilslibuilibaudiolibexpatlibsglLOCAL_SRC_FILESLOCAL_SRC_FILES變數必須包含一系列將被構建和組合成模塊的C/C++源文件。注意:不需要列出頭文件或include文件,因為生成系統會為你自動計算出源文件的依賴關係。默認的C++源文件的擴展名是.cpp,但你可以通過定義LOCAL_DEFAULT_EXTENSION來指定一個擴展名。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.cppdir/file2.cppLOCAL_STATIC_LIBRARIESLOCAL_STATIC_LIBRARIES變數和LOCAL_SHARED_LIBRARIES類似,用來列出你的模塊中所需的靜態庫的列表,你可以在你的module中包含一些想使用的靜態庫,通常我們使用共享庫,但是有些地方,像在sbin下的可執行程序和主機上的可執行程序我們要使用靜態庫。例如: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 := libutilslibtinyxmlLOCAL_MODULELOCAL_MODULE變數必須定義,用來標識在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。如果有其它moudle中已經定義了該名稱,那麼你在編譯時就會報類似這樣的錯誤:libgl2jnialready defined by frameworks/base/opengl/tests/gl2_jni/jni.Stop.下面就是該錯誤的截圖:

接下來就是修改你的module的名字了,或者找到跟你重名的module把它幹掉,但不建議你那麼做,因為有可能會帶來未知的錯誤(你修改了別人的module的名字,而別人不一定知道,當他再編譯或者做其它時,就會出錯)。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).注意:編譯系統會自動產生合適的前綴和後綴,例如:LOCAL_MODULE :=screenshot一個被命名為「screenshot」的共享庫模塊,將會生成「libscreenshot.so」文件。補充1:變數命名的規範性如果LOCAL_MODULE變數定義的值可能會被其它module調用時,就要考慮為其變數命名的規範性了。特別是在使用JNI時,既在LOCAL_JNI_SHARED_LIBRARIES變數中定義的值,最好要和LOCAL_MODULE變數定義的值保存一致(具體請參考LOCAL_JNI_SHARED_LIBRARIES變數的使用說明)。這時的LOCAL_MODULE變數的命名最好以lib開頭,既「libxxx」,例如:LOCAL_MODULE :=libscreenshotLOCAL_MODULE_PATH通知編譯系統將module放到其它地方而不是它通常的類型。如果你重寫這個變數,確保你還要再設置LOCAL_UNSTRIPPED_PATH變數的值。如果你忘了設置LOCAL_UNSTRIPPED_PATH變數的值的話,就會報錯。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_LIBRARIESLOCAL_WHOLE_STATIC_LIBRARIES指定模塊所需要載入的完整靜態庫(這些靜態庫在鏈接是不允許鏈接器刪除其中無用的代碼)。通常這在你想往共享庫中增加一個靜態庫時是非常有用的,共享庫就會接受到靜態庫暴露出的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_androidLOCAL_REQUIRED_MODULESLOCAL_REQUIRED_MODULES指定模塊運行所依賴的模塊(模塊安裝時將會同步安裝它所依賴的模塊)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_MODULELOCAL_PRELINK_MODULE變數用來規定是否需要預連接處理(默認需要,用來做動態庫優化)。LOCAL_PRELINK_MODULE只有在編譯.so的時候才會有的選項,主要是通過預鏈接的方式來加快程序啟動和執行的速度,如果在你的代碼(/jni/Android.mk)中有下面一條語句:LOCAL_PRELINK_MODULE:= true那麼你要在build/core/prelink-linux-arm.map中定義你的庫所需要使用的空間,如果不定義或者空間不夠的話,在編譯的時候就會報錯。如下圖所示:

當在build/core/prelink-linux-arm.map中定義了我們這裡使用的libhello-jni.so庫的空間之後,既在該文件中加入一條語句:libhello-jni.so0x99E00000注意:在prelink-linux-arm.map文件的開頭部分有明確的規定,指定的內存取值範圍分配給不同的部分使用,而我們的App的庫也給指定了一個範圍:0x90000000 -0x9FFFFFFF Prelinked App Libraries重新編譯,就不會再報錯了,下面的截圖中很清晰地看到已經將libhello-jni.so庫預編譯成功了:

注意:在給我們的應用庫分配地址空間時,最好以1M為邊界,地址空間大小按照由大到小的降序進行排序。下面是對於Prelink的說明:Prelink利用事先鏈接代替運行時鏈接的方法來加速共享庫的載入,它不僅可以加快起動速度,還可以減少部分內存開銷。程序運行時的動態鏈接尤其是重定位(relocation)的開銷對於大型系統來說是很大的。動態鏈接和載入的過程開銷很大,並且在大多數的系統上,函數庫並不會常常被更動,每次程序被執行時所進行的鏈接動作都是完全相同的,對於嵌入式系統來說尤其如此。因此,這一過程可以改在運行時之前就可以預先處理好,即花一些時間利用Prelink工具對動態共享庫和可執行文件進行處理,修改這些二進位文件並加入相應的重定位等信息,節約了本來在程序啟動時的比較耗時的查詢函數地址等工作,這樣可以減少程序啟動的時間,同時也減少了內存的耗用。Prelink的這種做法當然也有代價的,每次更新動態共享庫時,相關的可執行文件都需要重新執行一遍Prelink才能保證有效,因為新的共享庫中的符號信息、地址等很可能與原來的已經不同了,這就是為什麼androidframework代碼一改動,這時候就會導致相關的應用程序重新被編譯。LOCAL_JNI_SHARED_LIBRARIESLOCAL_JNI_SHARED_LIBRARIES變數主要是用在JNI的編譯中,如果你要在你的Java代碼中引用JNI中的共享庫*.so,此變數就是共享庫的名字。那麼你要注意的一點是:在你的Project根目錄下的Android.mk中要定義此變數用來引用你要使用的JNI中的共享庫*.so。例如:$(Project)/Android.mkLOCAL_JNI_SHARED_LIBRARIES :=libsanangeles而在你的jni目錄下的Android.mk中則要定義LOCAL_MODULE變數的值,一定要讓這兩個變數的值相同。假如你沒有這麼做,而是像這樣:$(Project)/jni/Android.mkLOCAL_MODULE :=sanangeles那麼,在編譯的時候就會出現下圖的錯誤:

這說明在編譯libsanangeles.so找不到其規則,因為在上面的代碼中定義的是sanangeles。重新修改LOCAL_MODULE變數的值:$(Project)/jni/Android.mkLOCAL_MODULE :=libsanangeles即可正常編譯。LOCAL_EXPORT_CFLAGS定義這個變數用來記錄C/C++編譯器標誌集合,並且會被添加到其他任何以LOCAL_STATIC_LIBRARIES和LOCAL_SHARED_LIBRARIES的模塊的LOCAL_CFLAGS定義中。例如:這樣定義"foo"模塊:foo/Android.mkinclude$(CLEAR_VARS)LOCAL_MODULE:=fooLOCAL_SRC_FILES:=foo/foo.cLOCAL_EXPORT_CFLAGS:=-DFOO=1include$(BUILD_STATIC_LIBRARY)另一個模塊,叫做"bar",並且依賴於上面的模塊:bar/Android.mkinclude$(CLEAR_VARS)LOCAL_MODULE:=barLOCAL_SRC_FILES:=bar.cLOCAL_CFLAGS:=-DBAR=2LOCAL_STATIC_LIBRARIES:=fooinclude$(BUILD_SHARED_LIBRARY)然後,當編譯bar.c的時候,標誌"-DFOO=1 -DBAR=2"將被傳遞到編譯器。輸出的標誌被添加到模塊的LOCAL_CFLAGS上,所以你可以很容易重寫它們。它們也有傳遞性:如果"zoo"依賴"bar",「bar」依賴"foo",那麼"zoo"也將繼承"foo"輸出的所有標誌。最後,當編譯模塊輸出標誌的時候,這些標誌並不會被使用。在上面的例子中,當編譯foo/foo.c時,-DFOO=1將不會被傳遞給編譯器。LOCAL_EXPORT_CPPFLAGS類似LOCAL_EXPORT_CFLAGS,但適用於C++標誌。具體請參考LOCAL_EXPORT_CFLAGS條目。LOCAL_EXPORT_C_INCLUDES類似LOCAL_EXPORT_CFLAGS,但是只有C能包含路徑,如果"bar.c"想包含一些由"foo"模塊提供的頭文件的時候這會很有用。具體請參考LOCAL_EXPORT_CFLAGS條目。LOCAL_EXPORT_LDLIBS類似於LOCAL_EXPORT_CFLAGS,但是只用於鏈接標誌。注意,引入的鏈接標誌將會被追加到模塊的LOCAL_LDLIBS,這是由UNIX連接器的工作方式決定的。當模塊foo是一個靜態庫的時候並且代碼依賴於系統庫時會很有用的。LOCAL_EXPORT_LDLIBS可以用於輸出依賴,例如:#Frist build thestatic library libfoo.ainclude$(CLEAR_VARS)LOCAL_MODULE :=fooLOCAL_SRC_FILES :=foo/foo.cLOCAL_EXPORT_LDLIBS:= -lloginclude$(BUILD_STATIC_LIBRARY)#Then build theshared library libbar.soinclude$(CLEAR_VARS)LOCAL_MODULE :=barLOCAL_SRC_FILES :=bar.cLOCAL_STATIC_LIBRARIES := fooinclude$(BUILD_SHARED_LIBRARY)這裡,在連接器命令最後,libbar.so將以」-llog」參數進行編譯來表明它依賴於系統日誌庫,因為它依賴於foo。LOCAL_ALLOW_UNDEFINED_SYMBOLS默認情況下,當試圖編譯一個共享庫的時候遇到任何未定義的引用都可能導致"未定義符號"(undefinedsymbol)的錯誤。這在你的源代碼中捕獲bug會很有用。然而,但是由於某些原因,你需要禁用此檢查的話,設置變數為"true"即可。需要注意的是,相應的共享庫在運行時可能載入失敗。LOCAL_ARM_MODELOCAL_ARM_MODE變數主要是應用與嵌入式產品的編譯系統中,可以指定為arm模式。例如:LOCAL_ARM_MODE :=arm注意:你需要執行編譯系統為在ARM模式下通過文件的名字增加後綴的方式編譯指定的源文件。例如:LOCAL_SRC_FILES:=foo.c bar.c.arm這會告訴編譯系統一直以ARM模式編譯"bar.c",並且通過LOCAL_ARM_MODE的值編譯foo.c。2.2.2.BUILD_XXX變數2.2.2.1.BUILD_SHARED_LIBRARYBUILD_SHARED_LIBRARY:指明要編譯生成動態共享庫。指向一個生成腳本,這個腳本通過LOCAL_XXX變數收集關於組件的信息,並決定如何根據你列出來的源文件生成目標共享庫。注意:在include這個腳本文件之前你必須至少已經定義了LOCAL_MODULE和LOCAL_SRC_FILES。例如:include$(BUILD_SHARED_LIBRARY)注意:這會生成一個名為lib$(LOCAL_MODULE).so的動態庫。2.2.2.2.BUILD_STATIC_LIBRARYBUILD_STATIC_LIBRARY與BUILD_SHARED_LIBRARY類似,但用來生成目標靜態庫。靜態庫不會被拷貝至你的project/packages文件夾下,但可用來生成共享庫。例如:include$(BUILD_STATIC_LIBRARY)注意:這會生成一個靜態庫,名叫lib$(LOCAL_MODULE).a的靜態庫。2.2.2.3.BUILD_PACKAGEBUILD_PACKAGE變數用於在最好編譯時生成*.apk,例如:include$(BUILD_STATIC_LIBRARY)注意:這會生成一個apk安裝包,名字就叫$(LOCAL_MODULE).apk的安裝包。2.2.3.其它變數2.2.3.1.CLEAR_VARSCLEAR_VARS變數是生成系統提供的,它指向一個特殊的GNU Makefile,它將會為你自動清除許多名為LOCAL_XXX的變數(比如:LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIES等),但LOCAL_PATH是例外,它不會被清除。注意:這些變數的清除是必須的,因為所有的控制文件是在單一的Makefile,執行環境中解析的,在這裡所有的變數都是全局的。2.2.3.2.TARGET_PLATFORMTARGET_PLATFORM:當解析該Android.mk文件時用它來指定Andoid目標平台的名稱。例如:android-3與Android 1.5相對應。2.2.4.NDK提供的宏函數下面是GNU Make的宏函數,必須通過這樣的形式調用:$(call<function>)2.2.4.1.my-dirmy-dir:返回放置當前Android.mk的文件夾相對於NDK生成系統根目錄的路徑。可用來在Android.mk的開始處定義LOCAL_PATH的值:LOCAL_PATH := $(callmy-dir)2.2.4.2.all-subdir-makefilesall-subdir-makefiles:返回my-dir子目錄下的所有Android.mk。例如:代碼的結構如下:sources/foo/Android.mksources/foo/lib1/Android.mksources/foo/lib2/Android.mk如果sources/foo/Android.mk里有這樣一行:include $(callall-subdir-makefiles)那麼,它將會自動地包含sources/foo/lib1/Android.mk和sources/foo/lib2/Android.mk。這個函數能將深層嵌套的代碼文件夾提供給生成系統。注意:默認情況下,NDK僅在source/*/Android.mk里尋找文件。2.2.4.3.this-makefilethis-makefile:返回當前Makefile所在目錄的路徑。2.2.4.4.parent-makefileparent-makefile:返回父Makefile所在目錄makefile的路徑。2.2.4.5.import-module一個允許你通過名字找到並包含另一個模塊的的Android.mk的功能,例如:$(callimport-module,<name>)這將會找到通過NDK_MODULE_PATH環境變數引用的模塊<name>的目錄列表,並且將其自動包含到Android.mk中。
推薦閱讀:

Vincents blog: Visual C 編譯器選項設置
經略編譯 | 怒從何來?「劍橋分析」與我們的時代
ffmpeg在centos7上的編譯
TarvisCI 全流程使用實踐(一)
靜態庫編譯

TAG:編譯 | 中文版 | 中文 |