1. 查看config配置項
進入需要編譯的目錄,我的目錄是 ./net/bridge,
sean@sean:/media/sean/b55f4db0-2560-4807-b8bf-b29a66db54e1/home/sean/work/tmp/kernel/linux-4.8/net/bridge$ ls br.c br_fdb.o bridge.mod.c br_if.o br_ioctl.o br_multicast.o br_netfilter_ipv6.o br_netfilter.o br_nf_core.o br_stp_bpdu.c br_stp_if.o br_sysfs_br.c br_vlan.c Makefile br_device.c br_forward.c bridge.mod.o br_input.c br_mdb.c br_netfilter_hooks.c br_netfilter.ko br_netlink.c br.o br_stp_bpdu.o br_stp.o br_sysfs_br.o br_vlan.o modules.order br_device.o br_forward.o bridge.o br_input.o br_mdb.o br_netfilter_hooks.o br_netfilter.mod.c br_netlink.o br_private.h br_stp.c br_stp_timer.c br_sysfs_if.c built-in.o Module.symvers br_fdb.c bridge.ko br_if.c br_ioctl.c br_multicast.c br_netfilter_ipv6.c br_netfilter.mod.o br_nf_core.c br_private_stp.h br_stp_if.c br_stp_timer.o br_sysfs_if.o Kconfig netfilter sean@sean:/media/sean/b55f4db0-2560-4807-b8bf-b29a66db54e1/home/sean/work/tmp/kernel/linux-4.8/net/bridge$
查看Makefile,找到需要編譯的文件,並確認編譯的config參數,如下:
2. 編譯
命令如下:
make CONFIG_BRIDGE_IGMP_SNOOPING=m -C /home/sean/kernel/linux-4.8 M=/home/sean/kernel/linux-4.8/net/bridge modules 或者 cd /home/sean/kernel/linux-4.8/net/bridge make CONFIG_BRIDGE_IGMP_SNOOPING=m -C /home/sean/kernel/linux-4.8 M=`pwd` modules
然后手動將生成的*.ko拷貝到/lib/modules/2.6.19/kernel/對應的目錄即可。(由於我需要的文件只能編譯為.o,所以不需要拷貝)
運行depmod -a重新配置依賴關系,以后就可以通過modprobe fuse來加載fuse模塊了。
3. make 參數的說明:
$(MAKE) -C $(KDIR) M=$(PWD) modules
-C:后面的參數為linux內核的頂層目錄
M:后面的參數為需要編譯文件的目錄
4. 例子
1)模塊Makefile
ifneq ($(KERNELRELEASE),) obj-m := mytest.o mytest-objs := file1.o file2.o file3.o else KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) M=$(PWD) modules endif
KERNELRELEASE 是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時,KERNELRELEASE沒有被定義,所以make將讀取執行else之后的內容。如果make的目標是clean,直接執行clean操作,然后結束。
當make的目標為modules或modules_install時,-C ( K E R N E L D I R ) 指 明 跳 轉 到 內 核 源 碼 目 錄 下 讀 取 那 里 的 M a k e f i l e ; M = (KERNELDIR)指明跳轉到內核源碼目錄下讀取那里的Makefile;M=(KERNELDIR)指明跳轉到內核源碼目錄下讀取那里的Makefile;M=(PWD) 表明然后返回到當前目錄繼續讀入、執行當前的Makefile。
當從內核源碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啟動去解析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容為kbuild語法的語句, 指明模塊源碼中各文件的依賴關系,以及要生成的目標模塊名。
2)Kconfig與內核Makefile
-
a. 使用Kconfig以及內核的Makefile可以在內核中添加自己的源代碼,並且可以添加內核配置選項,是否編進內核,是否以模塊的方式等;
-
b. 在內核某個目錄的Kconfig文件中可以配置各個選項的含義;在Makefile中指定如果配置了,該如何編譯;
如要在/driver/char中增加一個配置選項CONFIG_FISHING_POLE選項;
在driver/char/Kconfig文件中增加對該選項的說明:
config FISHING_POLE tristate “簡單說明” //tristate代表有三種方式,如為bool代表不能變為模塊 default n //默認是否選擇 help **** //一些幫助信息
在driver/char/Makefile中增加:
obj-$(CONFIG_FISHING_POLE) += fishing.o
如果有多個源文件:
obj-$(CONFIG_FISHING_POLE) += fishing.o
fishing-objs := fishing-main.o fishing-line.o
root@ubuntu:/opt/gopath/src/github.com/kata-containers/packaging/kernel/kata-linux-5.4.60-89/drivers/android# make CONFIG_ANDROID_BINDER_IPC=m -C /opt/gopath/src/github.com/kata-containers/packaging/kernel/kata-linux-5.4.60-89 M=/opt/gopath/src/github.com/kata-containers/packaging/kernel/kata-linux-5.4.60-89/drivers/android make: Entering directory '/opt/gopath/src/github.com/kata-containers/packaging/kernel/kata-linux-5.4.60-89' CC kata-linux-5.4.60-89/drivers/android/binderfs.o CC /kernel/kata-linux-5.4.60-89/drivers/android/binder_alloc_selftest.o AR kernel/kata-linux-5.4.60-89/drivers/android/built-in.a CC [M] kata-linux-5.4.60-89/drivers/android/binder.o CC [M] packaging/kernel/kata-linux-5.4.60-89/drivers/android/binder_alloc.o cat: / kernel/kata-linux-5.4.60-89/drivers/android/modules.order: No such file or directory Building modules, stage 2. MODPOST 0 modules sed: can't read packaging/kernel/kata-linux-5.4.60-89/drivers/android/modules.order: No such file or directory cat: /opt/gopath/src/github.com/kata-containers/packaging/kernel/kata-linux-5.4.60-89/drivers/android/modules.order: No such file or directory make: Leaving directory '/ /packaging/kernel/kata-linux-5.4.60-89'
不支持modulers
make modules The present kernel configuration has modules disabled. Type 'make config' and enable loadable module support. Then build a kernel with module support enabled. Makefile:1356: recipe for target 'modules' failed make: *** [modules] Error 1
Linux-Kconfig總結與分析
CONFIG宏變量參數
- bool: 表示該CONFIG宏只能選擇y(編譯內核)或者n(不編譯),不能選擇m(編譯為模塊)
- tristate: 表示該CONFIG宏可以設置y/m/n三種模式(tristate)
- string: 表示該CONFIG宏可以設為一串字符,比如#define CONFIG_XXX "config test"
- hex: 表示該CONFIG宏可以設為一個十六進制,比如#define CONFIG_XXX 0x1234
- int: 表示該CONFIG宏可以設為一個整數,比如#define CONFIG_XXX 1234
menuconfig MY_SYMBOL_TEST #生成一個菜單宏項 bool "MY_SYMBOL_TEST" default y config MY_SYMBOL1 bool "my symbol is bool" default y depends on MY_SYMBOL_TEST config MY_SYMBOL2 tristate "my symbo2 is tristate" default m depends on MY_SYMBOL_TEST config MY_SYMBOL3 string "my symbo3 is string" default "test symbo3" depends on MY_SYMBOL2 && MY_SYMBOL_TEST config MY_SYMBOL4 hex "my symbo4 is hex" range 0 0x2000 #設置hex區間 default 0x1234 depends on MY_SYMBOL2 && MY_SYMBOL_TEST config MY_SYMBOL5 int "my symbo5 is int" range 0 2000 #設置int區間 default 1234 depends on MY_SYMBOL2 && MY_SYMBOL_TEST
效果如下所示:
新手上路:內核模塊入門
從最初學習使用Linux OS,到學習Linux內核,再到自己編寫內核模塊,順利實現模塊的裝載和卸載,這是一個非常有趣的過程。下面我將內核模塊的學習內容和大家分享,將學習Linux內核的快樂簡單的傳遞。
構造和運行模塊的過程
模塊源代碼 hds.c文件
# include <linux/module.h> //任何模塊都必須包含,定義了可動態加載到內核的模塊所需要的必要信息
# include <linux/init.h> //必須包含,包含了宏__init(指定初始化函數)和__exit(指定清除函數)
# include <linux/kernel.h> //里面包含常用的內核API,例如內核打印函數printk()
static int __init hds_init(void) //__init將函數hds_init()標記為初始化函數,在模塊被裝載到內核時調用hds_init()
{
int sum = 0;
int i;
for(i = 1; i < 11; i++) //函數功能為1-10累加求和
sum +=i;
printk(KERN_CRIT "Hello kernel\n"); //注意末尾不要忘記加換行\n,否則打印會出現某些小的錯誤
printk(KERN_ALERT "sum is %d\n",sum);
//打印級別設為<1>,將求和結果立即打印,可以在插入模塊后,在用戶態下用命令dmesg查看打印效果
return 0;
}
static void __exit hds_exit(void) //清除函數,在模塊被卸載之前調用
{
printk(KERN_ALERT "Goodbye kernel\n"); //在模塊卸載時,將Goodbye kernel這句話打印到日志
}
module_init(hds_init); //引導內核 模塊從這里進來
module_exit(hds_exit); //引導內核 模塊從這里出去
MODULE_LICENSE("GPL"); //(必選項) 模塊許可證,缺省此句,將導致內核被污染
MODULE_AUTHOR("hds"); //(可選項) 描述模塊作者
MODULE_DESCRIPTION("for fun"); //(可選項) 描述模塊功能
Makefile文件
obj-m:=hds.o #根據make的自動推導原則,make會自動將源程序hds.c編譯成目標程序hds.o。
#所有在配置文件中標記為-m的模塊將被編譯成可動態加載進內核的模塊。即后綴為.ko的文件。
CURRENT_PATH:=$(shell pwd) #參數化,將模塊源碼路徑保存在CURRENT_PATH中
LINUX_KERNEL:=$(shell uname -r) #參數化,將當前內核版本保存在LINUX_KERNEL中
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
#參數化,將內核源代碼的絕對路徑保存在LINUX_KERNEL_PATH中
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules #編譯模塊
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean #清理
編譯模塊
$ make
為方便在當前終端查看日志打印信息,在裝載模塊前輸入此命令
$ tail -f /var/log/kern.log &
裝載模塊
$ sudo insmod hds.ko
查看裝載的模塊
$ lsmod
卸載模塊
$ sudo rmmod hds
查看模塊是否已卸載
$ lsmod