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

1、引文

前篇博文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

2、追蹤

既然模塊文件夾下的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/

 

3、真相:Linux Kbuild子系統

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

4、根本解決(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內核模塊拷貝到原模塊目錄。

相關文章
相關標籤/搜索