Android Makefile分析
首先是可能用得到的基礎(chǔ)知識(shí),必須了解基礎(chǔ)Makefile的語(yǔ)法,然后下面是Andriod用來(lái)編譯相應(yīng)模塊使用的核心makefile,當(dāng)然如果要速成的話也可以不看這些東西,直接按照后面的例子添加就可以了:
???? 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
???? 編寫可執(zhí)行文件基本上和.so是差不多的,現(xiàn)在分為兩類來(lái)仔細(xì)講一下,一類是prebuilt files的編譯,另外就是.so/.a/elf的編譯。
???? 在所有這許makefile中最重要的是base_rules.mk,它是對(duì)module進(jìn)行處理的核心過(guò)程,下面先看看這個(gè)文件的內(nèi)容:
??????
每個(gè)模塊在編譯的時(shí)候都會(huì)產(chǎn)生一個(gè)編譯目錄和一個(gè)安裝目錄,編譯目錄就是這個(gè)模塊編譯以后生成的目標(biāo)文件,安裝目錄就代表著這個(gè)模塊是否會(huì)編譯進(jìn)文件系統(tǒng),就是是否編譯進(jìn)IMG啦~~在base_rules.mk提供了兩個(gè)變量來(lái)定義你要輸出的目錄,仔細(xì)弄懂對(duì)你了解編譯后的生成目錄是很有幫助的~~
????? 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就是你要生成的編譯目標(biāo)啦,如果本地模塊指定了LOCAL_MODULE_STEM的話,它的值就是$(LOCAL_MODULE_STEM)$(LOCAL_MODULE_SUFFIX),如果沒(méi)有指定了的話就是$(LOCAL_MODULE)$(LOCAL_MODULE_SUFFIX)。由此可以看到LOCAL_MODULE的定義是很有講究的,比如什么*.so,一般*就用來(lái)作模塊名。LOCAL_MODULE_SUFFIX在編譯不同的模塊時(shí),GOOGLE內(nèi)置會(huì)給你加上相應(yīng)的值,如果你不了解的話還是盡量自己來(lái)指定,不然可能編譯出來(lái)的東西被篡改了文件名哦噢~~
????? 將編譯目錄的文件拷貝到安裝目錄就是我們的LOCAL_INSTALLED_MODULE了,是否會(huì)安裝就要看你定義的 LOCAL_MODULE_TAGS了,當(dāng)然你也可以通過(guò)修改LOCAL_MODULE_PATH來(lái)自定義安裝。LOCAL_MODULE_PATH是有個(gè)很有用的變量,首先我們看看當(dāng)我們?cè)诒镜啬K沒(méi)有指定這個(gè)值的時(shí)候,它的值實(shí)際上是:LOCAL_MODULE_PATH := $($(my_prefix)OUT$(use_data)_$(LOCAL_MODULE_CLASS)),如果你的模塊定義了TAGS := TESTS則user_data的值是DATA,這樣的模塊會(huì)被安裝在data/目錄下,那么通過(guò)替換我們就知道這個(gè)LOCAL_MODULE_PATH := TARGET_OUT_$(LOCAL_MODULE_CLASS)。這個(gè)LOCAL_MODULE_CLASS在特定的類型編譯會(huì)被google賦值成固定內(nèi)容,但是在prebuilt的編譯中它是由你自己來(lái)賦值的,它的值就會(huì)用來(lái)定義生成的目錄,比如LOCAL_MODULE_CLASS := ETC的時(shí)候,則就會(huì)被安裝在/system/etc目錄。那么我們就知道如何來(lái)定義prebuilt模塊里面的CLASS了,google還提供了一個(gè) LOCAL_MODULE_SUBDIR可以讓你來(lái)定義子目錄,但是要記得的是在每個(gè)模塊的最后要將這個(gè)值清空,因?yàn)槟J(rèn)CLEAR_VARS是不會(huì)清空這個(gè)值的。
????? 當(dāng)然前面說(shuō)的是LOCAL_MODULE_PATH的默認(rèn)值,我們可以通過(guò)給它賦值來(lái)強(qiáng)制指定安裝的目錄,比如說(shuō)要安裝在system/etc /permissions目錄,則可以強(qiáng)制指定它的值為$(TARGET_OUT_ETC)/permissions,這樣模塊就會(huì)被強(qiáng)制安裝在這個(gè)目錄了,給LOCAL_MODULE_PATH賦值的情況主要應(yīng)用在prebuilt模塊的編譯上,其他的應(yīng)該盡量采用其默認(rèn)值。
????? 下面我們就具體看看我寫的一個(gè)如何編譯自己的.so *.a elf的例子,具體能使用到的變量,和要注意的地方我都寫出來(lái)了:
?????????
這里要說(shuō)明的是這個(gè)prelink,prelinke只有在編譯.so的時(shí)候才會(huì)有的選項(xiàng),主要是通過(guò)預(yù)鏈接的方式來(lái)加快程序啟動(dòng)和執(zhí)行的速度,如果你的本地模塊prelink是真的話,那你要在build/core/prelink-linux-arm.map中定義你的庫(kù)需要使用的空間,空間不夠的話會(huì)報(bào)錯(cuò)(具體使用沒(méi)仔細(xì)研究過(guò))
?????? 下面再看看如何來(lái)將我們自己的prebuilt files編譯進(jìn)工程,先讓我們和這個(gè)相關(guān)的最重要的兩個(gè)makefile:
????????
multi_prebuilt.mk只用來(lái)加入需要加入的各種庫(kù),仔細(xì)注意它里面的那個(gè)對(duì)加入文件進(jìn)行處理的函數(shù),尤其是 LOCAL_MODULE,LOCAL_MODULE_SUFFIX ,LOCAL_SRC_FILES這3個(gè)變量是如何得到的,使用multi_prebuilt編譯進(jìn)工程的文件都會(huì)自動(dòng)打上USER的tag。而且它最后還是會(huì)掉用prebuilt.mk來(lái)執(zhí)行真正的編譯操作。
??????? prebuilt.mk實(shí)際上可以編譯任何文件到我們的工程中,下面是我寫的一個(gè)例子,可以自動(dòng)將目錄下相應(yīng)格式的文件編譯進(jìn)工程:
??????
此外添加prebuilt.mk也有一個(gè)粗暴的方式,可以通過(guò)下面的規(guī)則簡(jiǎn)單的將所有prebuilt files添加到你工程中去,必須一個(gè)一個(gè)添加:
??????? 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)
在最后說(shuō)一下Android對(duì)模塊唯一性檢測(cè)的規(guī)則,在base_rules.mk里面通過(guò)module_id里來(lái)檢測(cè)這個(gè)模塊是否已經(jīng)存在,我們看看這個(gè)值是如何定義的:
module_id := MODULE.$(if /
??? $(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
所以它是通過(guò)LOCAL_MODULE_CLASS和LOCAL_MODULE這兩個(gè)變量來(lái)檢測(cè)模塊的唯一性,因此當(dāng)你定義同一樣的CLASS和 MODULE的時(shí)候,Android就會(huì)報(bào)錯(cuò),提示模塊必須是唯一的。因此如果你將LOCAL_MODULE_CALSS進(jìn)行修改,使用 LOCAL_MODULE_PATH來(lái)指定安裝目錄的時(shí)候就會(huì)逃過(guò)Android對(duì)模塊唯一性的檢測(cè),但是這樣導(dǎo)致的問(wèn)題就是同一個(gè)目標(biāo)會(huì)有多個(gè)規(guī)則來(lái)實(shí)現(xiàn)它,而且每個(gè)規(guī)則都是相同的命令。這樣導(dǎo)致的結(jié)果就是MAKE會(huì)將所有的依賴放在一起,然后使用命令來(lái)將其生成目標(biāo),這樣是非常危險(xiǎn)的,會(huì)造成庫(kù)的覆蓋,而且很多時(shí)候你不知道它就究竟使用的是哪個(gè)依賴來(lái)最終生成目標(biāo),只能用md5sum來(lái)檢查。
????? 因此當(dāng)你使用prebuilt來(lái)覆蓋系統(tǒng)原有的文件的時(shí)候應(yīng)該特別小心,如果你確認(rèn)你的文件在覆蓋系統(tǒng)原有文件以后系統(tǒng)能正常運(yùn)行的話,好的方法是還是打開Android對(duì)module_id的檢測(cè),同時(shí)把原來(lái)生成這個(gè)文件的Makefile進(jìn)行修改,讓其不編譯出這個(gè)文件~
????? 最后補(bǔ)充一個(gè)Android如何來(lái)存放模塊的編譯中間文件:
1、如果你的LOCAL_MODULE_CLASS包含COMMON_MODULE_CLASS := JAVA_LIBRARIES NOTICE_FILES,則你編譯出的中間文件會(huì)放在:
?? $(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,則你編譯出的中間文件會(huì)放在:
???? $(TARGET__OUT_INTERMEDIATES)/$(LOCAL_MODULE_CLASS)/$(LOCAL_MODULE)_intermediates/
TARGET_OUT_INTERMEDIATES := out/target/product/msm7627_ffa/ob
總結(jié)
以上是生活随笔為你收集整理的Android Makefile分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 内存管理和垃圾回收
- 下一篇: Hotspot垃圾回收