前篇博文《Makefile之Linux內核模塊的Makefile寫法分析》,介紹了Linux編譯生成內核驅動模塊的Makefile的寫法,但最近在DVSDK下使用Linux2.6.37生成PowerVR 2D/3D加速器的內核模塊時,發現其Makefile中並未向其餘內核模塊Makefile指定內核模塊的目標對象(obj-m:= pvrsrvkm.o),但最後卻在模塊目錄下生成了pvrsrvkm.ko內核模塊。一開始感受很是奇怪,決定把其中的起因弄明白,並將該過程記錄了下來。linux
/**********************************************************************************************************************************/app
原創做品,轉載時請務必以超連接形式標明文章原始出處:http://blog.csdn.net/gqb666/article/details/9054413,做者:gqb666
/**********************************************************************************************************************************/post
既然模塊文件夾下的Makefile文件沒有指定,那確定會有其餘有相同功能的文件會指定內核模塊的目標對象pvrsrvkm.o,因而查看該目錄下的文件,果真在Kbuid文件發現有與Makefile文件相似的內容,將Kbuild的關鍵內容貼出來:ui
obj-m := pvrsrvkm.o FILES := \ services4/srvkm/common/queue.c \ …… services4/system/$(TI_PLATFORM)/sysconfig.c \ EXTRA_CFLAGS += -I$(src)/include4 EXTRA_CFLAGS += -I$(src)/services4/include …… EXTRA_CFLAGS += -I$(src)/services4/srvkm/bridged/sgx EXTRA_CFLAGS += $(ALL_CFLAGS) pvrsrvkm-y := $(FILES:.c=.o) ifeq ($(TI_PLATFORM),ti8168) obj-y := services4/3rdparty/dc_ti8168_linux/ else obj-y := services4/3rdparty/dc_omap3430_linux/ endif obj-y += services4/3rdparty/bufferclass_ti/
實際上從Linux內核2.6開始,Linux內核的編譯採用Kbuild系統,這同過去的編譯系統有很大的不一樣, 尤爲對於Linux內核驅動模塊的編譯。在新的系統下,Linux編譯系統會兩次掃描Linux的Makefile:首先編譯系統會讀取Linux內核頂層的Makefile,而後根據讀到的內容第二次讀取Kbuild的Makefile來編譯Linux內核。spa
查看內核文檔:../Documentation/kbuild/makefiles.txt咱們能夠獲取到如下信息:
Linux內核Makefile分類(五類)
·Kernel Makefile
Kernel Makefile位於Linux內核源代碼的頂層目錄,也叫 Top Makefile。它主要用於指定編譯Linux Kernel目標文件(vmlinux)和模塊(module)。這編譯內核或模塊是,這個文件會被首先 讀取,並根據讀到的內容配置編譯環境變量。對於內核或驅動開發人員來講,這個文件幾乎不用任何修改。.net
·.config翻譯
此文件爲Kbuid構建子系統從..\arch\arm\configs目錄下讀了內核的相關配置或者經過make menuconfig而生成的內核臨時配置文件。
·sripts/Makefile.*code
sripts/Makefile.* 包含了使用Kbuild Makefile子系統所用的全部規則的定義。
·Kbuild Makefile
Kbuild系統使用Kbuild Makefile來編譯內核或模塊。當Kernel Makefile被解析完成後,Kbuild會讀取相關的Kbuild Makefile進行內核或模塊的編譯。Kbuild Makefile有特定的語法指定哪些編譯進內核中、哪些編譯爲模塊、及對應的源文件是什麼等。內核及驅動開發人員須要編寫這個Kbuild Makefile文件。
·ARCH Makefile
ARCH Makefile位於ARCH/$(ARCH)/Makefile,是系統對應平臺的Makefile。Kernel Top Makefile會包含這個文件來指定平臺相關信息。只有平臺開發人員會關心這個文件。
Kbuild Makefile的文件名不必定是Makefile,儘管推薦使用Makefile這個名字。 大多的Kbuild文件的名字都是Makefile。爲了與其餘Makefile文件相區別,你也能夠指定Kbuild Makefile的名字爲Kbuild。並且若是「Makefile」和「Kbuild」文件同時存在,則Kbuild系統會使用「Kbuild」文件。
對象
上面的幾句來自對內核文檔的翻譯,然而上面標紅的一段話,通過驗證感受不太準確,博主將模塊目錄中的Makefile刪除,僅留下Kbuild文件卻模塊編譯會出錯。這究竟是怎麼回事呢?仍是跟下代碼流程來分析。blog
實際上執行了make命令後,Kbuild子系統仍是要找到模塊目錄下的Makefile,以下:
all: $(MAKE) -C $(KERNELDIR) M=`pwd` $*
其中 KERNELDIR 變量值爲內核源碼目錄根目錄
可見,Kbuild子系統將進行內核源碼根目錄下去執行make,並將模塊所在的目錄名以參數的形式傳進去。
實際上該過程總共分爲兩個stage:
1.編譯出pvrsrvkm.o文件。
2.生成pvrsrvkm.mod.o pvrsrvkm.ko,並內核模塊文件拷加原模塊目錄。見以下打印log:
make -C /home/ss/ti-dvsdk_dm3730-evm_4_02_00_06/psp/linux-2.6.32-psp03.00.01.06.sdk M=`pwd` Building objects, stage 1. make[3]: Entering directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/psp/linux-2.6.32-psp03.00.01.06.sdk' …… LD [M] /home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/GFX_Linux_KM/pvrsrvkm.o Building modules, stage 2. MODPOST 3 modules CC /home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/GFX_Linux_KM/pvrsrvkm.mod.o LD [M] /home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/GFX_Linux_KM/pvrsrvkm.ko …… make[3]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/psp/linux-2.6.32-psp03.00.01.06.sdk' make[2]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/GFX_Linux_KM' copying the sgx kernel modules to appropriate folder... building devmem2... make -C /home/ss/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2 clean && make -C /home/ss/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2 && make -C /home/ss/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2 install make[2]: Entering directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' rm -rf ./Obj *.o make[2]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' make[2]: Entering directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' mkdir -p ./Obj …… arm-none-linux-gnueabi-g++ -o ./Obj/devmem2 ./Obj/devmem2.o -lm -ldl -L/lib -Wl /usr/local/arm/arm-2009q1/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.3/../../../../arm-none-linux-gnueabi/bin/ld: warning: library search path "/lib" is unsafe for cross-compilation make[2]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' make[2]: Entering directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' cp ./Obj/devmem2 ../../targetfs/ make[2]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01/tools/devmem2' make[1]: Leaving directory `/home/ss/develop_environment/v2/sys/dvsdk/ti-dvsdk_dm3730-evm_4_02_00_06/omap35x_graphics_sdk_4.00.00.01'
stage 1:
內核Makefile根據時間戳進行比較看哪些目標文件須要編譯,這個過程將生成pvrsrvkm.o文件。
stage 2:
這個obj-m :pvrsrvkm.o何時會執行到呢?
在執行:
$(MAKE) -C $(KERNELDIR) M=`pwd` $*
時,Kbuild去內核根目錄下的Makefile中尋找目標modules,代碼貼上:
PHONY += modules modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order @$(kecho) ' Building modules, stage 2.'; $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
在這過程當中,會調用
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
而在 scripts/Makefile.modpost中會包含不少文件如:
include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile)
由上面可看出:內核根目錄Makefile至關於以頭文件的形式包含了模塊目錄下的Kbuild文件和Makefile
因此執行的是:obj-m:=pvrsrvkm.o
進而pvrsrvkm.mod.o pvrsrvkm.ko也就生成了,最後又將pvrsrvkm.ko內核模塊拷貝到原模塊目錄。