Linux内核配置、编译及Makefile简述

Hi,大家好!我是CrazyCatJack。最近在学习Linux内核的配置、编译及Makefile文件。今天总结一下学习成果,分享给大家^_^

1.解压缩打补丁

  首先是解压缩你获取到的Linux内核。这里我用到的是linux.2.22.6版本的内核。在Linux下命令行通过tar xjf linux.2.22.6.tar.bz2解压内核。然后,如果你需要对这个内核打补丁的话,用patch命令:patch -px <../linux.2.22.6.patch。这里的px指的是忽略掉补丁文件中描述的第几个斜杠。也就是忽略前x个目录。

--- linux-2.6.22.6/arch/arm/configs/s3c2410_defconfig
+++ linux-2.6.22.6_jz2440/arch/arm/configs/s3c2410_defconfig

  如果你此刻就在内核的根目录下,即linux-2.6.22.6下,也就是说打补丁需要忽略掉一个斜杠的目录。那么打补丁的命令就是patch -p1 <../linux.2.22.6.patch。

2.配置内核

  现在补丁已经打好了,接下来就是配置内核了。这里配置有3种方法:

  1>直接进行make menuconfig。这是最麻烦的一种方法,所有的配置都需要你来操作。

  2>在默认配置上自己修改,也就是修改defconfig文件。使用 find -name "*defconfig*"查找你的架构对应的默认配置文件。我是在arch/arm/configs找到自己板子的默认配置文件。执行defconfig文件: make XXX_defconfig。XXX是你具体使用的板子型号。执行这一操作后,结果保存在.config文件。然后再执行make menuconfig命令。这时的配置就是在默认配置上稍加修改就可以了。

  3>使用厂家的配置文件。如果你的硬件有厂家提供的config文件那是最轻松的。直接cp XXX .config。然后执行make menuconfig。

  这里详细给大家讲一下内核的配置。Linux的内核配置,就是为了生成.config文件。因为在编译时需要用.config文件生成其他相关配置文件。我们的配置项大多是例如CONFIG_XXXDRIVER,这里的XXXDRIVER指的是各种驱动。我们需要告诉内核,这些驱动是编译进内核,还是编译成模块。通过查找CONFIG_XXXDRIVER,我们可以发现,它出现在四个地方:

  1>C源代码

  2>子目录Makefile:drivers/XXX/Makefile

  3>include/config/auto.conf

  4>include/linux/autoconf.h

    这里首先说明:.config文件在进行内核编译时(make uImage)生成了include/config/auto.conf和include/linux/autoconf.h。通过查看C源代码我们发现CONFIG_XXXDRIVER是一个宏定义,等于一个常量。在include/linux/autoconf.h中宏定义CONFIG_XXXDRIVER为一个常量,可能是0或1。那么现在有一个问题,就是CONFIG_XXXDRIVER到底被编译进内核还是编译成一个模块呢?这在C语言中是无法进行区分的,这种区分体现在哪里呢?这种区分体现在子目录的Makefile文件中。在子目录的Makefile中,若有 obj -y += XXX.o则表示XXX.c被编译进内核;obj -m +=XXX.o则表示XXX被编译成模块,为XXX.ko。include/config/auto.conf文件则是对CONFIG_XXXDRIVER进行赋值,为y时表示编译进内核,为m时表示编译成独立模块。

#这里是include/config/auto.conf的部分内容
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.22.6
# Sun Nov 27 18:34:38 2016
#
CONFIG_CPU_S3C244X=y
CONFIG_CPU_COPY_V4WB=y
CONFIG_CRYPTO_CBC=y
CONFIG_CPU_S3C2410_DMA=y
CONFIG_CRYPTO_ECB=m
CONFIG_SMDK2440_CPU2440=y
#这里是drivers/i2c/Makefile
# Makefile for the i2c core.
# obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/ chips/ algos/ ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
EXTRA_CFLAGS += -DDEBUG
endif

3.编译内核
  通过上面的描述,我们可以知道,在每个driver下,都有一个Makefile文件。来定义这个驱动是编译进内核还是编译成模块。这里稍稍提一下。上面我们讲到了在Makefile中单个文件怎样编译进内核和编译成模块。但是如果有两个以上的文件该如何书写呢?这里举个例子:obj -y += a.o b.o就表示将a.c和b.c编译进内核。

obj -m += ab.o

ab -objs := a.o b.o

就可以表示将a.c和b.c共同编译成为一个模块。过程就是 a.c生成a.o , b.c生成b.o。a.o 和b.o共同生成ab.ko。在以往的对uboot启动内核的代码分析中,我们提到过编译内核生成的uImage是由两部分组成的:头部+Linux内核。这个头部包含了很多初始化的参数信息,例如内核的加载地址和入口地址。在编译内核时,我们直接执行make uImage即可。那么在文件中是怎样定义uImage的呢?又是怎样生成uImage的呢?

  首先,我们通过查找Makefile,发现uImage在arch/arm/Makefile中,而这个架构目录下的Makefile被包含进顶层目录的Makefile中。这样我们在执行 make uImage时,顶层目录的Makefile就可以调用架构子目录下的Makefile,实现对内核的编译,生成uImage。

顶层目录下Makefile中相关命令:
include $(srctree)/arch/$(ARCH)/Makefile
架构目录下Makefile相关命令:
zImage Image xipImage bootpImage uImage: vmlinux

  这就是刚刚所说的顶层Makefile调用架构目录下Makefile,架构目录下Makefile生成uImage,而且依赖于vmlinux文件。下面我们就开始讲解如何生成vmlinux文件。在顶层Makefile中,我们找到了有关生成vmlinux的大部分命令。

  

顶层目录Makefile:
init-y := init/
init-y := $(patsubst %/, %/built-in.o, $(init-y))
core-y := usr/
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
core-y := $(patsubst %/, %/built-in.o, $(core-y)) libs-y := lib/
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2) drivers-y := drivers/ sound/
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) net-y := net/
net-y := $(patsubst %/, %/built-in.o, $(net-y)) = net/built-in.o vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE 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/$(ARCH)/kernel/vmlinux.lds
export KBUILD_VMLINUX_OBJS := $(vmlinux-all) 架构目录Makefile:
zImage Image xipImage bootpImage uImage: vmlinux head-y        := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o

  我已经把顶层目录和架构目录下生成vmlinux的命令摘选出来。首先,我们看要想生成vmlinux,需要vmlinux-lds文件、vmlinux-init文件、vmlinux-main文件。其中,vmlinux-lds是链接脚本文件,定义了代码段,数据段的存放位置。这里我们接着往下看,vmlinux-init需要head-y和init-y,通过查看两个Makefile,我们可以得到经过转换后的结果:

  

head-y        :=
arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o init-y := $(patsubst %/, %/built-in.o, $(init-y)) = init/built-in.o core-y := $(patsubst %/, %/built-in.o, $(core-y))
= usr/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o libs-y := $(libs-y1) $(libs-y2) =lib/lib.a lib/built-in.o drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) = drivers/built-in.o sound/built-in.o net-y := $(patsubst %/, %/built-in.o, $(net-y)) = net/built-in.o

  现在已经分析了内核编译的全部过程。那怎样知道我们分析的到底对不对,通过实际执行make uImage我们就可以看到执行过程。这是执行make uImage过程中的部分相关命令:

arm-linux-ld -EL  -p --no-undefined -X -o vmlinux
-T arch/arm/kernel/vmlinux.lds
arch/arm/kernel/head.o
arch/arm/kernel/init_task.o init/built-in.o --start-group usr/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o

  可以看到,首先目标要生成vmlinux,然后是链接脚本为vmlinux.lds。开始生成第一个文件:head.o,第二个文件:init_task.o。这和我们分析的完全一致。接下来以此类推,和我们分析的相同,也就是说我们分析的是正确的。

SECTIONS
{ . = (0xc0000000) + 0x00008000; .text.head : {
_stext = .;
_sinittext = .;
*(.text.head)
} .init : { /* Init code and data */
*(.init.text)
_einittext = .;
__proc_info_begin = .;
*(.proc.info.init)
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;
. = ALIGN(16);
__setup_start = .;
*(.init.setup)
__setup_end = .;
__early_begin = .;
*(.early_param.init)
__early_end = .;
__initcall_start = .;

  这是链接脚本vmlinux.lds中的部分内容。首先定义了虚拟地址:(0xc0000000) + 0x00008000。 然后是首先执行头部文件,这与我们分析的完全一致。代码段,初始化代码段等等。

Linux内核的更多相关文章

  1. Linux 内核概述 - Linux Kernel

    Linux 内核学习笔记整理. Unix unix 已有40历史,但计算机科学家仍认为其是现存操作系统中最大和最优秀的系统,它已成为一种传奇的存在,历经时间的考验却依然声名不坠. 1973 年,在用 ...

  2. 模仿Linux内核kfifo实现的循环缓存

    想实现个循环缓冲区(Circular Buffer),搜了些资料多数是基于循环队列的实现方式.使用一个变量存放缓冲区中的数据长度或者空出来一个空间来判断缓冲区是否满了.偶然间看到分析Linux内核的循 ...

  3. linux内核调试技术之printk

    原创博客:欢迎转载,转载请注明出处https://i.cnblogs.com/EditPosts.aspx?postid=6218383 1.简介(基于s3c2440 linux) 在内核调试技术之中 ...

  4. Linux内核启动过程概述

    版权声明:本文原创,转载需声明作者ID和原文链接地址. Hi!大家好,我是CrazyCatJack.今天给大家带来的是Linux内核启动过程概述.希望能够帮助大家更好的理解Linux内核的启动,并且创 ...

  5. Linux内核配置、编译及Makefile简述

    Hi,大家好!我是CrazyCatJack.最近在学习Linux内核的配置.编译及Makefile文件.今天总结一下学习成果,分享给大家^_^ 1.解压缩打补丁 首先是解压缩你获取到的Linux内核. ...

  6. linux内核数据结构之kfifo

    1.前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由linux内核的kfifo改过来的.缓冲区在文件系统中经常用到,通过缓冲区缓解cpu读写内存和读写磁盘的速度.例如一个进程A产 ...

  7. 浅析linux内核中的idr机制

    idr在linux内核中指的就是整数ID管理机制,从本质上来说,这就是一种将整数ID号和特定指针关联在一起的机制.这个机制最早是在2003年2月加入内核的,当时是作为POSIX定时器的一个补丁.现在, ...

  8. gcc/linux内核中likely、unlikely和__attribute__(section(""))属性

    查看linux内核源码,你会发现有很多if (likely(""))...及if (unlikely(""))...语句,这些语句其实是编译器的一种优化方式,具 ...

  9. Linux 内核版本命名

    Linux 内核版本命名在不同的时期有其不同的规范,我们熟悉的也许是 2.x 版本奇数表示开发版.偶数表示稳定版,但到 2.6.x 以及 3.x 甚至将来的 4.x ,内核版本命名都不遵守这样的约定. ...

  10. 使用串口线真机调试Linux内核

    一.环境 ubuntu 14.04 一台有串口的PC(编号PC1,被调试机器) 另一台PC通过USB转串口线连接PC1(编号PC2,发起调试命令的机器) 二.串口线配置及测试 安装cutecom US ...

随机推荐

  1. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q40-Q44)

    Question 40You need to send a single value from a consumer Web Part to a provider Web Part.Which int ...

  2. android Java BASE64编码和解码一:基础

    今天在做Android项目的时候遇到一个问题,需求是向服务器上传一张图片,要求把图片转化成图片流放在 json字符串里传输. 类似这样的: {"name":"jike&q ...

  3. Iterator 迭代器(一)

         迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址.迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为 ...

  4. iOS 视频播放 - YVideoPlayer - UIView

    这是一个使用简便的视频播放框架,它基于UIView,它可以是一个小窗口,也可以是一个全屏的窗口 简单的方式加载Video框架: 一行代码加载! 一行代码更新! 下载链接 : https://githu ...

  5. Android-AsyncTask异步任务(获取手机联系人)

    本篇随笔将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多线程 在Android当中,当一个应用程序的组件启动的时候,并且没有 ...

  6. Android项目结构分析

    andriod项目目录结构如下图: 1. src目录 该目录一个普通的保存java源文件的目录,其和普通java工程中的src目录是一样的. 2. gen目录 此目录用于存放所有由ADT插件自动生成的 ...

  7. JAVA-使用commos-fileupload实现文件上传与下载

    一文件的上传 实体类 在CODE上查看代码片派生到我的代码片 import java.sql.Timestamp; /** * * @Decription 文件上传实体类 * @author 刘楠 * ...

  8. 【原】开发路上疑难BUG调试记录

    之前遇到棘手的BUG总是在处理过后就不管了,导致后面碰到相同问题后重复工作太多.现专门开辟一篇日志以记录接下来一路上比较棘手的“坑”的修复历程: [C++篇] 1.mt.exe : general e ...

  9. ReSharper 8.XXX 注册机

    今天给电脑重装系统,发现Rsharper已经更新到8.0.14.856了,于是下载新版本的,但像咱搞开发的,肯定不能用付费软件(关键是你也付不起啊,499$,499刀啊).于是在网上找相关的激活软件. ...

  10. 你连Bug都抓不住,还谈什么参与感?

    林子大了什么鸟都有,APP市场也是这样.举个例子,有段时期图片社交井喷式发展,各类图片社交APP一时充斥着市场.各种或重视图片加工或主打社交元素的APP“来得快去得快”.“你方唱罢我登场”,这些短命A ...