Linux Kbuild工作原理分析(以DVSDK生成PowerVR顯卡內核模塊爲例)

一、引文

前篇博文Makefile之Linux內核模塊的Makefile寫法分析》,介紹了Linux編譯生成內核驅動模塊的Makefile的寫法但最近在DVSDK下使用Linux2.6.37生成PowerVR 2D/3D加速器的內核模塊時,發現其Makefile中並未像其他內核模塊Makefile指定內核模塊的目標對象(obj-m:= pvrsrvkm.o),但最後卻在模塊目錄下生成了pvrsrvkm.ko內核模塊。一開始感覺非常奇怪,決定把其中的原由弄明白,並將該過程記錄了下來。

/**********************************************************************************************************************************/

 原創作品,轉載時請務必以超鏈接形式標明文章原始出處:http://blog.csdn.net/gqb666/article/details/9054413,作者:gqb666  
/**********************************************************************************************************************************/

二、追蹤

既然模塊文件夾下的Makefile文件沒有指定,那肯定會有其他有相同功能的文件會指定內核模塊的目標對象pvrsrvkm.o,於是查看該目錄下的文件,果然在Kbuid文件發現有與Makefile文件類似的內容,將Kbuild的關鍵內容貼出來:

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 Kbuild子系統

實際上從Linux內核2.6開始,Linux內核的編譯採用Kbuild系統,這同過去的編譯系統有很大的不同, 尤其對於Linux內核驅動模塊的編譯。在新的系統下,Linux編譯系統會兩次掃描LinuxMakefile:首先編譯系統會讀取Linux內核頂層的Makefile,然後根據讀到的內容第二次讀取KbuildMakefile來編譯Linux內核。

查看內核文檔:../Documentation/kbuild/makefiles.txt我們可以獲取到以下信息:
Linux內核Makefile分類(五類)

·Kernel Makefile 
Kernel Makefile位於Linux內核源代碼的頂層目錄,也叫 Top Makefile。它主要用於指定編譯Linux Kernel目標文件(vmlinux)和模塊(module)。這編譯內核或模塊是,這個文件會被首先 讀取,並根據讀到的內容配置編譯環境變量。對於內核或驅動開發人員來說,這個文件幾乎不用任何修改。

·.config

此文件爲Kbuid構建子系統從..\arch\arm\configs目錄下讀了內核的相關配置或者通過make menuconfig而生成的內核臨時配置文件。
·sripts/Makefile.*

   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文件卻模塊編譯會出錯。這到底是怎麼回事呢?還是跟下代碼流程來分析。

四、根本解決(Linux Kbuild 工作原理)

實際上執行了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內核模塊拷貝到原模塊目錄。

發佈了41 篇原創文章 · 獲贊 38 · 訪問量 42萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章