ARM9嵌入式Linux开发-Linux基础知识

目录

 

1 Linux简介

1.1 Linux的内核版本

1.2 Linux的发展历史

1.3 Linux的发行版本

1.4 Linux内核源码目录结构

2  Linux内核的配置和编译

2.1 Linux的配置

2.2  Linux内核的编译

2.2.1 Linux的Makefile体系

2.2.2 Linux内核文件编译

2.2.3 Makefile如何决定编译哪些文件

2.3.4 Makefile是怎样编译这些文件的?

2.3.5 Makefile是怎样连接这些文件

2.3.6 Makefile分析的总结

3 Linux内核的Kconfig分析

3.1 config

3.2 menu

3.3 choice

3.4 comment

3.5 source

5.编译Linux内核


1 Linux简介

1.1 Linux的内核版本

ARM9嵌入式Linux开发-Linux基础知识_第1张图片

1.2 Linux的发展历史

  • Linux内核的最初版本是1991年Linux Torvalds(林纳斯·托瓦兹)为他的80386开发的一个类Minix操作系统;
  • Linux 1.0的官方版本在1994年3月发布,支持386,进支持单CPU系统;
  • Linux 1.2于1995年3月发布,是第一个支持多平台(Alpha,Sparc,Mips等)的官方版本;
  • Linux 2.0在1996年6月发布,包含了很多新平台的支持,最重要的是第一个支持SMP(对称多处理器)体系结构的内核版本;
  • Linux 2.2在1999年1月发布,带来了SMP系统性能的极大提升,支持更多的硬件;
  • Linux 2.4于2001年1月发布,进一步提升了SMP系统的扩展性,同时集成了很多用于支持桌面系统的特性,内置即插即用等;
  • Linux 2.6于2003年12月发布,在2.4的基础上做了极大的改进,
  • 2.6内核支持更多的平台,使用了新的调度器,内核可抢占,I/O子系统也经历了很大的修改,模块子系统、文件系统都做了大量的改进等;
  • Linux 3.0于2011年7月发布。其特性包括:支持POSIX警报计时器,BPF包过滤器JIT编译器,新的sendmmsg()系统调用,ICMP socket,支持XEN dom0 ,改进Btrfs性能,Wake on WLAN支持等。

1.3 Linux的发行版本

Linux主要作为Linux发行版(通常被称为"distro")的一部分而使用。这些发行版由个人、松散组织的团队、商业机构和志愿者组织编写。它们通常包括了其他的系统软件和应用软件,以及一个用来简化系统初始安装的安装工具,和让软件安装升级的集成管理器。     

发行版为许多不同的目的而制作,包括对不同计算机结构的支持,对一个具体区域或语言的本地化,实时应用,和嵌入式系统,甚至许多版本故意地只加入免费软件。     

目前,超过三百个发行版被积极的开发,最普遍被使用的发行版有大约十二个。

一个典型的Linux发行版包括:Linux内核,一些GNU程序库和工具,命令行shell,图形界面的X Window系统和相应的桌面环境,如KDE或GNOME,并包含数千种从办公套件,编译器,文本编辑器到科学工具的应用软件。     

目前最著名的发行版有Debian,红帽(RedHat)、Ubuntu、Suse、CentOS、Fedora等。     

国内比较著名的linux版本:红旗Linux,深度。

1.4 Linux内核源码目录结构

ARM9嵌入式Linux开发-Linux基础知识_第2张图片

2  Linux内核的配置和编译

2.1 Linux的配置

内核提供了多种不同的工具来简化内核的配置:     

make config最简单的一种是字符界面下命令行工具。这个工具会依次遍历内核所有的配置项,要求用户进行逐项的选择配置。这个工具会耗费用户太多时间,除非万不得以(你的编译主机不支持其他配置工具)一般不建议使用。

make menuconfig。基于文本的,利用ncurse库编制的图形界面工具,键盘操作。相信以前对2.4内核比较熟悉的用户一定不会陌生。make menuconfig的界面

ARM9嵌入式Linux开发-Linux基础知识_第3张图片

 

make xconfig。在2.6内核中提供了更漂亮和方便的基于X11的图形配置工具,就是说你要在KDE、GNOME之类的X桌面环境下才可用,支持鼠标。当用户使用这个工具对Linux内核进行配置时,界面下方会出现这个配置项相关的帮助信息和简单描述。make xconfig的界面如下:

ARM9嵌入式Linux开发-Linux基础知识_第4张图片

make oldconfig。但是当你修改过配置文件之后,可以使用这个命令来验证和更新配置。    

2.2  Linux内核的编译

2.2.1 Linux的Makefile体系

当用户完成配置后,配置工具会自动生成.config文件,它被保存在内核代码树的根目录下。用户可以很容易找到它,当然用户也可以直接对这个文件进行简单的修改。     

Linux内核要编译哪些文件,怎样编译这些文件以及怎样连接这些文件,这都是通过Makefile来实现。     

Makefile是根据配置的情况,构造出需要编译的源文件列表,然后分别编译,并把目标代码链接到一起,最终形成Linux内核二进制文件。 当一切工作完成以后,用户只需要简单键入make,剩下所有的工作Makefile就会自动替你完成了。

从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同,尤其对于Linux内核模块的编译。Linux的Makefile体系由如下几部分组成:

  • 顶层 Makefile:顶层Makefile通过读取配置文件,递归编译内核代码树的相关目录,从而产生两个重要的目标文件:vmlinux和模块。
  • ARCH Makefile:位于arch/$(ARCH)目录下,为顶层Makefile提供与具体硬件体系结构相关的信息。
  • 公共编译规则定义文件:包括Makefile.build 、Makefile.clean、Makefile.lib、Makefile.host等文件组成。这些文件位于scripts目录中,定义了编译需要的公共的规则和定义。    
  • 内核配置文件 .config:通过调用make menuconfig或者make xconfig命令,用户可以选择需要的配置来生成期望的目标文件。
  • Kbuild Makefiles:主要为整个Makefile体系提供各自模块的目标文件定义,上层Makefile根据它所定义的目标来完成各自模块的编译。(注意:kbuild Makefile是指使用kbuild结构的Makefile,内核中的大多数Makefile都是kbuild Makefile。)    

2.2.2 Linux内核文件编译

Kbuild Makefile的文件名不一定是Makefile,尽管推荐使用Makefile这个名字。大多的Kbuild文件的名字都是Makefile。为了与其他Makefile文件相区别,你也可以指定Kbuild Makefile的名字为Kbuild。而且如果“Makefile”和“Kbuild”文件同时存在,则Kbuild系统会使用“Kbuild”文件。

Kbuild Makefile的一个最主要功能就是指定编译什么,这个功能是通过obj-?、lib-y和目录递归来实现的。

obj-?。其中的“?”可能是“y”或“m”,“y”指定把对象编译进内核中,“m”指定把对象编译为模块。语法如下:obj-? = $(target).o。target为编译对象的名字。如果没有指定xxx-objs,这编译这个对象需要的源文件就是$(target).c或$(target).s。如果指定了$(target)-objs,则编译这个对象需要的源文件由$(target)-objs指定,并且不能有$(target).c或$(target).s文件。xxx-objs指定了编译对象需要的文件,一般只有在源文件是多个时才需要它。

#drivers/isdn/i4l/Makefile  
obj-$(CONFIG_ISDN) += isdn.o  
isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
#drivers/isdn/i4l/Makefile  
# Makefile for the kernel ISDN subsystem and device drivers.  
# Each configuration option enables a list of files. 
obj-$(CONFIG_ISDN)             += isdn.o  
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o

lib-y。列出的objects由当前目录下的.c或.S文件编译生成,在那个文件夹中被综合进单独的一个库,即lib.a。列在obj-y和附加列在lib-y中的objects将不会被包含在库中,也就是说同时出现在obj-y和lib-y的objects不会被包含进lib.a中。值得注意的是kbuild makefile可能列出文件用作 built-in,并且作为库的一部分。因此,同一个文件夹可能包含一个 built-in.o和lib.a文件。 

Example:

#arch/i386/lib/Makefile  
lib-y    := checksum.o delay.o

这个例子创建一个基于checksum.o和delay.o的库文件。lib-y的使用方法通常被限制在lib/和arc/*/lib中。

目录递归。一个Makefile只负责在它自己的文件夹中构建objects。在子文件夹中的文件应该由子文件夹中的Makefiles来编译,系统将会自动递归地用在子文件夹中的Makefiles, 在这种情况下obj-y和obj-m就被使用了。 

Example:

#fs/Makefile  
obj-$(CONFIG_EXT2_FS) += ext2/

如果CONFIG_EXT2_FS被设置成y(built-in)或者m(modular),相应的obj-变量将会被设置,并且kbuild将会从ext2文件夹继承下来。Kbuild只会使用这些信息来决定它需要访问这些文件夹,而在子文件夹中的Makefile来指明哪些是modules哪些是built-in。

2.2.3 Makefile如何决定编译哪些文件

(1)顶层Makefile决定内核根目录下哪些子目录将被编进内核; 

init-y		:= init/
drivers-y		:= drivers/ sound/ 
net-y		:= net/
libs-y		:= lib/
core-y		:= usr/
...
core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/

顶层Makefile文件将Linux源码的子目录分成了init-y、drivers-y、net-y、lib-y和core-y。并直接包含arch/$(ARCH)/Makefle文件:

ARCH		?= $(SUBARCH)
CROSS_COMPILE	?=

# Architecture as present in compile.h
UTS_MACHINE 	:= $(ARCH)
SRCARCH 	:= $(ARCH)
...
include $(srctree)/arch/$(SRCARCH)/Makefile

(2)arch/$(ARCH)/Makefile决定arch/$(ARCH)目录下哪些文件、哪些目录将被编进内核;

以ARM体系为例:

head-y		:= arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o
textofs-y	:= 0x00008000
...
core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y				+= $(machdirs) $(platdirs)
core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
core-$(CONFIG_VFP)		+= arch/arm/vfp/
drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
libs-y				:= arch/arm/lib/ $(libs-y)

head-y直接用文件名表示,对于没有MMU的处理器,MMUEXT的值为 -nommu,对应的文件为head-nommu.S;对于有MMU的处理器,MMUEXT的值为空,对应的文件为head.S。

在编译内核时,将依次进入init-y、core-y、libs-y、drvers-y、和net-y所指出的目录中执行该目录下的Makefile,每个子目录都会生成一个buld-in.o文件,libs-y所指定的目录下有可能生成lib.a文件。最后,head-y所指定的文件和build-in.o、lib.a文件一起被连接成映像文件vmlinux。

(3)各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编成模块(即驱动程序),进入那些子目录继续调用它们的Makefile。

在include/config/auto.conf文件中,变量的值主要有两类:“y ”和“m”。各级子目录的Makefile使用这些变量来决定哪些文件被编进内核中,哪些文件被编成模块(即驱动程序), 要进入那些下一级子目录继续编译。

  • obj–y用来定义哪些文件被编进( built-in)内核;
  • obj-m用来定义哪些文件被编译成可加载模块( Loadable module );
  • lib-y用来定义哪些文件被编成库文件;
  • obj-y、obj-m还可以用来指定要进入的下一层子目录 。

2.3.4 Makefile是怎样编译这些文件的?

即编译选项、连接选项是什么

选项分3类:

  • 全局的,适用于整个内核代码树; 全局选项在顶层Makefile和arch/$(ARCH)Makefle中定义,这些选项的名称是:CFLAGS、AFLAGS、LDFLAGS、ARFLAGS,分别用于编译C文件的选项、编译汇编文件的选项、连接文件的选项和制作库文件的选项。
  • 局部的,仅适用于某个Makefile中的所有文件; 仅适用于某个Makefile中的所有文件;局部选项定义在各个子目录中,名称为:EXTEA_CFLAGS、EXTEA_AFLAGS、EXTEA_LDFLAGS、EXTEA_ARFLAGS,他们的用途和全局选项相同。
  • 个体的,仅适用于某个文件。可以使用CFLAGS_$@和AFLAGS_$A定义编译某个C文件和编译某个汇编文件。$@表示某个目标文件名。

2.3.5 Makefile是怎样连接这些文件

在顶层的Makefile和arch/$(ARCH)/Makefle中定义了:head-y、init-y、drivers-y、net-y、lib-y和core-y(除head-y外,其他的都是目录名)。在顶层Makefle中,这些目录名的后面直接加buld-in.o或者lib.a,表示连接到内核中:

init-y        := $(patsubst %/, %/built-in.o, $(init-y)) 
core-y    := $(patsubst %/, %/built-in.o, $(core-y)) 
drivers-y    := $(patsubst %/, %/built-in.o, $(drivers-y)) 
net-y        := $(patsubst %/, %/built-in.o, $(net-y)) 
libs-y1    := $(patsubst %/, %/lib.a, $(libs-y)) 
libs-y2    := $(patsubst %/, %/built-in.o, $(libs-y)) 
libs-y        := $(libs-y1) $(libs-y2) 

注:字符串处理函数patsubst的用法:$(patsubst pattern,replacement,text)寻找“text”中符合格式“pattern”的字符,用“replacement”替换。比如init-y的初始值为init/,经过处理后,“init-y”变为“init/built-n.o”。     
 

vmlinux-init := $(head-y) $(init-y) 
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y) 
vmlinux-all  := $(vmlinux-init) $(vmlinux-main) 
vmlinux-lds  := arch/$(SRCARCH)/kernel/vmlinux.lds

目标文件的连接顺序为: head-y、init-y、core-y、lib-y、drivers-y和net-y。     

对于ARM体系,Linux的连接脚本为arch/arm/kernel/vmlinux.lds.S文件。

2.3.6 Makefile分析的总结

  • 配置文件.config中定义了一系列的变量,Makefile将结合它们釆决定哪些文件被编 进内核、哪些文件被编成模块、涉及哪些子目录。
  • 顶层Makefile和arch/$(ARCH)/Makefile决定根目录下哪些子目录,arc/$(ARCH) 目录下哪些文件和目录将被编迸内核。
  • 最后,各级子目录下的Makefile决定所在目录下哪些文件将被编进内核,哪些文件将被编成模块(即驱动程序),进入那些目录继续调用它们的Makefile 。
  • 顶层Makefile和arch/$(ARCH)/Makefile设置了可以影响所有文件的编译、连接选项:CFLAGS、MLAGS、LDFLAGS、ARFLAGS。
  • 各级子目录下的Makefile中可以设置能够影响当前目录下所有文件的编译、连接选项:EXTRA_CFLAGS、EXTRA_AFLAGS、EXTRA_LDFLAGS、EXTRA_ARFLAGS;还可以设置可以影响某个文件的编译选项:CFLAGS_$@,AFLAGS_$@ 。
  • 顶层Makefile按照一定的顺序组织文件,根据连接脚本arc/$(ARCH)/ kernel/vmlinux.lds生成内核映象文件vmlinux。

3 Linux内核的Kconfig分析

  • 所有配置工具都是通过读取arc/$(ARCH)/Kconfig文件来生成配置界面这个文件是所有配置文件的总入口,它会包含其他目录的Kconfig文件;
  • 内核源码每个子目录中,都有一个Makefile文件和Kconfig文件;
  • Kconfig用于配置内核,它就是各种配置界面的源文件;
  • 内核的配置工具读取各个Kconfig文件,生成配置界面供开发人员配置内核,最后生成配置文件.config;
  • 内核的配置界面以树状的菜单形式组织,主菜单下有若干个子菜单,子菜单下又有子菜单或配置选项。每个子菜单或选项可以有依赖关系,这些依赖关系用来确定它们是否显示。只有被依赖项的父项已经被选中,子项才会显示。

Kconfig的基本要素包括:

3.1 config

config条目用来配置一个选项,它用于生成一个变量,这个变量会连同它的值一起被写入配置文件.config中。 config出现的三种配置结果:

CONFIG_LEDS_S3C24XX=y  #对应的文件被编进内核
CONFIG_LEDS_S3C24XX=m  #对应的文件被编成模块
#CONFIG_LEDS_S3C24XX  #对应的文件没有被使用

下面举一个例子来说明config的格式,代码选自drivers/char中,用于配置CYCLADES:

config CYCLADES
	tristate "Cyclades async mux support"
	depends on SERIAL_NONSTANDARD && (PCI || ISA)
	select FW_LOADER
	---help---
	  This driver supports Cyclades Z and Y multiserial boards.
	  You would need something like this to connect more than two modems to
	  your Linux box, for instance in order to become a dial-in server.

	  For information about the Cyclades-Z card, read
	  .

	  To compile this driver as a module, choose M here: the
	  module will be called cyclades.

	  If you haven't heard about it, it's safe to say N.
  • config关键字,表示一个配置选项的开始。后面的CYCLADES表示配置选择的名称,省略了“CONFIG_”,完整的配置选项名称是CONFIG_CYCLADES。
  • 变量类型。 config变量类型: bool, tristate, string, hex, int, tristate和string是基本类型,其他的都是他们的变种。bool变量的取值有y和n两种;tristate的取值有y、m和n;string为字符串;hex的取值是十六进制的数据,int的取值是十进制的数据。
  • 依赖关系。格式为: “depends on”/ “requires” 只有表达式SERIAL_NONSTANDARD && (PCI || ISA)为真时,当前配置选项的提示信息才会出现。
  • 当前配置CYCLADES别选中时,配置选项FW_LOADER会被自动选中。格式如下: “select” [“if” ]
  • 帮助信息

3.2 menu

menu条目用于生成菜单,格式如下:

“menu” 


“endmenu”

menu之后出现的字符串是菜单名,“menu”和“endmenu”之间有很多config。

#
# Video configuration
#

menu "Graphics support"
	depends on HAS_IOMEM

source "drivers/char/agp/Kconfig"

source "drivers/gpu/drm/Kconfig"

config VGASTATE
       tristate
       default n

config VIDEO_OUTPUT_CONTROL
	tristate "Lowlevel video output switch controls"
...
endmenu

ARM9嵌入式Linux开发-Linux基础知识_第5张图片

3.3 choice

choice条目将多个类似的配置选项组合在一起,供用户单选或多选,格式如下:

“choice”


“endchoice”

实际使用中,会在“choice”和“endchoice”中定义多个config。

menu "System Type"

choice
	prompt "ARM system type"
	default ARCH_VERSATILE
	...
config ARCH_SA1100
	bool "SA1100-based"
	...
config ARCH_S3C2410
	bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
	...
config ARCH_S3C64XX
	bool "Samsung S3C64XX"
	...
endchoice
	...
endmenu

ARM9嵌入式Linux开发-Linux基础知识_第6张图片

if ARCH_S3C2410
source "arch/arm/mach-s3c2400/Kconfig"
source "arch/arm/mach-s3c2410/Kconfig"
source "arch/arm/mach-s3c2412/Kconfig"
source "arch/arm/mach-s3c2440/Kconfig"
source "arch/arm/mach-s3c2442/Kconfig"
source "arch/arm/mach-s3c2443/Kconfig"
endif

3.4 comment

comment条目用于定义一些帮助信息,它在配置过程中出现在界面的第一行.并且这些 帮助信息会出现在配置文件中(作为注释),格式如下:
 

“comment”  

例子,选自arch/arm/Kconfig

menu “Floating point emulation” 
comment “At least one emulation must be selected”

3.5 source

source条目用于读入另一个Kconfig文件, 格式如下:

“source” 

下面是一个例子,代码选自drivers目录下:

source "drivers/base/Kconfig"
source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/of/Kconfig"

5.编译Linux内核

Step1: 拷贝arch/arm/configs/s3c2410_defconfig为文件.config     #cp arch/arm/configs/s3c2410_defconfig .config

Step2: 修改内核目录下的Makefile

		CROSS_COMPILE   ?= arm-linux-
    		ARM    ?= arm

Step3: 执行make menuconfig,并保存,如果有问题,以root权限执行     #make menuconfig

Step4: 编译内核     #make zImage 编译完成后,zImage放在/arch/arm/boot/zImage。

你可能感兴趣的:(ARM9嵌入式Linux开发)