linux內核模塊編譯makefile


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                

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM