Linux 内核 Makefile 解释
在软件开发中,创建和管理大型代码存储库的过程很容易变得非常复杂。
为了管理和降低这种复杂性,软件开发人员将代码组织在链接到特定模块的小文件中。开发人员可以单独编译每个文件,然后将它们链接在一起以创建最终的软件可执行文件。
例如,C 项目由扩展名为 .c 的源代码文件和扩展名为 .h 的软件接口组成。每个源文件与要创建的头文件一起编译。 o 使用库链接在一起的对象,从而创建可执行文件。
为了执行此过程,软件开发人员使用 Make 等工具来自动执行构建过程和所需的文件依赖项。 Make 使用 Makefile 来管理编译过程的行为。
GNU Make 工具提供了一组用于创建 Makefile 的规则和约定,降低了复杂性,提高了效率。
在本教程中,我们将讨论 Linux 内核 Makefile,特别是 Kconfig 和 Kbuild。
在开始之前,需要注意的是,本文并不假装教授有关内核构建系统的所有内容。不过,我们提供了构建 vmlinux 映像和模块的高级概述。
如果您需要本教程范围之外的信息,我们建议您使用以下资源以获得更好的信息:
https://linkfy.to/goMakefilesDocs
https://linkfy.to/gnuMake
内核 Makefile:概述
内核构建系统,也称为配置系统,对于那些需要它的人来说是一个必不可少的工具,它已经存在了一段时间。然而,并不是每个人都会使用这个系统;甚至驱动程序和其他低级软件开发人员也很少使用它。既然您正在阅读本文,这意味着您想了解更多有关内核构建系统的信息。
因此,我们将讨论内核是如何编译的,并讨论 Kbuild 和 Kconfig 系统,以便您可以更好地理解它们。
内核 Makefile 有五个核心组件:
Makefile:这是位于源根目录中的顶级 make 文件。
arch/$ (ARCH) Makefile:这是 arch Makefile;它作为顶层 Makefile 的补充。
.config:这是内核配置文件。
Scripts/Makefile.*:这定义了所有 kbuild Makefile 的设置规则。
Kbuild Makefiles: kbuild Makefiles 大约有 500 个,而且它们不太容易阅读。考虑一个文件,例如:
https://elixir.bootlin.com/linux/latest/source/scripts/Kbuild.include
内核配置
Kconfig 文件包含在使用 make *config 时提供帮助的模块。它帮助内核进行选择性配置,为内核构建过程创建模块化和可定制性。
Kconfig 系统指定了各种配置目标。您可以使用 make help 查看可用的目标。这些目标在构建过程中由内核提供的各种程序处理。
一些 Kconfig 目标包括:
配置:这用于使用线路程序更新内核配置文件。
Menuconfig:这是一个 Kconfig 功能或机制,提供对内核选项的基于菜单的访问。要启动 menuconfig 和其他 Kconfig 功能,您应该位于平台项目目录中。您可以使用以下命令启动 Kconfig menuconfig 功能。但是,您还可以使用其他 GUI Linux 内核配置功能(例如 xconfig 和 gconfig)启动 menuconfig。
gconfig 和 xconfig: Gconfig 激活基于 GUI 的 Linux 内核功能。 Gconfig 采用 GTK 或(基于 X)的 UI。另一方面,Xconfig 使用基于 Qt 的 UI。使用以下命令分别启动 gconfig 和 xconfig:
make linux-windriver.xconfig
注意:要使用 gconfig 和 xconfig,您应该在主机系统上安装 QT 开发工具。
Nconfig: Nconfig 功能运行当前配置(Buildtools)并适用于 Ncurses 菜单驱动程序。这允许您在构建内核时选择要构建的包,例如 CPU、驱动程序和文件系统。使用命令:make nconfig。
Oldconfig:oldconfig 功能允许您将较新的 .config 文件应用到较旧的内核配置文件。例如,旧的 .config 文件和较新的 .config 文件(较新的内核版本)会有差异,这意味着您需要在内核构建之前更新当前配置。您可以使用 make oldconfig 通过应用旧配置文件中缺少的选项来交互式更新旧配置。
Defconfig:此功能允许内核构建系统将 defconfig 提供的新配置添加到 .config 文件中。更准确地说,Kbuild 系统检查所有 Kconfig 文件。如果 defconfig 在文件中指定了一个选项,Kbuild 系统将使用指定的值将该选项添加到 .config 中。如果 defconfig 没有提及该选项,Kbuild 将使用 .config 中的默认值。
考虑以下:
来自以下资源的 Defconfig 代码快照:
https://elixir.bootlin.com/linux/v5.9/source/scripts/kconfig/Makefile#L98
2. ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
3. @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
4. $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
5. else
6. @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'"
7. $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
8. endif
9.
10. %_defconfig: $(obj)/conf
11. $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
12.
13. configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@)
14.
15. %.config: $(obj)/conf
16. $(if $(call configfiles),, $(error No configuration exists for this target on this architecture))
17. $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles)
18. $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig
来自以下资源的旧配置代码快照:
https://elixir.bootlin.com/linux/v5.9/source/scripts/kconfig/conf.c#L694
2. default:
3. break;
4. }
5.
6. if (input_mode == savedefconfig) {
7. if (conf_write_defconfig(defconfig_file)) {
8. fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
9. defconfig_file);
10. return 1;
11. }
12. } else if (input_mode != listnewconfig && input_mode != helpnewconfig) {
13. if (!no_conf_write && conf_write(NULL)) {
14. fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
15. exit(1);
16. }
17.
18. /*
19. * Create auto.conf if it does not exist.
20. * This prevents GNU Make 4.1 or older from emitting
21. * "include/config/auto.conf: No such file or directory"
22. * in the top-level Makefile
23. *
24. * syncconfig always creates or updates auto.conf because it is
25. * used during the build.
26. */
27. if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
28. fprintf(stderr,
29. "\n*** Error during sync of the configuration.\n\n");
30. return 1;
31. }
32. }
33. return 0;
34. }
Savedefconfig:该规则以./defconfig的形式保存当前的.config,它被视为最小配置文件。使用命令:make savedefconfig
Listnewconfig:这用于列出新选项。
Kvmconfig:这将启用 KVM 支持选项。使用命令:make kvm_guest.config
Allyesconfig:这将构建一个新的内核配置文件,并将所有选项设置为 yes。它与 allnoconfig 相反。
Allmodconfig:这会构建一个新的内核配置,默认情况下会启用该模块。
Randconfig:这会构建一个新的内核配置文件,其中包含所有选项的随机答案。
Tinyconfig:这使得最小的内核成为可能。
Kconfig系统中有很多目标。一些常见的包括 config 和 menuconfig。
如前所述,目标由主机系统中的各种程序处理,提供 GUI 或命令行。您可以在内核源代码的 /scripts/Kconfig 中找到 Kconfig 工具。
https://elixir.bootlin.com/linux/latest/source/scripts/kconfig
https://elixir.bootlin.com/linux/latest/source/scripts/kconfig/Makefile
第一个过程通常是读取根目录下的Kconfig文件,该文件用于构建初始配置数据库。随着该过程的继续,数据库在按以下顺序读取文件时更新:
/lib/modules/$(shell,uname-r)/.config
/etc/kernel-config
/boot/config-$(shell,uname-r)
ARCH_DEFCONFIG
arch/$(ARCH)/defconfig
然后将 .config 文件放入syncconfig,后者接受 .config 文件作为输入。它处理文件并输出文件,然后将文件分为各种类别,例如:
autoconf.h:用于C语言源文件。
auto.conf 和 tristate.conf: 它们用于 Makefile 文本处理。
/includes/config: 这些是依赖项跟踪中使用的空头文件。
Kbuild 文件
几乎所有内核文件都是使用 Kbuild 基础结构的 Kbuild Makefile,这是一个递归 make 功能。递归Make 是一种将Make 工具用作Makefile 中的命令的方法。编译大型项目时,递归非常有用。
Kbuild 通过引用我们在上一节中提到的所有文件来工作。
Kbuild 系统使用顶级 Makefile 构建其组件,其中包括配置文件中名为 arch/$ (ARCH)/Makefile 的 arch Makefile。它递归地下降到子目录中,使用 script/Makefile.* 中的例程在组件上调用 Make。然后 Kbuild 在相邻对象的基础上构建并将它们链接到对象中,创建 vmlinux。
要了解有关 Kbuild Makefile 中使用的语法的更多信息,请参阅文档。
考虑以下脚本。
https://github.com/torvalds/linux/blob/master/scripts/link-vmlinux.sh
用于创建 vmlinux 的 o 目标文件首先在各自的内置 .a 文件中编译为 var KBUILD_VMLINUX_INIT,MAIN,LIBS。这些都是在 vmlinux 中编写的。
https://github.com/torvalds/linux/blob/master/scripts/Makefile.build
结论
在本指南中,我们了解了内核构建系统中的 Kbuild 和 Kconfig 系统及其工作原理。正如我们在教程开头提到的,讨论的主题很广泛,无法在单个教程中涵盖。