导航

Linux源代码阅读——环境准备

目录

  1. Linux 系统环境准备
  2. 编译 Linux 内核
  3. 模拟执行 Linux
  4. 准备源码阅读环境
  5. Linux 内核源代码结构

1 Linux系统环境准备

1.1 定制安装Ubuntu

  1. 从科大源下载 Ubuntu Alternative CD,校验 MD5。
  2. 挂载 ISO,使用 preseed 文件来进行一些预定制,参考 http://pxe.ustc.edu.cn/boot/conf/preseed.debian.ustc.cfg(当然其中的 debian 需要改为 ubuntu,hostname 改成自己希望的主机名),指定安装所使用的源,以及其他一些预定义设置。
  3. 卸载ISO,使用 usb-creator-gtk 制作启动U盘。
  4. 使用 parted 分区:将硬盘的一个空闲 NTFS 分区删除;mkpartfs 建立一个ext2(用于/boot)、一个swap、一个ext4(用于根分区)。
  5. 从U盘启动,选择 Install a command-line system,设置键盘、分区等(其他设置已经写在 preseed 中了),安装基本系统,设置用户名密码。
  6. grub-mkimage 制作包含 reiserfs 模块的 grub2(原有的 linux 所在分区是 reiserfs 的),grub-mkconfig 更新 grub.cfg 配置文件。
  7. 安装 X(xserver-xorg)、GNOME 桌面环境(gdm、gnome-core、xinit、gnome-utils、synaptic)
  8. 安装中文语言包(language-pack-zh-base、language-support-fonts-zh、xfonts-wqy、language-selector),修改 locale
  9. 安装输入法(fcitx)、vim等
  10. 安装、设置声卡驱动(alsa)(特定硬件的驱动问题,采用网上的办法)
  11. 安装 ntfs-3g、wine 等系统工具,tcpdump、firefox、filezilla、amule 等网络工具,okular、chmsee、libreoffice 等办公工具
  12. 安装 ssh、nginx、php5-fpm、MySQL、memcached、vsftpd 等服务器需要的 daemon(网络开发用)
  13. apt-get clean 清除缓存
  14. 编辑 /etc/modules,开机加载 fuse(用户态文件系统)模块,以便使用 ntfs-3g
  15. 编辑 /etc/fstab 将 /dev/sda4(NTFS)自动挂载上,为方便 Windows 使用,学习资料等数据放在这个分区。
    # <file system> <mount point>   <type>  <options>       <dump>  <pass>
    proc            /proc           proc    nodev,noexec,nosuid 0       0
    # / was on /dev/sda2 during installation
    UUID=d993c54c-0602-48d2-935f-be9ac654f9a0 /               ext4    errors=remount-ro 0       1
    /dev/sda1       none            swap    sw              0       0
    /dev/sda4	/media/DATA	ntfs-3g	silent,umask=0,locale=zh_CN.utf8	0	0
    

1.2 安装工具链

2 编译Linux内核

2.1 默认编译

  1. 从 kernel.org 下载 Linux 2.6.26 源码,tar -zvxf
  2. make mrproper 清除所有已编译文件和配置文件
  3. make i386_defconfig 生成x86体系结构的默认配置。此过程首先HOSTCC、SHIPPED、HOSTLD一些配置文件,然后进入 Linux Kernel Configuration,与 make config 的命令行界面相同,只是所有选项都被自动选择了(具体参见 arch/x86/configs/i386_defconfig)。
  4. make 编译代码。由CC、LD、AR、AS、GEN、HOSTCC、OBJCOPY、BUILD等过程组成。其中有一些 warning,是因为代码不符合当前C标准,可以忽略。
    BUILD   arch/x86/boot/bzImage
    Root device is (8, 2)
    Setup is 10140 bytes (padded to 10240 bytes).
    System is 2651 kB
    CRC e3791c7
    Kernel: arch/x86/boot/bzImage is ready  (#1)
    

2.2 自定义编译

  1. 每次更改配置重新编译前,make clean 清除上次编译的目标文件和中间文件,但保留配置文件以便在其基础上修改。
  2. make menuconfig 进入终端下的菜单选择。相比完全命令行界面的 config,用起来更方便;而图形界面的 xconfig 或 gconfig 虽然比较直观,但不便于使用键盘。
  3. 设置完毕,保存到 .config
  4. make 编译代码,生成的内核映像是 arch/x86/boot/bzImage
    Root device is (8, 2)
    Setup is 10140 bytes (padded to 10240 bytes).
    System is 3063 kB
    CRC aa68b290
    Kernel: arch/x86/boot/bzImage is ready  (#3)
      Building modules, stage 2.
      MODPOST 26 modules
    
  5. 由于我们是在虚拟机内运行而不是安装到本地系统,因此不需要 make install

具体设置参考:Linux 2.6.19.x 内核编译配置选项简介(金步国)

3 模拟执行 Linux

3.1 用 qemu 模拟 Hello World 系统

  1. 写一个 Hello World 程序:
    [boj@boj-laptop:~/test]$ cat test.c
    #include<stdio.h>
    int main() {
    	printf("Hello World!");
    	return 0;
    }
    
  2. 静态链接编译
    [boj@boj-laptop:~/test]$ gcc -static -o init test.c
  3. 建立目标根目录映像
    [boj@boj-laptop:~/test]$ dd if=/dev/zero of=initrd4M.img bs=4096 count=1024
    [boj@boj-laptop:~/test]$ mke2fs initrd4M.img
    [boj@boj-laptop:~/test]$ mkdir rootfs
    [boj@boj-laptop:~/test]$ sudo mount -o loop initrd4M.img rootfs
    
  4. 将init拷贝到目标根目录下
    [boj@boj-laptop:~/test]$ cp init rootfs/
  5. 准备 /dev 目录、console 设备、linux 根设备(ram)
    [boj@boj-laptop:~/test]$ sudo mkdir rootfs/dev
    [boj@boj-laptop:~/test]$ sudo mknod rootfs/dev/console c 5 1
    [boj@boj-laptop:~/test]$ sudo mknod rootfs/dev/ram b 1 0
    [boj@boj-laptop:~/test]$ sudo umount rootfs
    
  6. 用 qemu 模拟运行
    [boj@boj-laptop:~]$ qemu -kernel linux-2.6.26/arch/x86/boot/bzImage -initrd test/initrd4M.img -append "root=/dev/ram init=/init"
    

    一段初始化后,输出了 Hello World,随即 Kernel Panic(因为 init 在输出字符串后就自行退出了)

    [    4.270006] Freeing unused kernel memory: 244k freed
    Hello World![    4.326627] Kernel panic - not syncing: Attempted to kill init!

4 准备源码阅读环境

4.1 vim 基本设置

[boj@boj-laptop:~]$ cat ~/.vimrc
set encoding=UTF-8
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
set fileencoding=utf-8
sy on
set ai
set nu
set shiftwidth=2
set tabstop=4
set softtabstop=4
set ic "搜索时忽略大小写,以便在某些“骆驼”变量名风格的源码中查找

4.2 在 vim 中使用 cscope

  1. 安装 CScope:
    sudo apt-get install cscope
  2. 确认 vim 支持 cscope:
    vim --version | grep cscope
  3. 给源代码建立索引:
    cscope -Rbq

    其中,ctags 递归的在每个目录下生成 tags 文件,供 vim 读取;cscope 生成 cscope.out

    cscope.out: cscope reference data version 15 with inverted index
  4. 将以下内容添加到 ~/.vimrc 中,以自动加载 cscope.out。
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " cscope setting
    
    if has("cscope")
       set csprg=/usr/bin/cscope              "指定用来执行 cscope 的命令
       set csto=1                             "先搜索tags标签文件,再搜索cscope数据库
       set cst                                "使用|:cstag|(:cs find g),而不是缺省的:tag
       set nocsverb                           "不显示添加数据库是否成功
       " add any database in current directory
       if filereadable(ncscope.out")
          cs add cscope.out                   "添加cscope数据库
       endif
       set csverb                             "显示添加成功与否
    endif
    
    nmap <C-@>s :cs find s <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>g :cs find g <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>c :cs find c <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>t :cs find t <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>e :cs find e <C-R>=expand("<cword>")<CR><CR>
    nmap <C-@>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
    nmap <C-@>i :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
    nmap <C-@>d :cs find d <C-R>=expand("<cword>")<CR><CR>
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    
  5. 根据上面的 .vimrc,使用简单的组合键和字母即可使用 cscope 的查找功能。

    例如,<C-@>g 先按 ctrl+@,再按 g,即可查看当前光标所在符号的定义。

    :cs help

4.3 在 vim 中使用 ctags

在源代码根目录下执行 ctags -R 命令用来为程序源代码生成标签文件,-R 选项表示递归操作,同时为子目录也生成标签文件。vim 利用生成的标签文件,可以进行相应检索、并在不同的文件中的C语言元素之间来回切换。

需要在 tags 文件所在的目录下运行 vim。否则,要用 :set tags=xxx 指定 tags 文件的路径。

使用 tag 命令时,可以使用 TAB 键进行匹配查找,继续按 TAB 键向下切换。

在函数中移动光标的快捷键:

4.4 使用 taglist 显示 symbol 窗口

taglist 插件可以像 Source Insight 那样将当前文件中的宏、全局变量、函数等 tag 显示在 Symbol 窗口,用鼠标点上述 tag,就跳到该 tag 定义的位置;可以按字母序、该tag所属的类或scope,以及该 tag 在文件中出现的位置进行排序;如果切换到另外一个文件,Symbol 窗口更新显示这个文件中的 tag。taglist 依赖于 ctags。

  1. 打开 vim 的文件类型自动检测功能;
  2. 系统中装了 Exuberant ctags 工具,并且 taglist 能够找到此工具(因为 taglist 需要调用它来生成 tag 文件);
  3. vim 支持 system() 调用;
  4. 在 ~/.vimrc 中加入
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    " ctags setting
    set tags=./tags,./../tags,./*/tags;
    
    " Tag list (ctags)
    
    filetype on                            "文件类型自动检测
    
    if MySys() == "windows"                "设定windows系统中ctags程序的位置
       let Tlist_Ctags_Cmd = 'ctags'
    elseif MySys() == "linux"              "设定linux系统中ctags程序的位置
       let Tlist_Ctags_Cmd = '/usr/bin/ctags'
    endif
    
    let Tlist_Show_One_File = 1            "不同时显示多个文件的tag,只显示当前文件的
    let Tlist_Exit_OnlyWindow = 1          "如果taglist窗口是最后一个窗口,则退出vim
    let Tlist_Use_Right_Window = 1         "在右侧窗口中显示taglist窗口 
      
    map <silent> <F8> :TlistToggle<cr>     "在映射F8键打开tags窗口
    """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
    

上述配置过程参考了:http://www.cnblogs.com/sunblackshine/archive/2011/08/25/2152962.html

5 Linux 内核源代码结构

Linux 2.6.26 源码各目录大致作用:


Copyright © 2012 李博杰 PB10000603

This document is available from http://home.ustc.edu.cn/~boj/courses/linux_kernel/0_prepare.html