Android.mk for your own module 收藏
這里我們向Android中添加自己的模塊,只涉及到.so/*.a/elf source的編譯,以及如何將prebuilt file添加進工程。對于APK以及jar的source暫時沒有仔細研究,要添加進去的話可以參照/pacakge和/framework 里面的Android.mk ~~ 首先是可能用得到的基礎知識,必須了解基礎Makefile的語法,然后下面是Andriod用來編譯相應模塊使用的核心makefile,當然如果要速成的話也可以不看這些東西,直接按照后面的例子添加就可以了: 1、prebuilt /build/core/base_rules.mk /build/core/prebuilt.mk /build/core/multi_prebuilt.mk 2、.so/ /build/core/base_rules.mk /build/core/shared_library.mk /build/core/dynamic_library.mk /build/core/binary.mk 3、.a /build/core/base_rules.mk /build/core/static_library.mk /build/core/binary.mk 編寫可執行文件基本上和.so是差不多的,現在分為兩類來仔細講一下,一類是prebuilt files的編譯,另外就是.so/.a/elf的編譯。 在所有這許makefile中最重要的是base_rules.mk,它是對module進行處理的核心過程,下面先看看這個文件的內容: ![]() 每個模塊在編譯的時候都會產生一個編譯目錄和一個安裝目錄,編譯目錄就是這個模塊編譯以后生成的目標文件,安裝目錄就代表著這個模塊是否會編譯進文件系統,就是是否編譯進IMG啦~~在base_rules.mk提供了兩個變量來定義你要輸出的目錄,仔細弄懂對你了解編譯后的生成目錄是很有幫助的~~
built_module_path := $(intermediates) LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM) LOCAL_INSTALLED_MODULE := $(LOCAL_MODULE_PATH)/$(LOCAL_MODULE_SUBDIR)$(LOCAL_INSTALLED_MODULE_STEM) built_module_path是編譯生成的中間文件所在的目錄,LOCAL_BUILT_MODULE_STEM就是你要生成的編譯目標啦,如果本地模塊指定了LOCAL_MODULE_STEM的話,它的值就是$(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX),如果沒有指定了的話就是$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)。由此可以看到LOCAL_MODULE的定義是很有講究的,比如什么*.so,一般*就用來作模塊名。LOCAL_MODULE_SUFFIX在編譯不同的模塊時,GOOGLE內置會給你加上相應的值,如果你不了解的話還是盡量自己來指定,不然可能編譯出來的東西被篡改了文件名哦噢~~ 將編譯目錄的文件拷貝到安裝目錄就是我們的LOCAL_INSTALLED_MODULE了,是否會安裝就要看你定義的 LOCAL_MODULE_TAGS了,當然你也可以通過修改LOCAL_MODULE_PATH來自定義安裝。LOCAL_MODULE_PATH是有個很有用的變量,首先我們看看當我們在本地模塊沒有指定這個值的時候,它的值實際上是:LOCAL_MODULE_PATH := $($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),如果你的模塊定義了TAGS := TESTS則user_data的值是DATA,這樣的模塊會被安裝在data/目錄下,那么通過替換我們就知道這個LOCAL_MODULE_PATH := TARGET_OUT_$(LOCAL_MODULE_CLASS)。這個LOCAL_MODULE_CLASS在特定的類型編譯會被google賦值成固定內容,但是在prebuilt的編譯中它是由你自己來賦值的,它的值就會用來定義生成的目錄,比如LOCAL_MODULE_CLASS := ETC的時候,則就會被安裝在/system/etc目錄。那么我們就知道如何來定義prebuilt模塊里面的CLASS了,google還提供了一個 LOCAL_MODULE_SUBDIR可以讓你來定義子目錄,但是要記得的是在每個模塊的最后要將這個值清空,因為默認CLEAR_VARS是不會清空這個值的。 當然前面說的是LOCAL_MODULE_PATH的默認值,我們可以通過給它賦值來強制指定安裝的目錄,比如說要安裝在system/etc /permissions目錄,則可以強制指定它的值為$(TARGET_OUT_ETC)/permissions,這樣模塊就會被強制安裝在這個目錄了,給LOCAL_MODULE_PATH賦值的情況主要應用在prebuilt模塊的編譯上,其他的應該盡量采用其默認值。 下面我們就具體看看我寫的一個如何編譯自己的.so *.a elf的例子,具體能使用到的變量,和要注意的地方我都寫出來了: ![]() 這里要說明的是這個prelink,prelinke只有在編譯.so的時候才會有的選項,主要是通過預鏈接的方式來加快程序啟動和執行的速度,如果你的本地模塊prelink是真的話,那你要在build/core/prelink-linux-arm.map中定義你的庫需要使用的空間,空間不夠的話會報錯(具體使用沒仔細研究過)
下面再看看如何來將我們自己的prebuilt files編譯進工程,先讓我們和這個相關的最重要的兩個makefile: ![]() multi_prebuilt.mk只用來加入需要加入的各種庫,仔細注意它里面的那個對加入文件進行處理的函數,尤其是 LOCAL_MODULE,LOCAL_MODULE_SUFFIX ,LOCAL_SRC_FILES這3個變量是如何得到的,使用multi_prebuilt編譯進工程的文件都會自動打上USER的tag。而且它最后還是會掉用prebuilt.mk來執行真正的編譯操作。
prebuilt.mk實際上可以編譯任何文件到我們的工程中,下面是我寫的一個例子,可以自動將目錄下相應格式的文件編譯進工程: ![]() 此外添加prebuilt.mk也有一個粗暴的方式,可以通過下面的規則簡單的將所有prebuilt files添加到你工程中去,必須一個一個添加:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # your prebuilt file name LOCAL_MODULE := example.so LOCAL_MODULE_TAGS := user eng # your prebuilt file (must be relative directory ) LOCAL_SRC_FILES := lib/example.so # the path your prebuilt file will be installed $(TARGET_OUT) is the system directory LOCAL_MODULE_PATH := $(TARGET_OUT)/lib include (BUILD_PREBUILT) 在最后說一下Android對模塊唯一性檢測的規則,在base_rules.mk里面通過module_id里來檢測這個模塊是否已經存在,我們看看這個值是如何定義的:
module_id := MODULE.$(if \
$(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE) 所以它是通過LOCAL_MODULE_CLASS和LOCAL_MODULE這兩個變量來檢測模塊的唯一性,因此當你定義同一樣的CLASS和MODULE的時候,Android就會報錯,提示模塊必須是唯一的。因此如果你將LOCAL_MODULE_CALSS進行修改,使用LOCAL_MODULE_PATH來指定安裝目錄的時候就會逃過Android對模塊唯一性的檢測,但是這樣導致的問題就是同一個目標會有多個規則來實現它,而且每個規則都是相同的命令。這樣導致的結果就是MAKE會將所有的依賴放在一起,然后使用命令來將其生成目標,這樣是非常危險的,會造成庫的覆蓋,而且很多時候你不知道它就究竟使用的是哪個依賴來最終生成目標,只能用md5sum來檢查。
因此當你使用prebuilt來覆蓋系統原有的文件的時候應該特別小心,如果你確認你的文件在覆蓋系統原有文件以后系統能正常運行的話,好的方法是還是打開Android對module_id的檢測,同時把原來生成這個文件的Makefile進行修改,讓其不編譯出這個文件~
最后補充一個Android如何來存放模塊的編譯中間文件:
1、如果你的LOCAL_MODULE_CLASS包含COMMON_MODULE_CLASS := JAVA_LIBRARIES NOTICE_FILES,則你編譯出的中間文件會放在: $(TARGET__OUT_COMMON_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates/ TARGET_OUT_COMMON_INTERMEDIATES := out/target/common/obj 2、如果你的LOCAL_MODULE_CLASS不包含COMMON_MODULE_CLASS,則你編譯出的中間文件會放在: $(TARGET__OUT_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates/ TARGET_OUT_INTERMEDIATES := out/target/product/msm7627_ffa/obj 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/yili_xie/archive/2009/12/09/4971736.aspx
|
|