1、編譯進內核的模塊
如果需要將一個模塊配置進內核,需要在makefile中進行配置:
obj-y += foo.o
2、編譯可加載的模塊
所有在配置文件中標記為-m的模塊將被編譯成可加載模塊.ko文件。
如果需要將一個模塊配置為可加載模塊,需要在makefile中進行配置:
obj-m += foo.o
3、模塊編譯依賴多個文件
通常的,驅動開發者也會將單獨編譯自己開發的驅動模塊,當一個驅動模塊依賴多個源文件時,需要通過以下方式來指定依賴的文件: obj-m += foo.o foo-y := a.o b.o c.o foo.o 由a.o,b.o,c.o生成,然后調用$(LD) -r 將a.o,b.o,c.o鏈接成foo.o文件。
4、編譯選項
在內核態,編譯的選項由EXTRA_CFLAGS, EXTRA_AFLAGS和 EXTRA_LDFLAGS修改成了ccflags-y asflags-y和ldflags-y.
ccflags-y asflags-y和ldflags-y這三個變量的值分別對應編譯、匯編、鏈接時的參數。
5、最簡單的makefile
obj-m+=hello.o all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
這個makefile的作用就是編譯hello.c文件,最終生成hello.ko文件。
obj-m+=hello.o obj-m表示編譯生成可加載模塊。 相對應的,obj-y表示直接將模塊編譯進內核。 obj-m+=hello.o,這條語句就是顯式地將hello.o編譯成hello.ko,而hello.o則由make的自動推導功能編譯hello.c文件生成。 -C選項:此選項指定make在編譯時將會進入指定的目錄(內核源碼目錄)。 modules是將源文件編譯並生成內核模塊。 $KDIR:/lib/modules/$(shell uname -r)/build/,指定內核源碼的位置。 M=$(PWD):需要編譯的模塊源文件地址。
6、同時編譯多個可加載模塊
當一個.o目標文件的生成依賴多個源文件時,可以這樣指定: obj-m += hello.o hello-y := a.o b.o hello_world.o hello.o目標文件依賴於a.o,b.o,hello_world.o,那么這里的a.o和b.o如果沒有指定源文件,
根據推導規則就是依賴源文件a.c,b.c,hello_world.c. 除了hello-y,同時也可以用hello-objs,實現效果是一樣的。
同時編譯多個可加載模塊 kbuild支持同時編譯多個可加載模塊,也就是生成多個.ko文件,它的格式是這樣的: obj-m := foo.o bar.o foo-y := <foo_srcs> bar-y := <bar_srcs> 就是這么簡單。
7、ifneq ($(KERNELRELEASE),)
通常,標准的makefile會寫成這樣: ifneq ($(KERNELRELEASE),) obj-m := hello.o else KDIR ?= /lib/modules/`uname -r`/build all: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M=$(PWD) clean endif
為什么要添加一個ifneq,else,all條件判斷。
這得從linux內核模塊make執行的過程說起:當鍵入make時,make在當前目錄下尋找makefile並執行,KERNELRELEASE在頂層的makefile中被定義,
所以在執行當前makefile時KERNELRELEASE並沒有被定義,走else分支,直接執行
$(MAKE) -C $(KDIR) M=$(PWD) modules
而這條指令會進入到$(KDIR)目錄,調用頂層的makefile,在頂層makefile中定義了KERNELRELEASE變量.
在頂層makefile中會遞歸地再次調用到當前目錄下的makefile文件,這時KERNELRELEASE變量已經非空,所以執行if分支,
在可加載模塊編譯列表添加hello模塊,由此將模塊編譯成可加載模塊放在當前目錄下。
歸根結底,各級子目錄中的makefile文件的作用就是先切換到頂層makefile,然后通過obj-m在可加載模塊編譯列表中添加當前模塊,
kbuild就會將其編譯成可加載模塊。如果是直接編譯整個內核源碼,就省去了else分支中進入頂層makefile的步驟。
需要注意的一個基本概念是:每一次編譯,頂層makefile都試圖遞歸地進入每個子目錄調用子目錄的makefile,
只是當目標子目錄中沒有任何修改時,默認不再進行重復編譯以節省編譯時間。
8、頭文件的放置
當編譯的目標模塊依賴多個頭文件時,kbuild對頭文件的放置有這樣的規定: • 直接放置在makefile同在的目錄下,在編譯時當前目錄會被添加到頭文件搜索目錄。 • 放置在系統目錄,這個系統目錄是源代碼目錄中的include/linux/。 • 與通用的makefile一樣,使用-I$(DIR)來指定,不同的是,代表編譯選項的變量是固定的,為ccflag. • 一般的用法是這樣的: ccflags-y := -I$(DIR)/include kbuild就會將$(DIR)/includ目錄添加到編譯時的頭文件搜索目錄中。
9、簡單用戶態makefile實例
#sample Makefile edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o