本次驱动编译主要是通过编译源码树来进行编译,过有关问题主要是编译源码树产生。通过linux-headers编译驱动是更为简单方便的,也是更为推荐的方法——本人后来试过此方法,一次成功,故没有相关踩坑记录:)。
ps:红色链接须重点查看
1.Ubuntu内核源码
ubuntu内核源码开源,且与linus维护的linux kernel存在微小区别
linus维护的linux kernel:
https://github.com/torvalds/linux
ubuntu内核源码git仓库:
https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal
focal为ubuntu20.04名字,查看其他版本源码需将focal换为其他系统的名字
launchpad.net 是维护Ubuntu GNU/Linux 发行版所使用的一个集代码管理,Bug 追踪,翻译等多种功能为一体的在线平台,由Canonical 公司开发和维护,Canonical 公司就是ubuntu的公司。
查看ubuntu系统名可通过以下链接:
https://zh.wikipedia.org/wiki/Ubuntu
或者通过命令查询
u@u-pc:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.6 LTS
Release: 20.04
Codename: focal
codename为ubuntu代号
ubuntu内核源码树官方下载教程如下:Kernel/SourceCode - Ubuntu Wiki
其他下载方法:
Ubuntu 下获取和编译内核源码的方法 :: Shaocheng.Li — Hello Friends
ubuntu发行版内核源码下载 - 沐多 - 博客园 (cnblogs.com)
2.ubuntu内核版本相关问题
查看完整内核版本命令
cat /proc/version_signature
内核版本含义:
Ubuntu kernels from Canonical | Ubuntu
ABI可简单理解为API,具体介绍:KernelTeam/BuildSystem/ABI - Ubuntu Wiki
linux-source包不使用上述命令规范,例如linux-source-5.4.0就是5.4.0-150.167,可见
Ubuntu – 在 focal 中的 linux-source-5.4.0 软件包详细信息
3.通过源码树编译驱动
0.完整教程:
Building External Modules — The Linux Kernel documentation
Linux驱动实践:带你一步一步编译内核驱动程序 - IOT物联网小镇 - 博客园 (cnblogs.com)
【Linux】驱动模块的 编译与加载_linux驱动模块编译_Xav Zewen的博客-CSDN博客
Ubuntu 14.04.2安装内核源码树以及编译_51CTO博客_ubuntu 编译内核
如何编译linux驱动ko_linux驱动编译ko_liyinuo2017的博客-CSDN博客
1.通过defconfig生成.config
Linux内核指令make defconfig做了什么事情_HMJ_的博客-CSDN博客
修改Linux Kernel defconfig的标准方法 - 君の内存 (adtxl.com)
linux kernel 编译的过程中 make defconfig、 make menuconfig、 make savedefconfig、 make olddefconfig 的含义_51CTO博客_linux使用make编译 如果对linux kernel了解较深,可跳过此步
以目标机为x64架构为例:
#O=build表示编译文件输出目录为build,防止编译生成文件污染源码目录,输出目录可自定义
#一旦选择了输出目录,后续均在此目录操作
#若一次执行了make O=build1 x86_64_defconfig,make O=build2 x86_64_defconfig,则会产生
#build1,build2两个目录,两份输出
#x86_64_defconfig 在arch/x86/configs/x86_64_defconfig
make O=build x86_64_defconfig
2.通过menuconfig选择要编译的模块
[config]关于make *config - aaronGao - 博客园 (cnblogs.com)
几个make config的作用_bytxl的博客-CSDN博客
Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解_dianhuiren的博客-CSDN博客
make O=build menuconfig
*表示编译到内核中,M表示以模块形式编译
3.生成编译所需信息
#理论上二者均可,但在ubuntu14中,仅make O=build prepare有效
make O=build prepare
make O=build moudles_prepare
To build external modules, you must have a prebuilt kernel available that contains the configuration and header files used in the build. Also, the kernel must have been built with modules enabled. If you are using a distribution kernel, there will be a package for the kernel you are running provided by your distribution.
An alternative is to use the "make" target "modules_prepare." This will make sure the kernel contains the information required. The target exists solely as a simple way to prepare a kernel source tree for building external modules.
NOTE: "modules_prepare" will not build Module.symvers even if CONFIG_MODVERSIONS is set; therefore, a full kernel build needs to be executed to make module versioning work.
4.编译
#根据.config编译整个内核
#j4表示以4进程编译
make O=build -j4
#仅编译hid-cp2112驱动,但仍需上述几步,所使用的的头文件也是该驱动所在linux源码树提供,而非系统提供
make O=build drivers/hid/hid-cp2112.ko
5.清理
编译过程中可能会出现各种问题,当修复好问题后,需清理输出目录再次编译
make O=build clean #删除大多数的编译生成文件, 但是会保留内核的配置文件.config, 还有足够的编译支持来建立扩展模块
make O=build mrproper #删除所有的编译生成文件, 还有内核配置文件, 再加上各种备份文件
make O=build distclean #mrproper删除的文件, 加上编辑备份文件和一些补丁文件。
6.安装驱动
方法一:
进入hid-cp2112.ko驱动模块文件所在的目录,然后直接insmod hid-cp2112.ko
insmod hid-cp2112.ko
方法二
将hid-cp2112.ko文件拷贝到原hid-cp2112.ko所在路径(/lib/modules/5.4.0-139-generic/kernel/drivers/hid/)。然后 depmod(会在/lib/modules/5.4.0-139-generic/kernel/drivers/hid/目录下生成modules.dep和modules.dep.bb文件,表明模块的依赖关系) 最后 modprobe hid-cp2112(注意这里无需输入.ko后缀) 即可。
#以下操作均需root权限
#以hid-cp2112.ko为例,因ubuntu自带hid-cp2112驱动,所以须先做备份
cp /lib/modules/5.4.0-139-generic/kernel/drivers/hid/hid-cp2112.ko /lib/modules/5.4.0-139-generic/kernel/drivers/hid/hid-cp2112.ko.bak
#此时位于自己编译的hid-cp2112.ko同一目录,将自己编译的hid-cp2112驱动复制到目的路径
cp hid-cp2112.ko /lib/modules/5.4.0-139-generic/kernel/drivers/hid/hid-cp2112.ko
depmod
modprobe hid-cp2112
注:两种方法的区别
modprobe和insmod类似,都是用来动态加载驱动模块的,区别在于modprobe可以解决load module时的依赖关系,它是通过/lib/modules/$(uname-r)/modules.dep(.bb)文件来查找依赖关系的;而insmod不能解决依赖问题。也就是说,如果你确定你要加载的驱动模块不依赖其他驱动模块的话,既可以insmod也可以modprobe,当然insmod可以在任何目录下执行,更方便一些。而如果你要加载的驱动模块还依赖其他ko驱动模块的话,就只能将模块拷贝到上
述的特定目录,depmod后再modprobe。
#查看已加载驱动
lsmod
#卸载驱动hid-cp2112.ko
rmmod hid-cp2112.ko
#查看已加载的hid-cp2112驱动信息
modinfo hid-cp2112
#查看当前目录下的hid-cp2112.ko的驱动信息
modinfo hid-cp2112.ko
相关问题
1.gcc版本切换问题
#用于选择gcc版本
sudo update-alternatives --config gcc
相关参考:
ubuntu 14.04 升级到 gcc 5 // Neurohazard (blkstone.github.io)
Ubuntu 1804 gcc、g++不同版本的切换 - 简书 (jianshu.com)
2.内核模块的vermagic相关问题
vermagic遇到问题务必看完这两个帖子,能解决大部分问题:
内核模块的version magic 你知多少?-OpenEdv-开源电子网
[转载]linux内核模块版本检查 - 君の内存 (adtxl.com)
其余相关:
向linux内核版本号添加字符/为何有时会自动添加“+”号_xiaofeng_yan的博客-CSDN博客
git - Don't add "+" to linux kernel version - Stack Overflow
Linux kernel 在 Git 目录和 SVN 目录编译行为不一致的解决方法 - 后台 / 嵌入式全栈之路 - SegmentFault 思否
内核模块编译怎样绕过insmod时的版本检查 - kk Blog —— 通用基础 (abcdxyzk.github.io)
解析 Linux 内核可装载模块的版本检查机制【转】 - Sky&Zhang - 博客园 (cnblogs.com)
取消编译出的模块信息带有加号的方法
例如:
u@u-pc:~/code/linux/build/drivers/hid$ modinfo hid-cp2112.ko
filename: /home/y/code/linux/build/drivers/hid/hid-cp2112.ko
license: GPL
author: David Barksdale <dbarksdale@uplogix.com>
description: Silicon Labs HID USB to SMBus master bridge
alias: hid:b0003g*v000010C4p0000EA90
depends:
intree: Y
vermagic: 4.4.0+ SMP mod_unload modversions
parm: gpio_push_pull:GPIO push-pull configuration bitmask (int)
4.4.0后面带有加号的原因是下载源码通过git下载,目录中带有git信息,并对源码进行了修改,导致编译出的模块带有+号,可在编译时使用参数LOCALVERSION取消掉+号
make LOCALVERSION= O=build drivers/hid/hid-cp2112.ko
原因如下:在scripts/setlocalversion中有注释:
append a plus sign if the repository is not in a clean annotated or signed tagged state (as git describe only looks at signed or annotated tags - git tag -a/-s) and LOCALVERSION= is not specified
翻译过来就是:
如果git仓库不是在一个干净的annotated or signed tagged的状态,且LOCALVERSION= 没有被指明,则添加一个加号
# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
res="$res$(collect_files "$srctree"/localversion*)"
fi
# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
# full scm version string
res="$res$(scm_version)"
else
# append a plus sign if the repository is not in a clean
# annotated or signed tagged state (as git describe only
# looks at signed or annotated tags - git tag -a/-s) and
# LOCALVERSION= is not specified
if test "${LOCALVERSION+set}" != "set"; then
scm=$(scm_version --short)
res="$res${scm:++}"
fi
fi
echo "$res"
annotate tag和sign tag含义可参考:
Git supports two types of tags: lightweight and annotated.
A lightweight tag is very much like a branch that doesn’t change — it’s just a pointer to a specific commit.
Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too.
If you have a GPG private key set up, you can now use it to sign new tags. All you have to do is use
-s
instead of-a
:
Git - Signing Your Work (git-scm.com)
其余参考资料:
ubuntu - Where to get linux "5.4.0-77-generic" kernel source? - Unix & Linux Stack Exchange
Kernel/SourceCode - Ubuntu Wiki
内核编译时, 到底用make clean, make mrproper还是make distclean_make清除编译_AyaoGGLi的博客-CSDN博客
Linux下加载.ko驱动模块的两种方法:insmod与modprobe_insmod : short read_coollh的博客-CSDN博客