当前位置:首页>Linux>从 Kbuild 编译系统,读懂 Linux 内核编译的底层逻辑

从 Kbuild 编译系统,读懂 Linux 内核编译的底层逻辑

  • 2026-03-21 01:27:02
从 Kbuild 编译系统,读懂 Linux 内核编译的底层逻辑

Linux 内核作为开源领域最复杂的软件工程之一,其编译过程绝非简单的 make 命令就能概括,而支撑这一切的核心正是 Kbuild 编译系统。不同于常规应用程序的 Makefile 编写逻辑,Kbuild 专为内核的模块化、跨平台、高扩展性设计,是理解内核构建流程的关键入口。无论是驱动开发者想要自定义编译模块,还是内核爱好者探究源码组织方式,搞懂 Kbuild 的工作机制,都能让你跳出 “只知执行命令,不知底层逻辑” 的误区,真正掌握内核编译的主动权。

Kbuild 本质上是一套基于 GNU Make 的分层构建框架,它通过分散在源码树各目录的 Kbuild、Makefile 文件,以及顶层 Makefile 的统一调度,实现了对千万行级代码的高效编译管理。从配置阶段的 make menuconfig 解析 .config 文件,到编译阶段的目标文件依赖处理,再到链接阶段的内核镜像生成,Kbuild 都遵循着一套严谨且灵活的规则。本文将从 Kbuild 的核心设计理念出发,拆解其目录遍历、模块编译、依赖管理等底层逻辑,帮你从根源理解 Linux 内核编译的完整流程。

一、Make 基础原理

Make 是 Linux 内核编译最基础的自动化构建工具,负责按照规则调度整个编译流程,没有复杂的专业修饰,核心作用就是读懂编译规则、按依赖顺序执行命令,也是 Kbuild 和 gcc 协同工作的基础载体。

1.1 Make 与 Makefile 简介

在 Linux 内核编译的庞大体系中,Make 就像是一位经验丰富的指挥官,它是一个自动化构建工具,主要用于管理项目的编译和构建过程。而 Makefile 则是这位指挥官的作战计划,是一个包含构建规则和依赖关系的文件 ,定义了如何将源代码转换为可执行程序的完整过程,其核心是依赖关系和构建规则的集合。

举个例子,当我们要建造一座房子时,Make 就像是负责统筹安排的包工头,Makefile 则是详细的施工蓝图。蓝图上会标明建造房子需要哪些材料(源文件),先搭建框架(编译部分代码)还是先砌墙(处理其他部分),以及每一步具体的操作方法(编译命令)。Makefile 通过定义目标(target)、依赖(dependencies)和命令(commands),告诉 Make 如何从源代码生成最终的可执行文件或其他目标文件。例如:

# 定义目标文件main: main.o utils.o    gcc -o main main.o utils.o  # 链接命令,生成可执行文件main,依赖于main.o和utils.omain.o: main.c main.h    gcc -c main.c -o main.o  # 编译命令,生成main.o,依赖于main.c和main.hutils.o: utils.c utils.h    gcc -c utils.c -o utils.o  # 编译命令,生成utils.o,依赖于utils.c和utils.h

在这个简单的 Makefile 中,我们定义了三个目标:main、main.o和utils.o。main目标依赖于main.o和utils.o,通过gcc命令将这两个目标文件链接成可执行文件main;main.o目标依赖于main.c和main.h,使用gcc -c命令将main.c编译成目标文件main.o;utils.o目标同理。这样,Make 在执行时,就会根据这些规则和依赖关系,有条不紊地完成编译和链接工作。

1.2 Make 工作流程

Make 的工作流程严谨而有序,就像一场精心编排的交响乐。当我们在命令行中输入make命令后,它会按照以下步骤进行工作:

  1. 查找 Makefile:Make 首先会在当前目录下查找名为Makefile或makefile的文件。如果找到了,就开始读取这个文件;如果没有找到,它会报错并停止执行。这就好比包工头要施工,首先得找到施工蓝图,如果找不到,自然无法开工。
  2. 读取 Makefile 内容:Makefile 由一系列规则组成,每个规则包含目标、依赖和命令。Make 会逐行读取 Makefile 中的内容,解析这些规则,并将它们存储在内存中。例如,对于上面提到的 Makefile,Make 会识别出main、main.o和utils.o等目标,以及它们各自的依赖和命令。
  3. 分析依赖关系:Make 会根据读取到的规则,分析目标之间的依赖关系,构建出一棵依赖树。在依赖树中,每个目标都是一个节点,它的依赖则是指向该节点的边。通过这种方式,Make 可以清晰地了解整个项目的构建结构,确定哪些目标需要先构建,哪些目标依赖于其他目标的构建结果。比如在我们的例子中,main依赖于main.o和utils.o,main.o又依赖于main.c和main.h,utils.o依赖于utils.c和utils.h,这样就形成了一个完整的依赖关系链。
  4. 检查文件时间戳:Make 会检查每个目标文件和其依赖文件的时间戳(修改时间)。如果目标文件不存在,或者其依赖文件的时间戳比目标文件新,Make 就会认为这个目标需要重新构建。这是 Make 实现增量编译的关键机制,它只重新编译那些被修改过的文件及其依赖项,从而大大节省了编译时间。例如,如果main.c文件被修改了,其时间戳会更新,那么main.o目标的时间戳就会比main.c旧,Make 就会重新编译main.c生成新的main.o,进而重新链接生成新的main可执行文件。
  5. 执行构建命令:当 Make 确定某个目标需要重新构建时,它会执行该目标对应的命令。这些命令通常是一些编译、链接或其他与构建相关的操作。Make 会按照依赖关系的顺序,依次执行各个目标的构建命令,直到最终生成我们需要的目标文件。在执行命令时,Make 会在命令行中显示正在执行的命令,以便我们了解构建过程的进展情况。

为了更直观地理解 Make 的工作流程,我们来看一个简单的示例。假设我们有一个包含main.cutils.c两个源文件的项目,其 Makefile 内容如下:

# 定义编译器和编译选项CC = gccCFLAGS = -Wall -g# 定义目标文件TARGET = myprogram# 定义源文件SRCS = main.c utils.cOBJS = $(SRCS:.c=.o)# 默认目标,生成可执行文件all: $(TARGET)# 生成可执行文件的规则$(TARGET)$(OBJS)    $(CC) $(CFLAGS) -o $(TARGET) $(OBJS)# 生成目标文件的规则%.o: %.c    $(CC) $(CFLAGS) -c $< -o $@# 清理生成的文件clean:    rm -f $(TARGET) $(OBJS)

当我们在命令行中输入make命令后,Make 会首先找到这个 Makefile 并读取其内容。然后,它会分析依赖关系,确定all是默认目标,而all依赖于$(TARGET),$(TARGET)又依赖于$(OBJS),即main.o和utils.o。接着,Make 会检查文件时间戳,如果main.c或utils.c被修改过,对应的.o文件就需要重新编译。最后,Make 会执行相应的编译和链接命令,生成可执行文件myprogram。如果我们输入make clean,Make 会执行clean目标对应的命令,删除生成的可执行文件和目标文件。

二、Kbuild 编译系统初相识

2.1 什么是 Kbuild

在深入探讨 Kbuild 报错与调优之前,咱们先来了解一下 Kbuild 到底是什么。简单来说,Kbuild 是 Linux 内核编译系统的核心组件 ,就像是一个 “编译指挥家”,负责协调内核编译过程中的各个环节,让整个编译工作有条不紊地进行。

Linux 内核的源代码规模庞大,包含了各种不同功能的模块和驱动,涉及到的源文件和目录层次繁多。如果没有一个高效的编译系统来管理,那编译内核简直就是一场噩梦。Kbuild 的出现,完美地解决了这个问题。它基于 Makefile 系统,但又在其基础上进行了大量的扩展和优化,提供了一套简洁、灵活且强大的机制,用于描述内核各个部分的编译规则、依赖关系以及如何将它们组合成一个完整的内核镜像。

比如,在一个大型的 Linux 项目中,有网络模块、文件系统模块、设备驱动模块等等。Kbuild 通过定义一系列特殊的变量和目标,像obj-y(表示将某个文件编译进内核)、obj-m(表示将某个文件编译成可加载模块),让开发者可以轻松地指定哪些代码需要编译进内核,哪些需要编译成模块,而不用去操心复杂的底层编译细节 。这就好比你在搭建一个乐高城堡,Kbuild 帮你把每个乐高零件的组装说明都整理好了,你只需要按照它的指示,就能顺利地搭建出完整的城堡。

2.2 Kbuild 的关键特性

(1)模块化构建:Kbuild 支持模块化构建,这是它的一大亮点。在内核开发中,不同的功能模块可能由不同的开发者编写,Kbuild 允许将这些模块分别编译,然后根据需要动态地加载到内核中。这就像搭积木一样,每个积木块(模块)可以独立制作,最后按照需求组合在一起。例如,对于设备驱动模块,开发者可以根据硬件设备的特点和需求,单独编译对应的驱动模块,而不必重新编译整个内核。通过obj-m和obj-y变量,Kbuild 可以轻松地指定哪些文件编译成模块(obj-m),哪些文件直接编译进内核(obj-y)。比如:

obj-m += my_driver.o

这行代码告诉 Kbuild,my_driver.o要被编译成可加载的内核模块,最终生成my_driver.ko文件。

(3)依赖管理:Kbuild 拥有强大的依赖管理能力,它能够自动处理文件之间的依赖关系。在内核庞大的代码体系中,文件之间的依赖错综复杂,Kbuild 通过分析源代码中的#include语句以及 Makefile 中的规则,准确地确定每个文件的依赖项。当某个源文件发生变化时,Kbuild 会智能地判断哪些文件需要重新编译,从而大大提高了编译效率。例如,如果一个内核模块依赖于多个头文件和源文件,Kbuild 会确保在编译该模块时,先编译其依赖的文件,并且在依赖文件更新时,及时重新编译相关模块。

(3)编译控制:Kbuild 提供了丰富的编译控制选项,开发者可以通过这些选项来定制编译过程。比如,通过EXTRA_CFLAGS变量可以添加自定义的编译标志,从而满足不同的编译需求。如果开发者想要启用特定的优化选项或者添加调试信息,可以这样设置:

EXTRA_CFLAGS += -O2 -g

这表示在编译时启用二级优化(-O2)并添加调试信息(-g)。此外,Kbuild 还支持条件编译,根据内核配置选项来决定哪些代码被编译,哪些代码被忽略。例如:

obj-$(CONFIG_FEATURE_X) += feature_x.o

当CONFIG_FEATURE_X被配置为y(编译进内核)或m(编译成模块)时,feature_x.o才会被编译,否则将被忽略。

(4)跨平台支持:由于 Linux 内核需要在各种不同的硬件平台上运行,Kbuild 具备出色的跨平台支持能力。它可以根据不同的硬件架构,自动调整编译过程和生成相应的目标代码。无论是 x86、ARM、PowerPC 还是其他架构,Kbuild 都能应对自如。通过arch/$(ARCH)/Makefile文件,Kbuild 可以获取特定架构的编译信息和规则,确保内核在不同平台上都能正确编译和运行 。

2.3 Kbuild 工作流程

了解了 Kbuild 是什么之后,接下来咱们深入剖析一下它的工作流程,这有助于我们更好地理解后续出现的各种报错。Kbuild 的工作流程大致可以分为以下几个主要步骤:

  1. 读取配置文件:Kbuild 首先会读取内核配置文件.config,这个文件包含了用户对内核的各种配置选项,比如是否启用某个驱动、是否支持特定的文件系统等。这些配置选项以CONFIG_XXX的形式存在,比如CONFIG_NETWORKING=y表示启用网络功能。读取配置文件的过程,就像是厨师在做菜前查看菜谱,了解需要准备哪些食材和调料 。
  2. 解析 Makefile:Kbuild 会递归地解析内核源代码树中的各个Makefile文件(这些Makefile采用了 Kbuild 特有的语法,所以也叫 Kbuild 文件)。在解析过程中,它会根据配置文件中的选项以及Makefile中定义的规则,确定哪些源文件需要编译,以及如何编译。比如,obj-$(CONFIG_FOO) += foo.o这条规则表示,如果CONFIG_FOO在配置文件中被设置为y或m,那么就会编译foo.c或foo.S生成foo.o。
  3. 编译源文件:根据前面解析得到的编译规则,Kbuild 会调用相应的编译器(如gcc)对源文件进行编译,生成目标文件(.o文件)。在这个过程中,如果源文件之间存在依赖关系,Kbuild 会自动处理这些依赖,确保先编译依赖的文件 。就像组装一台机器,需要先把各个零件准备好,才能进行下一步的组装。
  4. 链接目标文件:将编译生成的各个目标文件链接成一个完整的内核镜像文件(如vmlinux)或者内核模块文件(.ko文件)。链接过程中,会处理函数和变量的引用关系,确保内核能够正确运行。
  5. 生成最终产物:最后,对生成的内核镜像进行一些处理,比如压缩生成bzImage等最终可用于启动系统的内核文件。

下面是一个简单的 Kbuild 工作流程图,帮助大家更直观地理解:

st=>start: 开始read_config=>inputoutput: 读取.config配置文件parse_makefile=>operation: 递归解析Makefilecompile_files=>operation: 编译源文件生成.o文件link_files=>operation: 链接.o文件生成vmlinux或.ko文件generate_final=>operation: 生成最终内核文件(如bzImage)e=>end: 结束st->read_config->parse_makefile->compile_files->link_files->generate_final->e

通过这个工作流程,Kbuild 把复杂的内核编译任务分解成了一个个有序的步骤,让内核编译变得更加可控和高效 。但在实际操作中,由于内核的复杂性以及各种环境因素,难免会出现一些报错,接下来我们就来看看常见的报错有哪些。

2.4 Kbuild 与 Make 的协同机制

Kbuild 和 Make 之间的协同工作堪称默契十足,它们就像一对配合多年的舞伴,在 Linux 内核编译的舞台上共同演绎出精彩的 “编译之舞”。Kbuild 通过定义一系列特殊的变量和目标,巧妙地利用 Make 的功能来实现内核的编译。

在内核源代码的每个子目录中,都存在一个 Kbuild 风格的 Makefile(通常命名为Makefile或Kbuild),这些 Makefile 中使用了 Kbuild 特有的变量和语法。当我们在命令行中执行make命令时,顶层的 Makefile 会被首先读取。顶层 Makefile 会根据配置文件(.config)和 Kbuild 定义的规则,递归地调用各个子目录中的 Makefile。在这个过程中,Make 负责执行具体的编译命令,而 Kbuild 则负责提供编译的规则和配置信息 。

以编译一个简单的内核模块为例,假设我们有一个名为my_module的内核模块,其源代码位于drivers/my_module/目录下,该目录下的 Makefile 内容如下:

obj-m += my_module.omy_module-objs := my_module_core.o my_module_utils.o

这里,obj-m变量告诉 Kbuild,my_module.o要被编译成模块,而my_module-objs变量指定了my_module.o是由my_module_core.o和my_module_utils.o这两个目标文件组成。当执行make命令时,顶层 Makefile 会根据 Kbuild 的规则,调用scripts/Makefile.build文件来处理这个目录。scripts/Makefile.build会读取该目录下的 Makefile,解析其中的变量和规则,然后调用 Make 执行具体的编译命令,如使用gcc编译my_module_core.c和my_module_utils.c生成对应的目标文件,最后将它们链接成my_module.ko模块文件 。

在整个编译过程中,Kbuild 通过与 Make 的紧密配合,实现了从源代码到内核模块或内核镜像的高效转换,确保了 Linux 内核编译的顺利进行。

2.5 GCC 核心作用与编译流程

聊透 Kbuild 和 Makefile 的构建规则后,必须补上内核编译的核心执行工具——GCC(GNU Compiler Collection),它是整个 Linux 内核编译的“底层工匠”,所有内核C语言源码、汇编源码,最终都要靠 GCC 完成从文本代码到机器码的转换,没有 GCC 支撑,Kbuild 再完善的构建规则也无法落地成可运行的内核镜像。很多新手觉得内核编译晦涩,本质是没理清“Kbuild管流程、GCC管编译”的分工逻辑,搞懂 GCC 核心作用和完整流程,能彻底打通内核编译的底层认知。

先明确 GCC 的核心作用:它是一款开源的多语言编译器集合,针对 Linux 内核开发,主要负责将C语言源码、汇编源码编译生成目标文件,同时处理语法检查、代码优化、符号解析、链接前置准备等核心工作。区别于普通应用层编译,内核编译对 GCC 要求极高,需要指定专属编译参数、关闭部分应用层优化、适配内核内存布局,GCC 会严格按照 Kbuild 传递的编译指令(ccflags-y等变量)执行,保证编译出的目标文件适配内核运行环境。

GCC 完整编译流程分为四大核心阶段,环环相扣,也是内核源码编译的底层路径:预处理(Preprocessing)→ 编译(Compilation)→ 汇编(Assembly)→ 链接(Linking)

①预处理(Pre - Processing):这是编译的第一步,就像是在正式翻译前对原文进行的整理和准备工作。预处理器会根据以字符 “#” 开头的预处理指令,对源代码进行一系列操作 。它会将源代码中包含的头文件(如#include指令)插入到原文件中,把宏定义(如#define指令)展开,还会根据条件编译命令(如#ifdef、#endif等)选择要使用的代码。例如,对于以下代码:

#include <stdio.h>#define PI 3.14159#ifdef DEBUG#define DEBUG_INFO printf("Debugging...\n")#else#define DEBUG_INFO#endifint main() {    DEBUG_INFO    float radius = 5.0;    float area = PI * radius * radius;    printf("The area of the circle is: %f\n", area);    return 0;}

预处理器会将stdio.h头文件的内容插入到代码中,将PI宏替换为3.14159,并且根据是否定义了DEBUG宏来决定是否保留DEBUG_INFO的内容。如果没有定义DEBUG宏,DEBUG_INFO将被替换为空。预处理器的输出结果通常是一个以.i为扩展名的文件,我们可以使用gcc -E命令来查看预处理后的代码:

gcc -E -o example.i example.c

②编译(Compiling):经过预处理后的代码,就进入了正式的 “翻译” 阶段,即编译。编译器会对预处理后的代码进行语法分析、语义分析和优化,检查代码的规范性、是否有语法错误等,以确定代码实际要做的工作。在检查无误后,编译器将代码 “翻译” 成汇编语言代码 。汇编语言是一种低级语言,它与机器语言非常接近,但仍然使用助记符来表示指令,便于人类阅读和理解。例如,对于上面的 C 代码,编译后生成的汇编代码可能如下(简化示例):

.file "example.c".section.rodata.LC0:   .string "The area of the circle is: %f\n".text.globl main.type main, @functionmain:    pushl %ebp    movl %esp%ebp   ...    flds.LC1    flds.LC1    fmulp %st(1), %st    flds.LC2    fmulp %st(1), %st    movl $0%eax    leave    ret

我们可以使用gcc -S命令来生成汇编代码文件,文件扩展名为.s

gcc -S -o example.s example.i

③汇编(Assembling):汇编阶段是将编译生成的汇编代码进一步转化为机器语言,也就是目标文件(Object File)。汇编器会将汇编代码中的每条指令翻译成对应的机器指令,并生成目标文件,目标文件通常以.o为扩展名 。目标文件是一种二进制文件,它包含了机器指令和一些符号表、重定位信息等,但还不能直接运行,因为它可能还依赖于其他的库文件或目标文件。例如,我们使用gcc -c命令来进行汇编:

gcc -c -o example.o example.s

④链接(Linking):链接是编译的最后一步,它的作用是将多个目标文件以及所依赖的库文件链接成一个可执行文件。在一个项目中,可能会有多个源文件,每个源文件编译后都会生成一个目标文件,同时,程序可能还会使用到系统库或第三方库中的函数。链接器会将这些目标文件和库文件中的代码和数据整合在一起,解决符号引用问题,最终生成一个可以在特定平台上运行的可执行文件 。例如,在我们的示例中,printf函数是在libc库中定义的,链接器会找到libc库,并将其中printf函数的实现链接到我们的可执行文件中。我们可以使用gcc命令直接生成可执行文件:

gcc -o example example.o

这四个步骤紧密相连,缺一不可,共同完成了从 C 代码到可执行二进制文件的华丽转变,为 Linux 内核的运行提供了坚实的基础。在 Kbuild 体系中,GCC 并不是单独手动调用,而是由 Kbuild 脚本自动调用,开发者通过 Kbuild 中的编译变量间接控制 GCC 行为,这也是内核编译和普通应用编译的核心区别。理解 GCC 这四个阶段,就能明白内核编译时的各类报错根源(比如预处理头文件缺失、编译语法错误、汇编指令不兼容、链接符号未定义),也能看懂 Kbuild 传递的各类编译选项对应的 GCC 指令,后续排查编译问题会事半功倍。

三、Kbuild 编译系统核心组件剖析

3.1 Kernel Makefile

Kernel Makefile 位于 Linux 内核源代码的顶层目录,宛如一座城市的总规划蓝图,是整个内核编译过程的核心控制文件 。它的主要职责是指定编译 Linux Kernel 目标文件(vmlinux)和模块(module) 。当我们执行内核编译命令时,这个文件会率先被读取,就像一场演出开始前,主持人会先宣读节目单一样 。它会根据读取到的内容,精心配置编译环境变量,为后续的编译工作搭建起一个稳定、有序的环境 。

对于大多数内核或驱动开发人员来说,Kernel Makefile 就像是一座已经建好的坚固大厦,几乎不需要进行任何修改 。它已经经过了无数次的优化和完善,能够很好地适应各种常见的内核编译需求 。开发人员更多的是基于它所提供的框架和规则,在其基础上进行内核模块的开发和定制 。例如,当我们要添加一个新的内核驱动模块时,并不需要修改 Kernel Makefile 的核心内容,而是通过在相应的子目录中编写 Kbuild Makefile 文件,来告知 Kernel Makefile 如何编译这个新的模块 。

3.2 Kbuild Makefile

Kbuild Makefile 是 Kbuild 编译系统的关键组成部分,它就像是各个子项目的详细施工图纸,用于具体编译内核或模块 。当 Kernel Makefile 完成解析后,Kbuild 便会依据它的指引,读取相关的 Kbuild Makefile,深入到各个子目录中,按照其中定义的规则,有条不紊地进行内核或模块的编译工作 。

Kbuild Makefile 拥有一套独特而严谨的语法,专门用于精准地指定哪些内容将被编译进内核,哪些将被编译为模块,以及对应的源文件究竟是哪些 。例如,在一个简单的 Kbuild Makefile 中,我们可能会看到这样的定义:

obj-y += my_driver.o

当一个模块由多个文件组成时,Kbuild Makefile 的语法会稍微复杂一些 。此时,我们需要使用模块名加 “-objs” 后缀的形式来定义模块的组成文件 。例如:

obj-$(CONFIG_MY_MODULE) += my_module.omy_module-objs := my_module_core.o my_module_utils.o

这意味着,当 “CONFIG_MY_MODULE” 配置选项被启用(值为 “y” 或 “m”)时,“my_module.o” 将被编译 。并且,“my_module.o” 是由 “my_module_core.o” 和 “my_module_utils.o” 这两个目标文件链接生成的 。这种灵活的语法设计,使得 Kbuild Makefile 能够轻松应对各种复杂的内核模块编译需求 。

3.3 ARCH Makefile

ARCH Makefile 位于 “ARCH/$(ARCH)/Makefile” 路径下,它就像是针对不同地区的特殊建筑规范,是系统对应平台的专属 Makefile 。Kernel Top Makefile 在执行过程中,会包含这个文件,以便获取平台相关的特定信息 。这些信息涵盖了目标平台的硬件特性、指令集架构、内存布局等关键内容,对于内核能够在特定平台上正确运行起着决定性的作用 。

由于 ARCH Makefile 主要涉及平台相关的底层细节,通常只有平台开发人员才会对其给予特别关注 。他们需要根据目标平台的具体特点,精心调整和优化 ARCH Makefile 中的内容,确保内核能够充分发挥目标平台的性能优势,并且与平台的硬件设备实现无缝对接 。例如,在针对 ARM 架构的平台开发中,平台开发人员可能需要在 ARCH Makefile 中指定 ARM 特定的启动代码、中断处理方式以及内存管理策略等 。而对于大多数普通的内核开发者来说,他们更多地是在通用的内核框架下进行开发,较少直接与 ARCH Makefile 打交道 。

3.4 scripts/Makefile.* 系列文件

scripts/Makefile.* 系列文件,宛如一套通用的建筑工具和标准库,包含了 Kbuild 体系的核心构建规则和工具定义,为整个内核编译过程提供了通用的构建逻辑 。这些文件是 Kbuild 编译系统的重要支撑,它们默默地在幕后工作,协调着各个编译环节,确保整个编译过程的顺利进行 。

在依赖解析方面,scripts/Makefile.* 系列文件发挥着关键作用 。它们会仔细分析各个源文件之间的依赖关系,就像梳理一张复杂的关系网,确保在编译过程中,所有依赖的文件都能被正确地编译和链接 。例如,当一个源文件依赖于某个头文件时,这些文件会指导 Kbuild 在编译时正确地找到并包含该头文件,避免因依赖缺失而导致编译失败 。

在目标编译过程中,scripts/Makefile.* 系列文件同样不可或缺 。它们定义了各种编译工具的使用方法和编译参数的设置规则,确保每个目标文件都能按照正确的方式进行编译 。无论是 C 语言源文件的编译,还是汇编文件的处理,都能在这些文件的指导下有条不紊地进行 。例如,它们会指定 GCC 编译器的版本、优化级别、调试信息生成方式等关键参数,以满足不同的编译需求 。

此外,scripts/Makefile.* 系列文件还在其他方面为内核编译提供了强大的支持 。比如,它们可以定义一些通用的编译目标,如 “clean” 目标用于清理编译生成的临时文件,“install” 目标用于将编译好的内核和模块安装到指定的位置等 。这些通用目标的定义,大大提高了内核编译过程的标准化和自动化程度,使得开发者能够更加高效地进行内核开发和维护 。

四、Kbuild 编译系统功能深度解读

4.1 模块化构建

在 Linux 内核编译中,模块化构建是 Kbuild 编译系统的一项核心功能,它为内核的构建和运行带来了极大的灵活性和可扩展性,就像搭建一个积木城堡,每个积木都是一个独立的模块,可以根据需要自由组合 。

Kbuild 编译系统通过 “obj-y” 和 “obj-m” 这两个关键变量,巧妙地实现了将内核功能划分为核心部分和可加载模块 。“obj-y” 变量用于指定哪些目标文件将被直接编译进内核,成为内核的核心组成部分,这些部分就像是城堡的主体结构,是内核运行不可或缺的基础 。例如,在一个简单的内核模块构建中,如果我们有一个名为 “kernel_core.o” 的目标文件,通过在 Kbuild 文件中添加 “obj-y += kernel_core.o”,就明确表示 “kernel_core.o” 将被直接编译进内核 。

而 “obj-m” 变量则用于指定哪些目标文件将被编译成可动态加载的模块,这些模块就像是城堡上可以随时添加或移除的装饰部件,为内核提供了额外的功能扩展 。当我们有一个名为 “driver_module.o” 的目标文件,希望将其编译成可动态加载的模块时,只需在 Kbuild 文件中添加 “obj-m += driver_module.o” 。这样,在系统运行时,用户可以根据实际需求,使用 insmod 或 modprobe 等命令动态地加载或卸载这些模块,无需重新编译整个内核 。

模块化构建对内核大小和灵活性产生了深远的影响 。从内核大小方面来看,通过将一些不常用的功能编译成可加载模块,而不是直接编译进内核,可以显著减小内核的体积 。这对于资源有限的嵌入式设备来说尤为重要,能够有效减少内存占用,提高系统的运行效率 。例如,在一个嵌入式 Linux 系统中,如果设备不需要网络功能,那么可以将网络相关的驱动和协议编译成模块,不加载这些模块时,内核就不会包含这些功能代码,从而减小了内核的大小 。

从灵活性角度而言,模块化构建使得内核能够根据不同的硬件环境和应用需求,灵活地调整自身的功能 。在一个服务器环境中,可能需要支持多种不同类型的存储设备,通过模块化构建,可以将各种存储设备的驱动编译成模块,根据实际连接的存储设备,动态加载相应的驱动模块,实现对不同存储设备的支持 。这种灵活性大大提高了内核的通用性和适应性,使其能够在各种不同的场景中发挥作用 。

4.2 依赖管理

依赖管理是 Kbuild 编译系统的另一项重要功能,它就像是一个智能的管家,能够自动处理源文件、头文件和配置之间错综复杂的依赖关系,确保整个内核编译过程的顺利进行 。

在 Linux 内核庞大而复杂的源代码体系中,源文件之间存在着广泛而紧密的依赖关系 。一个源文件往往需要依赖其他源文件提供的函数、变量或数据结构,同时还可能依赖特定的头文件来获取必要的声明和定义 。Kbuild 编译系统能够敏锐地捕捉到这些依赖关系,通过一系列巧妙的机制,自动处理它们 。

当我们在编译一个内核模块时,假设该模块包含多个源文件,如 “module_core.c” 和 “module_utils.c”,并且 “module_core.c” 需要调用 “module_utils.c” 中定义的函数 。在 Kbuild 文件中,我们可以通过 “obj-$(CONFIG_MY_MODULE) += my_module.o” 和 “my_module-objs := module_core.o module_utils.o” 这样的定义,明确指定 “my_module.o” 是由 “module_core.o” 和 “module_utils.o” 链接生成的 。Kbuild 编译系统在编译过程中,会自动根据这些定义,先编译 “module_core.c” 和 “module_utils.c” 生成对应的目标文件,然后再将它们链接成 “my_module.o” 。

头文件的依赖关系同样复杂 。源文件通常需要包含各种头文件,以获取函数原型、宏定义和结构体声明等重要信息 。Kbuild 编译系统会自动搜索指定的头文件路径,确保在编译过程中能够正确地包含所需的头文件 。例如,如果我们在源文件中使用了 “#include <linux/module.h>” 这样的语句,Kbuild 编译系统会在默认的内核头文件路径中查找 “module.h” 文件,并将其包含进来 。

配置之间的依赖关系也是 Kbuild 编译系统依赖管理的重要内容 。在 Linux 内核的配置过程中,各个配置选项之间存在着复杂的依赖关系 。有些配置选项只有在其他特定选项被启用时才会生效,有些则相互排斥 。Kbuild 编译系统会根据.config 文件中记录的配置选择,自动处理这些依赖关系,确保编译过程中使用的配置选项是合理且一致的 。

为了更直观地说明依赖管理在实际编译中的作用,我们来看一个具体的例子 。假设有一个网络驱动模块,它依赖于通用的网络协议栈代码和一些特定的硬件头文件 。在编译这个网络驱动模块时,如果 Kbuild 编译系统没有正确处理依赖关系,可能会出现找不到函数定义、类型未声明等错误,导致编译失败 。而有了 Kbuild 的依赖管理功能,它会自动识别并编译网络协议栈代码,同时确保正确包含硬件头文件,使得网络驱动模块能够顺利编译 。这种依赖管理机制大大减轻了开发者手动管理依赖关系的负担,提高了内核编译的效率和准确性 。

4.3 编译控制

编译控制是 Kbuild 编译系统赋予开发者的一项强大能力,它允许开发者通过一系列变量,如 ccflags-y、asflags-y 和 ldflags-y 等,精确地指定编译选项,从而对内核编译过程进行细致入微的控制 。

ccflags-y 变量主要用于指定 C 编译器(如 GCC)的编译选项,它就像是给编译器下达的一组详细指令,能够影响 C 源文件的编译行为 。通过 ccflags-y,我们可以设置优化级别、调试信息开关、宏定义以及头文件搜索路径等关键参数 。例如,我们可以使用 “ccflags-y += -O2” 来启用二级优化,这将使编译器对生成的目标代码进行优化,提高代码的执行效率 。如果我们希望在编译过程中生成调试信息,方便后续调试,可以使用 “ccflags-y += -g” 选项 。此外,还可以通过 “ccflags-y += -DDEBUG” 来定义一个名为 DEBUG 的宏,在源代码中可以根据这个宏来控制调试代码的编译和执行 。

asflags-y 变量则专门用于指定汇编编译器的编译选项 。在 Linux 内核中,有些代码可能是用汇编语言编写的,这些代码通常用于实现一些底层的硬件操作或特定的功能 。asflags-y 变量可以让我们为汇编编译器设置诸如目标架构、指令集等选项 。比如,对于 ARM 架构的汇编代码,我们可以使用 “asflags-y += -march=armv8-a” 来指定目标架构为 ARMv8-a,确保汇编代码能够正确地在该架构上编译和运行 。

ldflags-y 变量主要用于指定链接器的链接选项 。当所有的目标文件都编译完成后,链接器会将它们链接成最终的内核镜像或模块 。ldflags-y 变量可以控制链接器的行为,如指定链接脚本、设置输出文件格式、添加库路径等 。假设我们有一个自定义的链接脚本 “my_linker.ld”,可以使用 “ldflags-y += -T my_linker.ld” 来告诉链接器使用这个链接脚本进行链接,从而实现对链接过程的精细控制 。

为了更好地理解如何使用这些变量进行编译控制,我们来看一个具体的示例 。假设我们正在开发一个内核模块,需要启用调试功能,并为其添加一些自定义的宏定义 。在 Kbuild 文件中,我们可以这样设置:

ccflags-y += -g -DDEBUG -D CUSTOM_MACRO=100

上述代码中,“-g” 选项用于生成调试信息,“-DDEBUG” 定义了 DEBUG 宏,方便在代码中进行调试相关的操作,“-D CUSTOM_MACRO=100” 则定义了一个名为 CUSTOM_MACRO 的自定义宏,并赋值为 100 。这样,在编译这个内核模块时,编译器会根据这些选项进行编译,生成带有调试信息且包含自定义宏定义的目标文件 。

通过灵活运用 ccflags-y、asflags-y 和 ldflags-y 等变量,开发者可以根据具体的需求和场景,对内核编译过程进行个性化的控制,从而生成满足特定要求的内核镜像和模块 。

4.4 跨平台支持

跨平台支持是 Kbuild 编译系统的一项卓越特性,它使得 Linux 内核能够在各种不同的硬件平台上高效运行,就像一位万能的旅行者,可以轻松适应不同的地域环境 。

Kbuild 编译系统与 Kconfig 系统紧密集成,共同实现了强大的跨平台支持功能 。Kconfig 系统负责定义内核的各种配置选项,这些选项涵盖了硬件设备支持、功能特性启用等各个方面 。而 Kbuild 编译系统则根据 Kconfig 系统生成的.config 文件,准确地获取配置信息,并据此进行内核的编译和构建 。

在不同的硬件平台上,硬件的特性和需求各不相同 。x86 架构的处理器和 ARM 架构的处理器在指令集、内存管理等方面存在显著差异 。通过 Kbuild 与 Kconfig 的集成,开发者可以针对不同的平台,通过 make menuconfig 等命令交互式地配置内核选项 。当我们在基于 x86 架构的计算机上编译内核时,执行 “make menuconfig” 命令,会弹出一个基于文本菜单的交互式配置界面 。在这个界面中,我们可以根据 x86 平台的特点,选择启用对 x86 特定硬件设备的支持,如 Intel 网卡驱动、AMD 显卡驱动等 。同样,当在基于 ARM 架构的嵌入式设备上编译内核时,通过 “make menuconfig” 命令进入配置界面后,可以根据 ARM 平台的需求,选择启用对 ARM 特定硬件设备的支持,如 ARM 架构的串口驱动、SPI 驱动等 。

这种交互式的配置方式极大地提高了内核配置的便捷性和可视化程度 。在配置界面中,每个配置选项都有清晰的描述和当前状态,开发者可以通过简单的键盘操作,如上下移动光标、按下回车键等,自由地选择是否启用某个功能、是否添加某个驱动等 。配置完成后,保存的.config 文件将记录所有的配置选择,为后续的内核编译提供准确的指导 。

以一个实际的例子来说明,假设我们要为一款基于 ARM 架构的开发板编译内核 。通过执行 “make menuconfig” 命令进入配置界面后,我们可以在 “Device Drivers” 菜单中,根据开发板上实际连接的硬件设备,选择启用对应的驱动选项 。如果开发板上连接了一个 USB 摄像头,我们可以在配置界面中找到 “USB Camera Support” 选项,将其设置为 “y”(表示编译进内核)或 “m”(表示编译成模块) 。这样,在后续的内核编译过程中,Kbuild 编译系统会根据.config 文件中的配置信息,正确地编译和链接相关的驱动代码,使得内核能够支持 USB 摄像头的使用 。通过这种方式,Kbuild 编译系统与 Kconfig 系统的集成,实现了 Linux 内核在不同硬件平台上的高效配置和编译,大大增强了 Linux 内核的跨平台适应性和通用性 。

五、实例演示:用 Kbuild 编译一个简单内核模块

5.1 创建模块源文件

下面是一个简单的内核模块源文件示例,我们将其命名为hello_module.c

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>// 加载时执行的函数staticint __init hello_init(void){    printk(KERN_INFO "Hello, world! This is a simple kernel module.\n");    return 0;}// 模块卸载时执行的函数staticvoid __exit hello_exit(void){    printk(KERN_INFO "Goodbye, world! The simple kernel module is being unloaded.\n");}// 声明模块的初始化函数和退出函数module_init(hello_init);module_exit(hello_exit);// 声明模块的许可证MODULE_LICENSE("GPL");

这个模块的功能非常简单,主要实现了两个函数:hello_init和hello_exit。当模块被加载到内核时,hello_init函数会被调用,它使用printk函数在内核日志中输出一条信息,表示模块已成功加载 。printk函数类似于标准 C 库中的printf函数,但它是用于内核空间的输出,KERN_INFO 是一个日志级别宏,表示这是一条普通的信息日志 。

当模块从内核中卸载时,hello_exit函数会被调用,同样使用printk函数在内核日志中输出一条信息,表示模块正在被卸载 。module_init和module_exit宏用于声明模块的初始化函数和退出函数,这两个宏是内核模块编程中非常重要的部分,它们告诉内核在加载和卸载模块时应该调用哪些函数 。

最后,MODULE_LICENSE("GPL")用于声明模块的许可证为 GPL(General Public License),这是 Linux 内核中常用的许可证,确保模块的开源和可共享性 。

5.2 编写 Kbuild Makefile

接下来,我们需要编写一个 Kbuild Makefile 来编译这个内核模块。在与hello_module.c相同的目录下,创建一个名为Makefile的文件,内容如下:

obj-m += hello_module.oall:    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

在这个 Makefile 中,obj-m += hello_module.o这一行至关重要,它明确告诉 Kbuild 编译系统,hello_module.o这个目标文件将被编译成可动态加载的模块 。也就是说,最终会生成一个名为hello_module.ko的内核模块文件 。all目标定义了编译模块的具体操作 。make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules这一命令的含义如下:

  1. -C选项表示切换到指定的目录,这里/lib/modules/$(shell uname -r)/build是当前系统内核源代码的构建目录 。$(shell uname -r)会获取当前系统正在运行的内核版本号,通过这个版本号可以找到对应的内核源代码构建目录 。例如,如果当前系统内核版本是 5.10.0,那么这个目录可能是/lib/modules/5.10.0/build 。
  2. M=$(PWD)表示将当前目录($(PWD)即 Print Working Directory,当前工作目录)作为模块源代码的目录传递给内核构建系统 。这意味着内核构建系统会在当前目录下查找模块的源文件并进行编译 。
  3. modules是内核构建系统的一个目标,表示编译模块 。

clean目标则定义了清理编译生成文件的操作 。make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean这一命令会切换到内核源代码构建目录,并清理当前目录下与模块编译相关的所有生成文件,包括.o文件、.ko文件以及其他临时文件,使目录恢复到编译前的状态 。

5.3 执行编译过程

在完成模块源文件和 Kbuild Makefile 的编写后,就可以执行编译过程了。首先,打开终端,切换到包含hello_module.c和Makefile的目录 。然后,执行以下命令:

make

执行make命令后,系统会读取当前目录下的Makefile文件,并按照其中的规则进行编译 。在编译过程中,你会看到一系列的输出信息,这些信息展示了编译的详细过程 。首先,系统会切换到内核源代码的构建目录,然后开始编译hello_module.c文件 。编译器会根据Makefile中指定的编译选项,对源文件进行预处理、编译、汇编等操作,生成hello_module.o目标文件 。接着,链接器会将hello_module.o链接成最终的内核模块文件hello_module.ko 。编译过程中的输出信息可能类似于以下内容:

make -C /lib/modules/5.10.0/build M=/home/user/hello_module modulesmake[1]: Entering directory '/usr/src/linux-headers-5.10.0'  CC [M]  /home/user/hello_module/hello_module.o  Building modules, stage 2.  MODPOST 1 modules  CC      /home/user/hello_module/hello_module.mod.o  LD [M]  /home/user/hello_module/hello_module.komake[1]: Leaving directory '/usr/src/linux-headers-5.10.0'

从这些输出信息中,我们可以清晰地看到编译的各个步骤 。CC [M]表示正在编译模块相关的 C 文件,这里是hello_module.o 。Building modules, stage 2.表示进入模块构建的第二阶段,主要进行模块的链接和后期处理 。MODPOST表示正在进行模块的后期处理,如生成模块的依赖信息等 。CC和LD [M]则分别表示正在编译模块的其他相关文件和链接生成最终的模块文件hello_module.ko 。

当编译完成后,如果没有出现任何错误信息,说明编译成功 。此时,在当前目录下会生成一个hello_module.ko文件,这个文件就是我们编译好的内核模块 。我们可以使用insmod命令将其加载到内核中,使用rmmod命令将其从内核中卸载 。例如,加载模块的命令如下:

sudo insmod hello_module.ko

卸载模块的命令如下:

sudo rmmod hello_module

通过以上步骤,我们成功地使用 Kbuild 编译系统编译了一个简单的内核模块,并了解了整个编译过程和相关命令的使用 。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-03-27 17:23:28 HTTP/2.0 GET : https://f.mffb.com.cn/a/481406.html
  2. 运行时间 : 0.305819s [ 吞吐率:3.27req/s ] 内存消耗:4,781.88kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=58c68ff3a06a4829a57af584d2a63b70
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000929s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001789s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000702s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.006638s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001566s ]
  6. SELECT * FROM `set` [ RunTime:0.003863s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001780s ]
  8. SELECT * FROM `article` WHERE `id` = 481406 LIMIT 1 [ RunTime:0.006933s ]
  9. UPDATE `article` SET `lasttime` = 1774603409 WHERE `id` = 481406 [ RunTime:0.016622s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.001248s ]
  11. SELECT * FROM `article` WHERE `id` < 481406 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.018752s ]
  12. SELECT * FROM `article` WHERE `id` > 481406 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.010795s ]
  13. SELECT * FROM `article` WHERE `id` < 481406 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.034954s ]
  14. SELECT * FROM `article` WHERE `id` < 481406 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.004892s ]
  15. SELECT * FROM `article` WHERE `id` < 481406 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.007206s ]
0.309855s