【分享】在Petalinux編譯多個源文件的Linux內核模塊,以及擴展Makefile功能


作者:付漢傑

創建內核模塊

Petalinux可以幫助工程師簡化內核模塊的創建工作。在petalinux工程目錄下,使用命令“petalinux-create -t modules --name --enable”,能創建Linux內核模塊,包括c源代碼文件、Makefile、Yocto的bb文件。相關文件放在目錄“project-spec/meta-user/recipes-modules”,目錄結構如下。

hankf@XSZGS4:~/proj/vcu-trd-2020.2-peta-qt/project-spec/meta-user/recipes-modules$ tree
.
└── linux-test-module
    ├── files
    │   ├── COPYING
    │   ├── linux-test-module.c
    │   └── Makefile
    ├── linux-test-module.bb
    └── README

2 directories, 5 files

Makefile

原始Makefile

原始的Makefile只支持一個源文件,內容如下:

obj-m := linux-module-module.o

MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}

SRC := $(shell pwd)

all:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
	rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
	rm -f Module.markers Module.symvers modules.order
	rm -rf .tmp_versions Modules.symvers

原始的Makefile,支持模塊在內核源碼目錄外編譯。編譯的命令是“$(MAKE) -C $(KERNEL_SRC) M=$(SRC)”。其中-C選項將當前工作目錄轉移到指定的位置;KERNEL_SRC是Yocto/PetaLinux在文件components/yocto/layers/core/meta/classes/module.bbclass里定義的變量,指定了Linux內核源代碼目錄,一般是Petalinux工程目錄下的子目錄“build/tmp/work-shared/zynqmp-generic/kernel-source”。這樣編譯時先進入內核源代碼目錄,先執行其中的頂層Makefile。M是內核根目錄下的Makefile中使用的變量,讓make在構造modules目標之前返回到內核模塊源的代碼目錄。

Linux內核頂層Makefile關於M變量的代碼:

# Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the
# directory of external module to build. Setting M= takes precedence.
ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

module.bbclass里定義的變量KERNEL_SRC的代碼:

python do_devshell_prepend () {
    os.environ['CFLAGS'] = ''
    os.environ['CPPFLAGS'] = ''
    os.environ['CXXFLAGS'] = ''
    os.environ['LDFLAGS'] = ''

    os.environ['KERNEL_PATH'] = d.getVar('STAGING_KERNEL_DIR')
    os.environ['KERNEL_SRC'] = d.getVar('STAGING_KERNEL_DIR')
    os.environ['KERNEL_VERSION'] = d.getVar('KERNEL_VERSION')
    os.environ['CC'] = d.getVar('KERNEL_CC')
    os.environ['LD'] = d.getVar('KERNEL_LD')
    os.environ['AR'] = d.getVar('KERNEL_AR')
    os.environ['O'] = d.getVar('STAGING_KERNEL_BUILDDIR')
    kbuild_extra_symbols = d.getVar('KBUILD_EXTRA_SYMBOLS')
    if kbuild_extra_symbols:
        os.environ['KBUILD_EXTRA_SYMBOLS'] = kbuild_extra_symbols
    else:
        os.environ['KBUILD_EXTRA_SYMBOLS'] = ''
}

語句“obj-m := linux-test-module.o”指示Kbuild將模塊編譯成Linux內核模塊文件linux-test-module.ko。

更多信息可以參考相關文檔,比如深入理解 Linux 配置/構建系統是如何工作的,LINUX內核編譯學習筆記, Linux 內核模塊編譯 MakefileLinux 2.6內核Makefile淺析

多源文件Makefile

如果有多個源文件,也可以學習Linux內核模塊的Makefile寫法,使Petalinux的內核模塊也支持多個源文件。Linux內核通過$(<module_name>-objs)包含多個目標文件,使Kbuild編譯多個源文件。因此在支持新Makefile里,增加了objs語句。首先通過TEST_FILES列出所有C文件,再將C文件替換成Obj文件賦值給$(TEST_MODULE_NAME)-objs 。

export TEST_MODULE_NAME = linux-test-module
export TEST_FILES = linux-test-module.c linux-test-module-internal.c
$(TEST_MODULE_NAME)-objs = $(patsubst %.c,%.o,$(filter %.c,$(TEST_FILES)))
obj-m += $(TEST_MODULE_NAME).o

MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}

SRC := $(shell pwd)

all:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
	rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
	rm -f Module.markers Module.symvers modules.order
	rm -rf .tmp_versions Modules.symvers

內核源碼目錄內Makefile

有時內核模塊也需要在Linux內核源碼目錄內編譯,不需要指定編譯命令。KERNELRELEASE是Linux內核源碼的頂層Makefile定義的一個變量。如果在內核源碼目錄內編譯,先執行Linux內核源碼的頂層Makefile,會定義KERNELRELEASE的具體值。如果加上對KERNELRELEASE的檢查,前面的Makefile可以改造成既可以在在內核源碼目錄內編譯,也可以在在內核源碼目錄外編譯。下面的Makefile,增加了檢查KERNELRELEASE的語句“ifeq ($(KERNELRELEASE),)”。

export TEST_MODULE_NAME = linux-test-module
export TEST_FILES = linux-test-module.c linux-test-module-internal.c
$(TEST_MODULE_NAME)-objs = $(patsubst %.c,%.o,$(filter %.c,$(TEST_FILES)))
obj-m += $(TEST_MODULE_NAME).o

MY_CFLAGS += -g -DDEBUG
ccflags-y += ${MY_CFLAGS}

ifeq  ($(KERNELRELEASE),)

SRC := $(shell pwd)

# KERNEL_SRC=/proj/hankf/zcu106/rdf0428-zcu106-vcu-trd-2020.2/source/linux-kernel

all:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC)

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install

clean:
	rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
	rm -f Module.markers Module.symvers modules.order
	rm -rf .tmp_versions Modules.symvers
	
endif

實際測試中,不加KERNELRELEASE相關語句,也不影響在Linux內核源碼目錄內編譯。據說舊版本Kbuild才需要的KERNELRELEASE相關語句。
上面的Makefile文件也可以作為一個模板。只需要更改TEST_MODULE_NAME的值“linux-test-module”,和更改TEST_FILES后的文件列表,可以用於編譯其它模塊。
如果既不在PetaLinux環境里編譯,也不再Linux內核源碼目錄內編譯,請再在上面的Makefile文件里定義內核源碼目錄。

Yocto recipe文件

Yocto recipe文件的擴展名是.bb,它定義recipe需要的文件。

原始bb文件

原始的recipe的bb文件的只含有一個C文件。

SUMMARY = "Recipe for  build an external linux-test-module Linux kernel module"
SECTION = "PETALINUX/modules"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=12f884d2ae1ff87c09e5b7ccc2c4ca7e"

inherit module

INHIBIT_PACKAGE_STRIP = "1"

SRC_URI = "file://Makefile \
           file://linux-test-module.c \
	       file://COPYING \
          "

S = "${WORKDIR}"

# The inherit of module.bbclass will automatically name module packages with
# "kernel-module-" prefix as required by the oe-core build environment.

新bb文件

由於要支持多個源文件,需要在recipe的bb文件的添加所有C文件。修改其實也很簡單。下面的bb文件添加了行“file://linux-test-module-internal.c”以為Yocto/PetaLinux增加文件linux-test-module-internal.c。

SUMMARY = "Recipe for  build an external linux-test-module Linux kernel module"
SECTION = "PETALINUX/modules"
LICENSE = "GPLv2"
LIC_FILES_CHKSUM = "file://COPYING;md5=12f884d2ae1ff87c09e5b7ccc2c4ca7e"

inherit module

INHIBIT_PACKAGE_STRIP = "1"

SRC_URI = "file://Makefile \
           file://linux-test-module.c \
           file://linux-test-module-internal.c \
	   file://COPYING \
          "

S = "${WORKDIR}"

# The inherit of module.bbclass will automatically name module packages with
# "kernel-module-" prefix as required by the oe-core build environment.

測試環境

UBuntu 18.04
PetaLinux 2020.2


免責聲明!

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



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