linux 系统移植(第八期)----Linux 内核的获取、编译、顶层 Makefile 的简介-- Ubuntu20.04

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

[一、Linux 内核获取](#一、Linux 内核获取)

[二、Linux 内核初次编译](#二、Linux 内核初次编译)

[三、Linux 工程目录分析](#三、Linux 工程目录分析)

[1、arch 目录](#1、arch 目录)

[2、block 目录](#2、block 目录)

[3、crypto 目录](#3、crypto 目录)

[4、Documentation 目录](#4、Documentation 目录)

[5、drivers 目录](#5、drivers 目录)

[6、firmware 目录](#6、firmware 目录)

[7、fs 目录](#7、fs 目录)

[8、include 目录](#8、include 目录)

[9、init 目录](#9、init 目录)

[10、ipc 目录](#10、ipc 目录)

[11、kernel 目录](#11、kernel 目录)

[12、lib 目录](#12、lib 目录)

[13、mm 目录](#13、mm 目录)

[14、net 目录](#14、net 目录)

[15、samples 目录](#15、samples 目录)

[16、scripts 目录](#16、scripts 目录)

[17、security 目录](#17、security 目录)

[18、sound 目录](#18、sound 目录)

[19、tools 目录](#19、tools 目录)

[20、usr 目录](#20、usr 目录)

[21、virt 目录](#21、virt 目录)

[22、.config 文件](#22、.config 文件)

[23、Kbuild 文件](#23、Kbuild 文件)

[24、Kconfig 文件](#24、Kconfig 文件)

[25、Makefile 文件](#25、Makefile 文件)

[26、README 文件](#26、README 文件)

[四、顶层 Makefile 简介](#四、顶层 Makefile 简介)

1、版本号

[2、MAKEFLAGS 变量](#2、MAKEFLAGS 变量)

3、命令输出

4、静默输出

5、设置编译结果输出目录

6、代码检查

7、模块编译

8、设置目标架构和交叉编译器

[9、调用 scripts/Kbuild.include 文件](#9、调用 scripts/Kbuild.include 文件)

10、交叉编译工具变量设置

11、头文件路径变量

12、导出变量

总结


前言

前几期我们重点讲解了如何移植 uboot 到 I.MX6U-ALPHA 开发板上,从本章开始我们就开始学习如何移植 Linux 内核。同 uboot 一样,在具体移植之前,我们先来学习一下 Linux 内核的顶层 Makefile 文件,因为顶层 Makefile 控制着 Linux 内核的编译流程。


一、Linux 内核获取

可以从官网获取:The Linux Kernel Archives

从上图可以看出最新的稳定版 Linux 已经到了 6系列了,NXP 会从 https://www.kernel.org 下载某个版本的 Linux 内核,然后将其移植到自己的 CP上,测试成功以后就会将其开放给 NXP 的 CPU 开发者。开发者下载 NXP 提供的 Linux 内核,然后将其移植到自己的产品上,本次我们就使用NXP 提供的 Linux 源码:> linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2

二、Linux 内核初次编译

编译内核之前需要先在 ubuntu 上安装 lzop 库,否则内核编译会失败!命令如下:

复制代码
sudo apt-get install lzop

先看一下如何编译 Linux 源码,这里编译 I.MX6U-ALPHA 开发板移植好的 Linux 源码,为:linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7.tar.bz2

在 Ubuntu 中新建名为" alientek_linux " 的 文 件夹,然后将linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7.tar.bz2拷贝到这个文件夹并解压

输入以下命令:

复制代码
tar -vxjf linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7.tar.bz2

解压完成后的的 Linux 源码根目录如下图所示:

以 EMMC 核心板为例,讲解一下如何编译出对应的 Linux 镜像文件。新建名为 "mx6ull_alientek_emmc.sh"的 shell 脚本,如下图所示:

然后在这个 shell 脚本里面输入如下所示内容:

复制代码
#!/bin/sh

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16

第 2 行,执行"make distclean",清理工程,所以 mx6ull_alientek_emmc.sh 每次都会清理一

下工程。

第 3 行,执行"make xxx_defconfig",配置工程。

第 4 行,执行"make menuconfig",打开图形配置界面。

第 5 行,执行"make",编译 Linux 源码。

从这个脚本中可以看出Linux 的编译过程基本和 uboot 一样,都要先执行"make xxx_defconfig"来配置一下,然后在执行"make"进行编译。如果需要使用图形界面配置的话就执行"make menuconfig"。

使用 chmod 给予 mx6ull_alientek_emmc.sh 可执行权限。

复制代码
chmod 777 mx6ull_alientek_emmc.sh

然后运行此 shell 脚本,命令如下:

复制代码
./mx6ull_alientek_emmc.sh

注意:编译的时候可能会报下边的错误

原因1:为链接错误由 yylloc 在 parser(dtc-parser)和 lexer(dtc-lexer)中都被定义导致。

方法:将yylloc 在词法器中的定义改为 extern,以消除重复定义错误。

原因2:是没有安装 lzop 库,输入如下命令安装 lzop 库即可解决:

复制代码
sudo apt-get install lzop

lzop 库安装完成以后在重新编译一下 Linux 内核即可。

编译完会弹出 Linux 图形配置界面如下图所示:

Linux 的图行界面配置和 uboot 是一样的,这里我们不需要做任何的配置,直接按两下 ESC键退出,退出图形界面以后会自动开始编译 Linux。等待编译完成,编译完成如下:

编译完成以后就会在 arch/arm/boot 这个目录下生成一个叫做 zImage 的文件,zImage 就是

我们要用的 Linux 镜像文件。另外也会在 arch/arm/boot/dts 下生成很多.dtb 文件,这些.dtb 就是

设备树文件。

三、Linux 工程目录分析

编译后的 Linux 目录如下图:

其中重要的文件夹或文件的含义见下表:

重点关注下边文件夹。

1 arch 目录

这个目录是和架构有关的目录,比如 arm、arm64、avr32、x86 等等架构。每种架构都对应

一个目录,以 arch/arm 为例,其一部分子目录如图:

这些子目录用于控制系统引导、系统调用、动态调频、主频设置等,arch/arm/configs 目录是不同平台的默认配置文件:xxx_defconfig

在这个目录里就包含有 I.MX6U-ALPHA 开发板的默认配置文件:imx_v7_defconfig,执行"make imx_v7_defconfig"即可完成配置。

arch/arm/boot/dts 目录里面是对应开发平台的设备树文件,如下图所示:

arch/arm/boot 目录下会保存编译出来的 Image 和 zImage 镜像文件,而 zImage 就是我们要

用的 linux 镜像文件。

arch/arm/mach-xxx 目录分别为相应平台的驱动和初始化文件,比如 mach-imx 目录里面就

I.MX 系列 CPU 的驱动和初始化文件。

2、block 目录

block 是 Linux 下块设备目录,像 SD 卡、EMMC、NAND、硬盘等存储设备就属于块设备,block 目录中存放着管理块设备的相关文件。

3、crypto 目录

crypto 目录里面存放着加密文件,比如常见的 crc、crc32、md4、md5、hash 等加密算法。

4、Documentation 目录

此目录里面存放着 Linux 相关的文档,如果要想了解 Linux 某个功能模块或驱动架构的功能,就可以在 Documentation 目录中查找有没有对应的文档。

5、drivers 目录

驱动目录文件,此目录根据驱动类型的不同,分门别类进行整理,比如 drivers/i2c 就是 I2C 相关驱动目录,drivers/gpio 就是 GPIO 相关的驱动目录,这是我们学习的重点。

6、firmware 目录

此目录用于存放固件。

7、fs 目录

此目录存放文件系统,比如 fs/ext2fs/ext4fs/f2fs 等,分别是 ext2、ext4 和 f2fs 等文件系统。

8、include 目录

头文件目录。

9、init 目录

此目录存放 Linux 内核启动的时候初始化代码。

10、ipc 目录

IPC 为进程间通信,ipc 目录是进程间通信的具体实现代码。

11、kernel 目录

Linux 内核代码。

12、lib 目录

lib 是库的意思,lib 目录都是一些公用的库函。

13、mm 目录

此目录存放内存管理相关代码。

14、net 目录

此目录存放网络相关代码。

15、samples 目录

此目录存放一些示例代码文件。

16、scripts 目录

脚本目录,Linux 编译的时候会用到很多脚本文件,这些脚本文件就保存在此目录中。

17、security 目录

此目录存放安全相关的文件。

18、sound 目录

此目录存放音频相关驱动文件,音频驱动文件并没有存放到 drivers 目录中,而是单独的目

录。

19、tools 目录

此目录存放一些编译的时候使用到的工具。

20、usr 目录

此目录存放与 initramfs 有关的代码。

21、virt 目录

此目录存放虚拟机相关文件。

22、.config 文件

跟 uboot 一样,.config 保存着 Linux 最终的配置信息,编译 Linux 的时候会读取此文件中

的配置信息。最终根据配置信息来选择编译 Linux 哪些模块,哪些功能。

23、Kbuild 文件

有些 Makefile 会读取此文件。

24、Kconfig 文件

图形化配置界面的配置文件。

25 Makefile 文件

Linux 顶层 Makefile 文件,建议好好阅读一下此文件。

26 README 文件

此文件详细讲解了如何编译 Linux 源码,以及 Linux 源码的目录信息,建议仔细阅读一下此文件。

关于 Linux 源码目录就分析到这里,接下来分析一下 Linux 的顶层 Makefile。

四、顶层 Makefile 简介

Linux 的顶层 Makefile 和 uboot 的顶层 Makefile 非常相似,因为 uboot 参考了 Linux。

顶层 Makefile 一开始就是 Linux 内核的版本号,如下所示:

1 、版本号

复制代码
VERSION = 4
PATCHLEVEL = 1
SUBLEVEL = 15
EXTRAVERSION =
NAME = Series 4800

可以看出,Linux 内核版本号为 4.1.15。

2、MAKEFLAGS 变量

MAKEFLAGS 变量设置如下所示:

复制代码
MAKEFLAGS += -rR --include-dir=$(CURDIR)

3 、命令输出

Linux 编译的时候也可以通过"V=1"来输出完整的命令,这个和 uboot 一样。相关代码如下:

复制代码
ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif

ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

4 、静默输出

Linux 编译的时候使用"make -s"就可实现静默编译,编译的时候就不会打印任何的信息,

同 uboot 一样,相关代码如下:

复制代码
ifneq ($(filter 4.%,$(MAKE_VERSION)),)  # make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
  quiet=silent_
endif
else                      # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
  quiet=silent_
endif
endif

export quiet Q KBUILD_VERBOSE

5 、设置编译结果输出目录

Linux 编译的时候使用"O=xxx"即可将编译产生的过程文件输出到指定的目录中,相关代

码如下:

复制代码
ifeq ($(KBUILD_SRC),)

# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
ifeq ("$(origin O)", "command line")
  KBUILD_OUTPUT := $(O)
endif

endif

6 、代码检查

Linux 也支持代码检查,使用命令"make C=1"使能代码检查,检查那些需要重新编译的

文件。"make C=2"用于检查所有的源码文件,顶层 Makefile 中的代码如下:

复制代码
ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif

ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif

7 、模块编译

Linux 允许单独编译某个模块,使用命令"make M=dir"即可,顶层 Makefile 中的代码如下:

复制代码
# Use M=dir to specify directory of external module to build
# Old syntax make ... M=$(PWD) is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
ifdef SUBDIRS
  KBUILD_EXTMOD ?= $(SUBDIRS)
endif

ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

# If building an external module we do not care about the all: rule
# but instead .all depend on modules
PHONY += all
ifeq ($(KBUILD_EXTMOD),)
_all: all
else
_all: modules
endif

ifeq ($(KBUILD_SRC),)
  # building in the source tree
  srctree := .
else
  ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR)))
    # building in a subdirectory of the source tree
    srctree := ..
  else
    srctree := $(KBUILD_SRC)
  endif
endif

objtree	:= .
src	:= $(srctree)
obj	:= $(objtree)

VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD))

export srctree objtree VPATH

8 、设置目标架构和交叉编译器

同 uboot 一样,Linux 编译的时候需要设置目标板架构ARCH 和交叉编译器 CROSS_COMPILE,

在顶层 Makefile 中代码如下:

复制代码
ARCH		?= $(SUBARCH)
CROSS_COMPILE	?= $(CONFIG_CROSS_COMPILE:"%"=%)

为了方便,一般直接修改顶层 Makefile 中的 ARCH 和 CROSS_COMPILE,直接将其设置

为对应的架构和编译器,修改如下:

复制代码
ARCH           ?= arm
CROSS_COMPILE  ?= arm-linux-gnueabihf-

设置好以后我们就可以使用如下命令编译 Linux 了:

复制代码
make xxx_defconfig    // 使用默认配置文件配置 Linux
make menuconfig       // 启动图形化配置界面
make -j16             // 编译 Linux

9 、调用 scripts/Kbuild.include 文件

同 uboot 一样,Linux 顶层 Makefile 也会调用文件 scripts/Kbuild.include,顶层 Makefile 相

应代码如下:

复制代码
# We need some generic definitions (do not try to remake the file).
scripts/Kbuild.include: ;
include scripts/Kbuild.include

10 、交叉编译工具变量设置

顶层 Makefile 中其他和交叉编译器有关的变量设置如下:

复制代码
AS	= $(CROSS_COMPILE)as
LD	= $(CROSS_COMPILE)ld
CC	= $(CROSS_COMPILE)gcc

CPP	= $(CC) -E
AR	= $(CROSS_COMPILE)ar
NM	= $(CROSS_COMPILE)nm
STRIP	= $(CROSS_COMPILE)strip
OBJCOPY	= $(CROSS_COMPILE)objcopy
OBJDUMP	= $(CROSS_COMPILE)objdump

LA、LD、CC 等这些都是交叉编译器所使用的工具。

11 、头文件路径变量

顶层 Makefile 定义了两个变量保存头文件路径:USERINCLUDE 和 LINUXINCLUDE,相

关代码如下:

复制代码
381 USERINCLUDE	:= \
382 	-I$(srctree)/arch/$(hdr-arch)/include/uapi \
383 	-Iarch/$(hdr-arch)/include/generated/uapi \
384 	-I$(srctree)/include/uapi \
385 	-Iinclude/generated/uapi \
386 		-include $(srctree)/include/linux/kconfig.h
387 
388 # Use LINUXINCLUDE when you must reference the include/ directory.
389 # Needed to be compatible with the O= option
390 LINUXINCLUDE	:= \
391 	-I$(srctree)/arch/$(hdr-arch)/include \
392 	-Iarch/$(hdr-arch)/include/generated/uapi \
393 	-Iarch/$(hdr-arch)/include/generated \
394 	$(if $(KBUILD_SRC), -I$(srctree)/include) \
395 	-Iinclude \
396 	$(USERINCLUDE)

第 381~386 行是 USERINCLUDE 是 UAPI 相关的头文件路径,第 390~396 行是LINUXINCLUDE 是 Linux 内核源码的头文件路径。

12 、导出变量

顶层 Makefile 会导出很多变量给子 Makefile 使用,导出的这些变量如下:

复制代码
export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION
export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP
export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE
export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS

export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KASAN
export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
export KBUILD_ARFLAGS

总结

对Linux 内核的获取,编译,顶层 Makefile 进行了介绍。

相关推荐
leo03081 小时前
Ubuntu (NVIDIA Jetson) 开启 Wi-Fi 后系统高延迟、Ping 不通甚至硬死机排查全过程
linux·运维·ubuntu
Ha_To1 小时前
2026.1.16 Linux磁盘实验
linux·运维·服务器
2023自学中2 小时前
嵌入式系统中的非易失性存储设备
linux·嵌入式硬件
历程里程碑2 小时前
Linux 1 指令(1)入门:6大基础指令详解
linux·运维·服务器·c语言·开发语言·数据结构·c++
egoist20232 小时前
[linux仓库]线程池[线程·玖]
linux·运维·服务器·线程池
kaoa00010 小时前
Linux入门攻坚——62、memcached使用入门
linux·运维·memcached
model200511 小时前
alibaba linux3 系统盘清理
linux·运维·服务器
WG_1711 小时前
Linux:动态库加载总结_进程间通信+进程池 + 进程IPC(27/28/29/30/31/32)
linux·运维·服务器
小赵还有头发11 小时前
安装 RealSense SDK (驱动层)
linux