如何重新编译单个内核模块?

59

通常内核源代码存储在/usr/src/linux-2.6.x/

如果我修改了一个模块的源代码,为避免重新编译整个内核,该如何只重新编译这个模块呢?

5个回答

62

进入你的源代码根目录并运行以下命令:

$ make modules SUBDIRS=drivers/the_module_directory

并安装编译好的模块:

$ make modules_install SUBDIRS=drivers/the_module_directory

注意: 正如lunakid所提到的那样,后面的命令可能不会先构建模块,所以请小心。


请确保在树的根目录下运行该程序,不要像我一样。;) - Sz.
@lunakid 不错的观点 ;) 虽然 SUBDIRS 相对于当前工作目录应该是非常清晰的 :P - Niklas B.
这确实很清楚,但最终我还是发现自己坐在了wacom驱动程序目录中。 :) 只是没有注意到我的步骤。另外,您能否在您的答案中添加它也可以通过相同的方式进行安装,只需放置make modules_install SUBDIRS=...即可。那几乎肯定是下一步,可能不会立即简单(即使看起来是这样,在我花费几分钟搜索无果后... :))。谢谢,干杯! - Sz.
@lunakid 好的,谢谢你的反馈,我已经将它融入到我的答案中了。 - Niklas B.
干得好,可惜我不能给它加2分。 :) - Sz.
显示剩余4条评论

24

自从内核版本 3.x.x4.x.x 以来,该过程变得更加复杂(但仍有希望,继续阅读):

  1. 如果你不是刚克隆了一个新源码,而是之前已经编译过其他模块,则应执行 make distclean
  2. 在某个地方创建一个新文件夹来存放模块源码(例如: extra),并复制与需要构建的模块相关的源文件(从内核源码或其他地方)到这个新文件夹中
  3. /boot/config-`uname -r` 文件(例如:/boot/config-4.8.0-46-generic)复制到内核源码文件夹中的 .config 文件中,并运行 make oldconfig。如果该模块属于内核源码,请通过调用 make menuconfig 并搜索模块来验证是否已启用该模块,必要时应用字母 'M'
  4. 内核源码根目录下的 Makefile 必须被修改为精确匹配当前运行的版本组件(如果使用 make kernelversion 验证它是否与 uname -r 完全匹配)
  5. 建议先使用 make scripts 生成脚本
  6. 在实际模块构建之前必须执行 make preparemake modules_prepare
  7. 必须从相应运行内核版本的目标系统头文件夹中复制 Module.symvers 文件,例如: /usr/src/linux-headers-`uname -r`/Module.symvers (例如:/usr/src/linux-headers-3.13.0-117-generic/Module.symvers) 到为模块编译准备的新创建的模块源码文件夹(例如:示例中的 extra)中。
  • 在模块源编译文件夹中创建新的Makefile,添加以下行:obj-y += <module_source_file_name>.o,如果源代码很复杂,可以使用这里的指导
  • 只有在这样做之后才是构建模块的正确时间,使用命令make -C <kernel source path> M=the_module_directory进行模块构建(例如:make -C . M=extra/
  • 使用命令modprobe --dump-modversion <module_name>.ko验证导出API的模块和Module.symvers中对应值的CRC匹配。如果失败,请改用命令modinfo <module_name>.ko
  • 验证kernel.release文件内容是否与当前运行版本的头文件完全匹配。如果发现末尾添加了+,则说明您已经编译了git克隆的源代码,并且您的实验性修改导致构建系统在末尾添加了+以破坏localversion字符串。
  • 如果仅在kernel.release存储值的末尾发现了+,并且它与目标运行内核的确切名称不匹配,
  • 解决方案如下:

    提交所有更改,使用git tag -a <tag version> -f命令强制发布标签以将其移动到您的修改之上。然后从步骤8重新构建您的模块。


    如果驱动程序有自己的子目录(例如linux/drivers/net/ethernet/natsemi),是否仍然需要将驱动程序代码复制到其自己的“extra”文件夹中? - novice
    提供给其他可能遇到“Symbol version dump 'vmlinux.symvers' is missing.”的人参考:您可能需要在Linux源代码树中执行“cp Module.symvers vmlinux.symvers”。 - KJ7LNW

    9
    您可以将模块名称或模块目录作为参数传递给 make 命令的路径。
    make path/to/the/module/itself.ko
    make path/to/the/module/directory/
    

    1
    相比于使用“make modules SUBDIRS=directory/path”(3分钟 vs 5秒),使用“make path/to/the/module/itself.ko”需要更多的时间。实际上,仅使用“make path/to/directory”似乎无法工作,它总是显示“Nothing to be done”,但我已经修改了代码。 - Lilás

    7

    如果您只编辑了drivers/net/ethernet/intel/e1000/e1000_main.c文件中的代码

    构建该模块。

    make scripts prepare modules_prepare
    make -C . M=drivers/net/ethernet/intel/e1000
    

    安装模块。

    cp drivers/net/ethernet/intel/e1000/e1000.ko /lib/modules/5.1.15/kernel/drivers/net/ethernet/intel/e1000/e1000.ko
    

    4

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接