【笔记】构建Linux

作者: 外星间谍 | 来源:发表于2017-03-31 18:18 被阅读428次

    14年即将毕业时构建的,尝试Markdown整理下格式,内容没整理。

    说明

    我构建的目标平台为BeagleBone Black
    交叉编译工具为Sourcery CodeBenchLite

    要构建Linux,很简单,只有3个部分,

    1. bootloader,即启动引导程序,我选择U-Boot。
    2. Linux内核。
    3. 应用程序。

    我这里构建的目标是可编译C程序。
    我还没研究是什么决定了32位和64位。

    我主要的资料,

    • Running Linux
      介绍Linux的书,这才叫入门级,了解下Linux的思想即可,书的内容可能有些过时,
      这本书不是介绍怎么使用Linux的。如果想知道怎么使用Linux,
      可看看Linux Pocket Guide,很薄。
      鸟哥的书也不错,感觉挺详细的,好于大部分书,我没看。
      我连shell脚本都不会写呢,很多命令没用过,这与构建Linux关系不大。

    • Building Embedded Linux Systems
      教构建嵌入式Linux的,了解下思想即可。

    • Linux From Scratch
      教构建各种Linux的网站,最关键的是网站给出了Linux由哪些应用程序构成。
      我没有用网站中的方式,sed那种命令不会。也是了解下思想即可。

    If you can’t explain it simply, you don’t understand it well enough.
    --Albert Einstein

    [TOC]

    准备SD卡

    BeagleBone Black有4种启动方式,我选择用SD卡。
    将SD卡插到电脑中,在我的系统中被识别为/dev/sdb。

    分区:

    # fdisk /dev/sdb
    

    用法很简单,输入'm',就可得到帮助。
    第一个分区64M,类型为FAT32 (LBA),加上启动标记。
    第二个分区为余下的全部,类型默认为Linux,不必改。

    参考过程是这样的,
    输入'o',新建一个空DOS分区表,这会清除所有分区。
    输入'p',会列出分区列表,此时应该没有。
    输入'n'来添加新分区,直接'enter',接受默认为主分区,'enter'接受默认为第一分区,
    'enter'接受默认的开始扇区,输入'+64M',设置分区大小为64M。
    输入't',来改变分区类型,自动选择了第一个分区,输入l可列出所有分区列表的代码,
    输入'c'选择W95 FAT32(LBA)。
    输入'a',在第一分区设置可启动标记。
    输入'n','enter'主分区,'enter'第二个,'enter'起始扇区,'enter'结束扇区。
    输入'w',将改动写入分区表。

    格式化:

    # mkfs.vfat -F 32 /dev/sdb1
    # mkfs.ext4 /dev/sdb2
    

    第一个分区用来放U-Boot。
    第二个分区用来放Linux系统。

    sdb2被格式化后,里面自动有个lost+found,文件系统的结构中正好有一条:
    /lost+found: Filesystem-specific recoverable data

    文件系统目录结构

    因为感觉Linux系统比较乱,
    尝试改变了下目录结构。
    和我一样想法的不止我一个,例如GoboLinux

    /
    /data/             ;存放数据,看看下面的软链接就知道了。
    /lost+found
    /mount/            ;挂载点,就是传统的mnt。
    /program/          ;存放程序,Linux内核也在里面。
    /user/             ;用户,就是传统的home。
    /dev/
    

    dev本来应该是下面那样的软链接,但那样的话不能在ttyO0登陆,
    不过倒是可以在tty1登陆,也就是通过HDMI连接显示器的时候。
    为了兼容,以下是一些额外的软链接,注意并没有dev。

    /bin -> /data/index/bin       ;index中的都是软连接,指向program中相应位置。
    /dev -> /data/device          
    /etc -> /data/configuration   ;有些程序要在这里找配置文件。
    /lib -> /data/index/lib
    /proc -> /data/process
    /run -> /data/run
    /sbin -> /data/index/bin
    /sys -> /data/system
    /tmp -> /data/temporary
    /var -> /data/variable
    
    /usr/
    /usr/include -> /data/index/include
    /usr/lib -> /data/index/lib
    
    /usr/share/
    /usr/share/info -> /data/index/info
    /usr/share/man -> /data/index/man
    

    便签

    export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
    export PKG_CONFIG_LIBDIR=/home/spy/Work/data/index/lib/pkgconfig
    export PKG_CONFIG_SYSROOT_DIR=/home/spy/Work
    
    --prefix=/program/
    --oldincludedir=/program//oldinclude
    --build=x86_64-unknown-linux-gnu
    --host=arm-none-linux-gnueabi
    
    DESTDIR=/home/spy/Work
    
    chown -R 0:0
    chgrp -v tty /program/util-linux/bin/wall
    chown -R spy:users
    

    以可读写重新挂载根文件系统

    mount -n -o remount,rw /
    

    放到交叉编译器搜索库中的程序库
    linux-pam,ncurses,libcap,gdbm

    coreutils与util-linux重复的命令。
    kill

    shadow与util-linux重复的命令。
    {login,nologin,su}

    shadow与coreutils重复的命令。
    groups

    编译软件

    U-Boot

    2分钟 CPU 1.86GHz;内存2G,DDR2,单条1G。

    $ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
    $ export CROSS_COMPILE=arm-none-linux-gnueabi-
    $ cd /home/spy/Work/sources/u-boot/u-boot-2014.04
    
    $ make O=/home/spy/Work/program/u-boot distclean
    $ make O=/home/spy/Work/program/u-boot am335x_boneblack_config
    $ make O=/home/spy/Work/program/u-boot all
    

    源码中正好有am335x_boneblack这个配置文件,对应我的开发板,
    想知道可用的配置文件看README吧,它会告诉你到另一个文件boards.cfg中找。

    AM335x U-Boot User's Guide
    TI的wiki,看“Two stage U-Boot design”让你了解MLO和u-boot.img是什么。
    大概是AM335X芯片中的程序较小,只为了4种启动方式初始化,
    然后找到MLO,运行MLO进一步初始化,如DDR3内存。
    MLO最后找到u-boot.img,运行之。u-boot.img这个名字应该是在MLO的>代码中指定的。
    提示:TI的StarterWare中的2个文件叫MLO和app。

    编译完后,现在就可以找找成就感了,

    • 将MLO和u-boot.img复制到SD卡的第一个分区里;
    • 将串口调试用的线与计算机相连,启动串口调试程序,如Putty
    • 将SD卡插入开发板,保持按下板子上的启动选择键,插上电源,板子会从SD卡启动,
    • 可以松开启动选择键了。

    Putty的窗口上会打印一些信息,你会看到一个1秒的倒计时,
    然后U-Boot会运行环境变量中已经设置好的一些列命令,比如将Linux内核载入内存,
    但此时还没有内核文件,U-Boot会停留在它自己的命令行中,
    你可以输入命令,如reset,这会让板子重启,
    倒计时的时候按下计算机上的任意键,U-Boot就不会运行环境变量中的命令了,
    可玩一玩下面的演示。

    给出U-Boot中的一些演示,输入help可显示所有命令。
    help后接命令,可显示该命令的帮助。如

    help help
    
    U-Boot# mmc rescan
    U-Boot# mmc list
    OMAP SD/MMC: 0
     OMAP SD/MMC: 1
    U-Boot# mmc dev
    mmc0 is current device
    U-Boot# mmc part
    
    Partition Map for MMC device 0  --   Partition Type: DOS
    
    Part    Start Sector    Num Sectors     UUID            Type
      1     2048            131072          29942d7e-01     0c Boot
      2     133120          15390720        29942d7e-02     83
    U-Boot# ls mmc 0:1
       100688   mlo
       308232   u-boot.img
          510   uenv.txt
    
    3 file(s), 0 dir(s)
    
    U-Boot# ls mmc 0:2
    <DIR>       4096 .
    <DIR>       4096 ..
    <SYM>          7 bin
    <DIR>       4096 boot
    <DIR>       4096 dev
    <DIR>       4096 etc
    <DIR>       4096 home
    <SYM>          7 lib
    <DIR>       4096 lost+found
    <DIR>       4096 mnt
    <DIR>       4096 proc
    <DIR>       4096 run
    <SYM>          7 sbin
    <DIR>       4096 sys
    <DIR>       4096 tmp
    <DIR>       4096 usr
    <DIR>       4096 var
    U-Boot# mmcinfo
    Device: OMAP SD/MMC
    Manufacturer ID: 3
    OEM: 5344
    Name: SU08G
    Tran Speed: 50000000
    Rd Block Len: 512
    SD version 3.0
    High Capacity: Yes
    Capacity: 7.4 GiB
    Bus Width: 4-bit
    U-Boot# mmc dev 1
    mmc1(part 0) is current device
    U-Boot# mmcinfo
    Device: OMAP SD/MMC
    Manufacturer ID: fe
    OEM: 14e
    Name: MMC02
    Tran Speed: 52000000
    Rd Block Len: 512
    MMC version 4.41
    High Capacity: No
    Capacity: 1.8 GiB
    Bus Width: 4-bit
    U-Boot# mmc dev 0
    mmc0 is current device
    U-Boot#
    

    fatls,ext4ls也可以显示文件,但对应某种文件系统。

    Linux

    26 + 53

    内核配置文件我在开发板的github找的,
    复制一份名字改“.config”放到O指定的目录中。
    这样就可以用make oldconfig了。
    如果要修改的话,要注意systemd对内核的配置是有要求的,我并没有改。

    编译Linux内核的时候,提示我的系统中缺少bc,用你的包管理器安上就好了。

    $ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
    $ export CROSS_COMPILE=arm-none-linux-gnueabi-
    $ export PATH=$PATH:/home/spy/Work/program/u-boot/tools
    $ cd /home/spy/Work/sources/linux/linux-3.14.4
    
    $ make O=/home/spy/Work/program/linux ARCH=arm help
    $ make O=/home/spy/Work/program/linux ARCH=arm oldconfig
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 uImage
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 dtbs
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 modules
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 INSTALL_MOD_PATH=/home/spy/Work/root/program/linux/modules modules_install
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 INSTALL_FW_PATH=/home/spy/Work/root/program/linux/firmware firmware_install
    $ make O=/home/spy/Work/program/linux ARCH=arm LOADADDR=0x80008000 INSTALL_HDR_PATH=/home/spy/Work/root/program/linux/headers headers_install
    

    make help是否指定ARCH,输出内容是不同的。

    uImage就是Linux内核,编译时需要mkimage这个工具,编译U-Boot的时候会生成那个工具,
    所以我编译内核之前将该目录加到了PATH环境变量中。

    需要指定“LOADADDR”,否则会有下面的问题。

      Kernel: arch/arm/boot/zImage is ready
    multiple (or no) load addresses: 
    This is incompatible with uImages
    Specify LOADADDR on the commandline to build an uImage
    
    • dts --> device tree source
    • dtb --> device tree blob
    • dtbo --> device tree blob overlay
    • dtc --> device tree compile

    没研究为什么编译设备树是dtbs,是在make help的帮助中看到的。

    内核的配置中指定了很多把驱动编译成模块的,这部分需要make modules来单独编译。

    编译完成后,可在输出文件夹的arch/arm/boot找到zImage, uImage和dts子文件夹,dts里面有am335x-boneblack.dtb。zImage也是内核,也可以用,但我用的uImage。

    最后那三个安装目录自己选个更好的吧。

    • modules会安在lib/moduleslib/firmware2个文件夹中。
      DEPMOD  3.14.4
    depmod: ERROR: Module 'hci_vhci' has devname (vhci) but lacks major and minor information. Ignoring.
    

    安装modules的时候,可能会提示depmod出问题,据说正常,那不是处理交叉编译的模块的。
    但我还是看到了depmod后应该出现的modules.dep文件。
    depmod是用来构建模块依赖关系的,目的是,当用insmod装载某模块的时候,可能会失败,
    因为这个模块依赖的其他模块还没有装入内核,depmod构建完依赖关系后,用另外一个命令装载模块,即可自动装载模块所依赖的其他模块。

    • firmware也安在lib/firmware中,但与modules中的不同。我目前不知道firmware是干什么的。

    • headers还是需要安装的,它就像glibc那样,编译程序时被调用。


    下面可以验证了。
    将uImage文件,dts文件夹复制到SD卡第二个分区的/boot/里。
    其实dts中应该只需am335x-boneblack.dtb。

    启动开发板前应该了解下U-Boot如何载入Linux。

    U-Boot中最关键的环境变量

    • bootcmd: This variable defines a command string that is automatically executed when the initial countdown is not interrupted.
      This command is only executed when the variable bootdelay is also defined!
    • bootargs: The contents of this variable are passed to the Linux kernel as boot arguments (aka "command line").

    U-Boot中最关键的命令

    • run - run commands in an environment variable

    U-Boot启动后会运行bootcmd里的命令,所以要研究的话,从bootcmd开始。

    提示:我的研究在后面。现在可不必研究直接看我的处理。

    编译后的U-Boot是不能引导uImage的,通过printenv看U-Boot的环境变量,
    可看到它找的是zImage,而且am335x-boneblack.dtb是在/boot/中找,不是/boot/dts/

    为了符合我的要求,要修改环境变量,可以用editenv修改环境变量后saveenv。

    但还是别这么做了,我不知道它把环境变量保存到哪里去了。我以为把MLO和u-boot.img换回原始的可以恢复默认的环境变量值,但不是这样,把SD卡格式化后也没用。
    有可能是存到eMMC中了,我想尽各种办法破坏eMMC的数据,用了
    dd if=/dev/zero of=/dev/mmcblk1也不行。
    除了mmcblk1还有个mmcblk1boot,可能是存到那里了,记着那个设备比较奇怪,没有验证。
    最后用env default -a然后saveenv恢复默认了。

    另一个方法是创建一个uEnv.txt文件,将它和MLO放到一起,内容如下。
    该文件中的环境变量会覆盖掉默认的环境变量。

    bootdir=/program/linux/boot
    bootfile=uImage
    loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/dts/${fdtfile}
    mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootm ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
    mmcroot=/dev/mmcblk0p2 rw
    mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} init=/program/systemd/root/lib/systemd/systemd
    
    

    一共7行,最后一行空白。

    • bootdir修改了内核存放的目录。
    • bootfile修改了内核名字,
    • loadfdt中只是在目录中加了“dts/”,
    • mmcloados主要是把bootz改成bootm。
    • mmcroot把只读改成了读写,原因是systemd启动后会创建一个machine-id到/etc中。也许有其他办法,如/etc/fstab文件,但我为了简单没创建那个文件。
    • mmcargs只是在后面指定了init为systemd,也有其他方法,如init为指向systemd的软链接。

    启动BeagleBone Black,待内核启动后会打印很多信息,最后你将目睹“kernel panic”,
    这是因为我们目前并没有init程序,为了找到成就感,
    你可以编译下面静态链接的“Hello world!”,放到某个目录中,
    然后在U-Boot的mmcargs变量中把init指定为那个hello。

    hello.c

    #include <stdio.h>
    
    int main(int argc, char *argv)
    {
      printf("Hello world!\n");
      sleep(999999999);
    }
    
    $ arm-none-linux-gnueabi-gcc -o hello -static hello.c
    

    再次启动,最后你看到的将是"Hello world!"。


    我分析了U-Boot的引导过程,如下,再往下是我的演示。

    gpio set 53   //这个是点亮LED灯的,其实并没有这个,是我在其他的U-Boot中看到的。
    i2c mw 0x24 1 0x3e //这个也没有,不知干什么的。
    mmc dev 0 //将设备切换到'0',即SD卡,其实一开始就是'0',eMMC是'1'。
    mmc rescan //应该是检测设备是否存在吧。
    
    gpio set 54
    load mmc 0 0x80200000 uEnv.txt
    env import -t 0x80200000 $filesize //这2步是导入环境变量,filesize这个变量没找到。
    
    gpio set 55
    load mmc 0:2 0x80200000 /boot/uImage
    
    gpio set 56
    load mmc 0:2 0x80F80000 /boot/dts/am335x-boneblack.dtb
    
    setenv bootargs console=ttyO0,115200n8 ${optargs} root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait init=/usr/lib/systemd/systemd
    bootm 0x80200000 - 0x80F80000
    
    optargs这个环境变量也没找到,在其他U-Boot中发现是quiet,
    作用是减少了内核打印的信息,systemd打印的信息也少了。
    
    U-Boot# mmc dev 0
    mmc0 is current device
    U-Boot# mmc rescan
    U-Boot# load mmc 0:2 0x80200000 /boot/uImage
    3894896 bytes read in 237 ms (15.7 MiB/s)
    U-Boot# load mmc 0:2 0x80F80000 /boot/dts/am335x-boneblack.dtb
    17911 bytes read in 213 ms (82 KiB/s)
    U-Boot# setenv bootargs console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait init=/usr/lib/systemd/systemd
    U-Boot# bootm 0x80200000 - 0x80F80000
    ## Booting kernel from Legacy Image at 80200000 ...
       Image Name:   Linux-3.13.5
       Image Type:   ARM Linux Kernel Image (uncompressed)
       Data Size:    3894832 Bytes = 3.7 MiB
       Load Address: 80008000
       Entry Point:  80008000
       Verifying Checksum ... OK
    ## Flattened Device Tree blob at 80f80000
       Booting using the fdt blob at 0x80f80000
       Loading Kernel Image ... OK
       Using Device Tree in place at 80f80000, end 80f875f6
    
    Starting kernel ...
    
    [    0.000000] Booting Linux on physical CPU 0x0
    [    0.000000] Initializing cgroup subsys cpuset
    [    0.000000] Initializing cgroup subsys cpu
    [    0.000000] Initializing cgroup subsys cpuacct
    [    0.000000] Linux version 3.13.5 (spy@alien) (gcc version 4.8.1 (Sourcery CodeBench Lite 2013.11-33) ) #1 SMP Sat Mar 8 20:26:55 UTC 2014
    

    我并没有导入uEnv.txt,它是下面这个样子的。

    U-Boot# load mmc 0 0x80200000 uEnv.txt
    reading uEnv.txt
    510 bytes read in 4 ms (124 KiB/s)
    U-Boot# env import -t 0x80200000
    ## Info: input data size = 966 = 0x3C6
    
    

    下面就是应用程序了,可根据我的提示自行安排顺序,我曾经的顺序不是这样的。
    主要的过程就是glibc,bash,coreutils,util-linux,systemd,shadow,
    这些中间的都是被依赖的程序。
    bash需要libgcc_s.so.1,它位于gcc中,但编译gcc时间较长,gcc还依赖5个程序。
    迫不及待验证编译结果的话可以先把交叉编译器中的库复制到开发板系统中,我当初就那么做的。

    • glibc是程序库,几乎动态链接的程序都要用到了,"Hello world"中的printf函数都需要。
    • bash是个shell,即命令解释器,提供了人与计算机交互的界面。
    • coreutils里有很多常用命令,如'ls'。
    • util-linux也是有很多命令,如mount,login,fdisk。
    • systemd是个init程序。
    • shadow是和登陆相关的,主要是把'/etc/passwd'文件里的密码变成“x”,
      里面有login,passwd,useradd等命令。

    其实系统启动后的第一个程序是systemd,但它的文档较少,不了解是怎么工作的,所以先保证其他的能工作,再研究。

    至于怎么编译,源码中会有README,INSTALL等文档。


    环境变量的设置。

    $ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
    $ export PKG_CONFIG_LIBDIR=/home/spy/Work/data/index/lib/pkgconfig
    $ export PKG_CONFIG_SYSROOT_DIR=/home/spy/Work
    

    有些程序的编译需要pkg-config这个程序,这个程序根据系统程序库中的.pc文件,生成编译时的参数。
    我这样设置是为了找到我们自己编译的,而不是/usr/lib/pkgconfig中的。
    PKG_CONFIG_LIBDIR覆盖了pkg-config默认的搜索路径。
    PKG_CONFIG_SYSROOT_DIR是为了交叉编译准备的,它的值会加到参数前。

    glibc

    18
    /usr/local
    ->
    <- bash, //这2个依赖和被依赖的,仅供参考,肯定不全的,下面也一样。

    $ cd /home/spy/Work/sources/glibc/build
    $ ../glibc-2.19/configure --prefix=/program/glibc --oldincludedir=/program/glibc/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install install_root=/home/spy/Work
    

    源码中并没有makefile文件,这需要运行configure来生成。
    通过configure --help查看可用的选项。

    • prefix为安装目录;
    • oldincludedir,不太清楚,根本没用上;
    • build和host用来指定系统类型。可看看autoconf的手册中“Specifying target triplets”。
    • build - 构建程序的系统,在该系统中配置和编译程序。
    • host - 构建后的程序运行在此系统中。
    • target - 编译工具为此系统生成程序。

    这个target,配置glibc不用指定,有的文档中是这样说的。

    It's for use when building compiler tools, with --host being where they
    will run, and --target what they'll produce code for.

    也就是说,通常用在构建编译工具的时候,举个例子,

    • 如果你在你的x86_64计算机中编译gcc,运行在你的x86_64系统中,让gcc生成的程序也运行在x86_64中,
      这三个是这样的(为了突出重点,我简化了等号右边):
      build=x86_64,host=x86_64,target=x86_64。
      在Arch Linux中运行pacman -S gcc安装的就是这种(pacman是包管理器)。
    • 前2个条件不变,如果让gcc生成的程序运行在arm中,就像我们要用的Sourcery CodeBench Lite,那么这三个是这样的:
      build=x86_64,host=x86_64,target=arm
    • 第一个条件不变,如果让gcc运行在arm中,生成的程序也运行在arm中,就像后面我们要编译的,这三个是这样的:
      build=x86_64,host=arm,target=arm

    等号右边的格式如下:

    cpu-company-system

    system可以有以下2种格式之一

    os
    kernel-os

    查看源码中的config.sub文件,能看到各部分可能的值。
    运行configure的时候,如果没指定的话,configure会用config.guess这个脚本猜出build的值。然后host默认等于build,target默认等于host。
    config.guess通常和config.sub在一起,都可单独运行的,有“--help”这个选项可用。

    在我的系统中猜测出的值为“x86_64-unknown-linux-gnu”。
    在BeagleBone Black中,结果为“armv7l-unknow-linux-gnueabihf”。
    这个结果应该是不知道的,因为我是在BeagleBone Black已经可用的系统中运行的config.guess
    而我们的系统还没有构建出来呢,不可能运行config.guess。

    那么我们如何确定host呢,难道要看config.sub?不必。
    当build和host不同的时候,configure会启用交叉编译模式。
    它会检测以host值为前缀的编译工具,如arm-none-linux-gnueabi-gcc,
    然后使用这个带前缀的gcc。所以我们的host指定为我们交叉编译器中命令的前缀就好了。
    我尝试过了,如果host是“abcdefg”这种,大概会提示无效的值;
    如果是“arm-none-linux-gnueabihf”这种有效的,
    configure会检测arm-none-linux-gnueabihf-gcc,他是找不到的。

    既然build可以猜测出来,那是否还要指定呢,我开始就是没指定,可以的。但是autoconf手册中:

    “For historical reasons, whenever you specify --host, be sure to specify --build too; this will be fixed in the future.”

    看来这个“future”已经到了,但我还是指定了。

    我们编译程序是用在其他的系统中,如果不指定install_root,它就要往prefix指定的目录安了,
    不要这样,我的路径还好,如果是/usr/lib/,那就破坏了你正使用的系统,不过我用的是普通用户,应该没权限往那个目录安。
    有了install_root,就会安装到/home/spy/Work/program/glibc,看看makefile文件就会明白原理。
    那么把prefix指定为那个完整的目录,不使用install_root行不行呢。最好别这样。
    构建完glibc,其中的ld.so并不是在/lib/或/usr/lib/中找程序库,而是在glibc的库被安装到的目录中找,即/program/glibc/lib
    可见,这个prefix会记录到生成的程序中,所以最好别让目录那么长,那么乱。

    问题又来了,ld.so竟然不在/usr/lib/中找程序库,这可是传说中的默认目录啊。
    我的处理是在构建的系统中运行ldconfig,在bash中说。

    gmp

    2
    /usr/local
    ->
    <- mpfr,mpc,isl,cloog,gcc

    编译这个的时候提示我缺少m4,安上。

    $ cd /home/spy/Work/sources/gmp/build
    $ ../gmp-6.0.0/configure --prefix=/program/gmp --oldincludedir=/program/gmp/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    这个和下面的4个都是为gcc服务的。
    这里的安装目录用的是DESTDIR,看看源代码里的文档吧。

    mpfr

    2
    /usr/local
    -> gmp,
    <- mpc,gcc

    $ cd /home/spy/Work/sources/mpfr/build
    $ ../mpfr-3.1.2/configure --prefix=/program/mpfr --oldincludedir=/program/mpfr/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp=/home/spy/Work/program/gmp
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    修改lib/libmpfr.la

    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib /program/gmp/lib/libgmp.la'
    

    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib /home/spy/Work/program/gmp/lib/libgmp.la'
    

    也就是把目录改成完整的,这个过程的原因见mpc。

    make时会看到其他警告,libgmp.la文件被moved,答案也是见mpc。

    mpc

    1
    /usr/local
    -> gmp,mpfr
    <- gcc

    $ cd /home/spy/Work/sources/mpc/build
    $ ../mpc-1.0.2/configure --prefix=/program/mpc --oldincludedir=/program/mpc/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp=/home/spy/Work/program/gmp --with-mpfr=/home/spy/Work/program/mpfr
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    修改.la文件,

    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib -L/home/spy/Work/program/mpfr/lib /program/mpfr/lib/libmpfr.la /program/gmp/lib/libgmp.la -lm'
    

    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib -L/home/spy/Work/program/mpfr/lib /home/spy/Work/program/mpfr/lib/libmpfr.la /home/spy/Work/program/gmp/lib/libgmp.la -lm'
    

    找不到*.la的问题

    /usr/bin/sed: can't read /program/gmp/lib/libgmp.la: No such file or directory
    libtool: link: `/program/gmp/lib/libgmp.la' is not a valid libtool archive
    

    如果没有我mpfr中的修改,编译时就会出现这个错误。
    编译mpc的时候,应该读取了mpfr中的libmpfr.la。然后根据dependency_libs中的路径找libgmp.la,结果找不到。
    dependency_libs的前一部分,应该是由我配置时指定的--with-gmp来确定,而后半部分,看看安装后的gmp,也有个.la文件,文件中有个libdir,

    # Directory that this library needs to be installed in:
    libdir='/program/gmp/lib'
    

    很明显,这个libdir是根据编译gmp时指定的prefix确定的。

    如果把libdir手动改成'/home/spy/Work/program/gmp/lib',
    再编译mpfr,libmpfr.la中的dependency_libs就是,

    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib /home/spy/Work/program/gmp/lib/libgmp.la'
    

    这样也不会出现lib*.la文件被moved的警告。
    由此可见,后半部分是由所依赖的.la文件中libdir确定的。
    我最后没有选择修改libdir,虽然修改libdir也可以编译成功,而且没有警告。

    isl

    3
    /usr/local
    -> gmp
    <- gcc

    $ cd /home/spy/Work/sources/isl/build
    $ ../isl-0.12.2/configure --prefix=/program/isl --oldincludedir=/program/isl/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp-prefix=/home/spy/Work/program/gmp --with-gmp-exec-prefix=/home/spy/Work/program/gmp
    $ make
    $ make install DESTDIR=/home/spy/Work
    
    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib /program/gmp/lib/libgmp.la'
    
    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/gmp/lib /home/spy/Work/program/gmp/lib/libgmp.la'
    

    如果只指定with-gmp-prefix,没有 "--with-gmp-exec-prefix",竟然会有下面的错误。

    /home/spy/Work/program/gmp/lib/libgmp.so: error adding symbols: File in wrong format
    

    cloog

    1
    /usr/local
    -> isl,gmp
    <- gcc

    $ cd /home/spy/Work/sources/cloog/build
    $ ../cloog-0.18.1/configure --prefix=/program/cloog --oldincludedir=/program/cloog/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --with-gmp-prefix=/home/spy/Work/program/gmp --with-gmp-exec-prefix=/home/spy/Work/program/gmp --with-isl=system --with-isl-prefix=/home/spy/Work/program/isl --with-isl-exec-prefix=/home/spy/Work/program/isl
    

    修改Makefile libcloog-isl.la:

    libcloog_isl_la_LDFLAGS = -version-info 4:0:0 \
      -L/home/spy/Work/program/isl/lib 
    
    am_libcloog_isl_la_rpath = -rpath /home/spy/Work/program/isl/lib
    
    $ make
    $ make install DESTDIR=/home/spy/Work
    
    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/isl/lib -L/home/spy/Work/program/gmp/lib /program/isl/lib/libisl.la /program/gmp/lib/libgmp.la'
    
    # Libraries that this one depends upon.
    dependency_libs=' -L/home/spy/Work/program/isl/lib -L/home/spy/Work/program/gmp/lib /home/spy/Work/program/isl/lib/libisl.la /home/spy/Work/program/gmp/lib/libgmp.la'
    

    --with-isl=system 目的是使用之前编译的isl,cloog源码中有也有份isl。


    编译时错误undefined reference

    warning: libisl.so.10, needed by ./.libs/libcloog-isl.so, not found (try using -rpath or -rpath-link)
    

    rpath的问题,解决见make前操作。

    一看和isl有关,cloog的源码中自带了一份isl,我配置时没用cloog中的,
    当出现这个错误时,我配置成用cloog中的,这样编译cloog的时候,会有编译isl的过程,结果编译isl的时候就有错误。
    看了一下cloog中的isl,版本低一些。
    我单独编译这个isl或者在isl官网下载同样的版本,都是出错,为了解决cloog的错误,我决定先解决简单一些的isl的错误入手。

    isl-0.12.1版本的问题

    isl_polyhedron_sample
    isl_polytope_scan
    isl_polyhedron_detect_equalities
    isl_cat
    isl_closure

    以上就是编译时出现过的有问题的make对象。在makefile文件中,用了下面的rpath即可解决。
    -rpath /home/spy/Work/program/gmp/lib
    rpath是运行时搜索程序库的路径,是gcc的参数,可以写到编译后的程序中的。

    也许还有别的对象,但都用LINK

    LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
      $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
      $(AM_LDFLAGS) $(LDFLAGS) -o $@
    

    更改 AM_LDFLAGS = -rpath /home/spy/Work/program/gmp/lib
    就都解决了。

    但我发现了另一个方式,把这一个改对就可以

    libisl.la: $(libisl_la_OBJECTS) $(libisl_la_DEPENDENCIES) $(EXTRA_libisl_la_DEPENDENCIES) 
      $(AM_V_CCLD)$(libisl_la_LINK) -rpath /home/spy/Work/program/gmp/lib $(libisl_la_OBJECTS) $(libisl_la_LIBADD) $(LIBS)
    

    我不知道这样做是否会出现什么问题,但还没遇到,除了下面没造成什么影响的。

    按这个方式修改cloog的makefile的时候,
    .la文件中,安装路径里出现的应该是cloog啊,竟然是isl,我做了修改,

    # Directory that this library needs to be installed in:
    libdir='/home/spy/Work/program/isl/lib'
    

    改成

    # Directory that this library needs to be installed in:
    libdir='/program/cloog/lib'
    

    其实这次编译的时候isl已经是0.13版本了,这一版本抛弃了isl_int,
    而cloog的发行版还没有跟上,虽然git中有更新,但我不会用。这会有下面的问题。
    unknown type name 'isl_int'

    gcc

    54
    /usr/local
    -> gmp,mpfr,mpc,isl,cloog
    <- bash

    $ cd /home/spy/Work/sources/gcc/build
    $ ../gcc-4.9.0/configure --prefix=/program/gcc --oldincludedir=/program/gcc/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi --enable-shared --enable-threads --enable-languages=c --with-gmp=/home/spy/Work/program/gmp --with-mpfr=/home/spy/Work/program/mpfr --with-mpc=/home/spy/Work/program/mpc --with-isl=/home/spy/Work/program/isl --with-cloog=/home/spy/Work/program/cloog
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    gcc就是编译器了,我们编译软件就靠它了,gcc也包含一些库,我们的bash要用到。
    gcc的配置选项太多了,我只额外用了
    --enable-shared --enable-threads --enable-languages=c
    也不知道是否需要。

    bash

    1
    /usr/local
    -> glibc,gcc,
    <-

    $ cd /home/spy/Work/sources/bash/build
    $ ../bash-4.3/configure --prefix=/program/bash --oldincludedir=/program/bash/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --without-bash-malloc
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    --with-installed-readline
    本想加这个选项,但我编译readline的时候,提示不让交叉编译,我做点修改还是编译了。
    但配置bash时,检测到交叉编译,竟然忽略了这一选项,那我还是别用这选项了。

    我的bash好像有点问题,开发板中编译软件时,执行makefile中的脚本发现的问题,在开发板中重新编译了一次bash,问题消失了。
    而且之前输入命令满一行不能自动换行,始终在一行。

    在这里推荐个工具,readelf,这是binutils中的一个命令。可查看二进制文件的信息,我用它主要是为了看到所依赖的库。
    $ readelf -hld bin/bash
    -a选项是打印所有的信息,我们用-hld就可以了。
    看看我们编译后的bash,它需要gcc中的libgcc_s.so.1,而我电脑中的bash却不需要那个库。


    有了shell,我们就可以在开发板中验证我们编译的结果了。
    至此,我们编译了glibc,gmp,mpfr,mpc,isl,cloog,gcc,bash。
    在复制到SD卡之前,我想应该先把mpfr,mpc,isl,cloog中的改动改回来。
    根据prefix,将编译后的程序复制到SD卡,/data/index/lib//data/index/bin/中添加相应的软链接。
    我并不是在这个时候才制作的软链接,每编译过一个程序,发现有bin和lib文件夹,就把软链接做好了,直接复制到SD卡中就可以了。
    至于怎么制作,我不擅长,写个脚本应该比较好,但我没学。
    /data/configuration/中不必有配置文件。

    在uEnv.txt中,把bootargs的init改为/program/bash

    如果就这样启动的话,会提示找不到libgcc_s.so.1,因为这个库不在ld.so的搜索路径中。
    目前的搜索路径是/program/glibc/lib
    所以/program/glibc/lib中有个libgcc_s.so.1就可以了,
    可以放一个软链接,就像/data/index/lib中的。
    不要担心,这只是临时的。

    接下来我们要在开发板中运行ldconfig,这是glibc的一部分,
    它会读取ld.so.conf文件中的路径,然后建立一个ld.so.cache文件,
    这样ld.so就能利用ld.so.cache找到那些路径中的库了。

    ld.so.conf文件不存在,而我们构建的系统还没有文本编辑器,所以要在启动之前建立该文件。内容就是

    /data/index/lib
    
    

    很多文本文件都以空行结尾,我们也这么做吧。
    那么这个文件要放到哪里呢,一般是/etc/中,但在我们构建的系统中,ldconfig是到/program/glibc/etc/中找,所以要放到这个目录中。

    好,可以启动开发板了,进到shell之后,运行ldconfig。
    /program/glibc/lib中的libgcc_s.so.1删掉,重启,看看是不是可以正常运行了?

    这样的方法并不好,应该让编译glibc的时候可以指定ld.so的搜索路径。
    其实我当初用了更不好的方法,我在内核参数中指定了LD_LIBRARY_PATH
    我还试过把init改成ldconfig,但没成功。由于ID为1的程序结束导致“kernel panic”倒是可理解。

    虽然我们没安什么程序,但bash是有内置命令的,比如切换目录的cd,查看当前目录的pwd

    coreutils

    2
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/coreutils/build
    

    也许要先编译一遍本地版的,先看下面的解释。

    $ ../coreutils-8.22/configure --prefix=/program/coreutils --oldincludedir=/program/coreutils/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --enable-install-program=arch,hostname
    

    修改Makefile,.x.1对象,$(abs_top_builddir) 改 /home/spy/Work/sources/coreutils

    $ make
    $ make install DESTDIR=/home/spy/Work
    

    --enable-install-program=arch,hostname
    默认不安那2个,这样就安了。

    help2man不能得到help信息

    help2man: can't get `--help' info from man/chroot.td/chroot
    Try `--no-discard-stderr' if option outputs to stderr
    

    help2man通过目标程序--help选项的输出来生成man,
    而我是交叉编译,目标程序不能在我的系统中运行。
    所以我先编译了一遍本地版的,
    把运行make那个目录中的src文件夹复制到了/home/spy/Work/sources/coreutils
    重新配置成交叉编译,在make之前修改makefile文件,
    将help2man的目标程序指定到本地版的。

    linux-pam

    1
    /usr
    ->
    <- util-linux,libcap,

    $ cd /home/spy/Work/sources/linux-pam/build
    

    先看下面的问题。

    $ ../Linux-PAM-1.1.8/configure --prefix=/program/linux-pam --oldincludedir=/program/linux-pam/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    pam与认证有关,如果没有这个,编译util-linux的时候就不会有login。
    util-linux的配置中并没有指定pam的选项,所以安装后,我把pam的库和头文件做了软连接,放到我交叉编译器搜索库的目录中了。
    我也尝试过把gcc依赖的库放到交叉编译器搜索库的目录中,但遇到了新的问题,时间关系,没有研究。

    pam的库中也有个la文件,根据pam所放的目录,做类似下面的修改。
    libpam_misc.la

    # Libraries that this one depends upon.
    dependency_libs=' /home/spy/Work/program/linux-pam/lib/libpam.la -ldl'
    

    include/security/
    需要pam头文件的程序在那个目录找而不是include/
    编译其他程序的时候如果提示找不到头文件,可改下目录。

    yywrap的问题

    搜索后这个函数在flex中,安装后,我也不太会用,
    conf/pam_conv1/Makefile
    LIBS = -lfl

    doc/specs/Makefile

    还有一些其他新问题,于是换策略。

    conf/pam_conv1/pam_conv_l.c

    int     yywrap (void)
    {
      return 1;
    }
    

    doc/specs/parse_l.c

    int     yywrap (void)
    {
      return 1;
    }
    

    就是在那2个c源文件中添加yywrap函数,
    反正felx中有个libyywrap.c,里面的函数就这个样子。

    ncurses

    3
    /usr/local
    ->
    <- util-linux,nano,vim

    $ cd /home/spy/Work/sources/ncurses/build
    $ ../ncurses-5.9/configure --prefix=/program/ncurses --oldincludedir=/program/ncurses/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi --with-shared --enable-widec --with-build-cc=gcc
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    也是放到交叉编译器搜索库的目录中,再做个下面那样的软连接,因为有些程序找的是ncurses。
    ncurses -> ncursesw

    util-linux

    3
    /usr
    -> pam,ncurses
    <-

    $ cd /home/spy/Work/sources/util-linux/build
    

    先看下面的问题。

    $ ../util-linux-2.24.2/configure --prefix=/program/util-linux --oldincludedir=/program/util-linux/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ su
    # make install DESTDIR=/home/spy/Work
    
    • 带ncurses编译时,
      text-utils/more.c:200:51
      text-utils/pg.c:60:18
      text-utils/ul.c:46:41
      term-utils/setterm.c:113:18
      misc-utils/cal.c:82:19
      提示找不到term.h,把源文件中改成下面那样就好了。
      <ncurses/term.h>

    • 带pam库编译时
      cannot find the library /program/linux-pam/lib/libpam.la' or unhandled argument/program/linux-pam/lib/libpam.la'
      修改libpam_misc.la中的路径,见pam中的修改。

    安装时,不能改变bin/wall的用户组为tty
    我采用了安装时切换用户为root的方法。

    libcap

    0
    -> pam
    <- systemd,

    $ cd /home/spy/Work/sources/libcap/libcap-2.24
    

    将makefile要引入的文件Make.Rules做如下修改。

    CC := arm-none-linux-gnueabi-gcc
    BUILD_CC := gcc
    AR := arm-none-linux-gnueabi-ar
    RANLIB := arm-none-linux-gnueabi-ranlib
    SYSTEM_HEADERS = /home/spy/Software/arm-2013.11/arm-none-linux-gnueabi/libc/usr/include
    LIBATTR := no
    
    $ make prefix=/program/libcap lib=lib DESTDIR=/home/spy/Work
    $ make install prefix=/program/libcap lib=lib DESTDIR=/home/spy/Work
    

    完成以上步骤,也是做一份软连接和交叉编译器的库放到一起。

    xz

    1
    /usr/local
    ->
    <- systemd

    $ cd /home/spy/Work/sources/xz/build
    $ ../xz-5.0.5/configure --prefix=/program/xz --oldincludedir=/program/xz/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    kmod

    1
    /usr
    ->
    <- systemd

    $ cd /home/spy/Work/sources/kmod/build
    $ ../kmod-17/configure --prefix=/program/kmod --oldincludedir=/program/kmod/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    编译完的目录中是有一些软链接指向kmod命令的,但安装完的目录里没有那些软链接。
    这些软链接很有意思啊,比如insmod指向kmod,输入insmod实际运行的不是kmod,而是kmod insmod。大概是这样的。

    kmod与模块有关,所以你的系统中应该放上编译内核时的模块了。

    systemd

    22
    /usr
    -> libcap
    <-

    $ cd /home/spy/Work/sources/systemd/build
    

    修改configure,避免rpl_malloc的错误

      if test "$cross_compiling" = yes; then :
      ac_cv_func_malloc_0_nonnull=no 改成 yes
    

    配置出错时提示过的
    sys/capability.h 在libcap中
    pkg-config
    intltool
    gperf

    后3个不是库,编译时被调用,又不像编译器那样为另一个平台生成程序,
    所以应该不必为我构建的系统编译他们,用自己Linux系统的包管理器安上就好了。

    $ ../systemd-212/configure --prefix=/program/systemd --oldincludedir=/program/systemd/oldinclude --with-rootprefix=/program/systemd/root --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --disable-seccomp --disable-blkid --disable-libcryptsetup --disable-audit --disable-acl --disable-xattr --disable-selinux --disable-gcrypt --disable-qrencode --disable-microhttpd --disable-gudev --without-python
    

    看下面修改Makefile。

    $ make
    $ make install DESTDIR=/home/spy/Work
    

    --with-rootprefix=/program/systemd/root
    由于安装的时候会有一些东西安装在了program文件夹之外,指定这个选项为安装路径内部就可以了,
    root是我随便起的,但最好与其他文件夹独立。

    后面那些都是可选的软件包,我全禁用了。
    还有一些可选的如kmod,xz,没有禁用。
    曾经禁用过kmod,发现不能自动载入模块。

    编译时和kmod有关的错误。

    KMOD_CFLAGS = -I/home/spy/Work/program/kmod/include
    KMOD_LIBS = -L/home/spy/Work/program/kmod/lib -lkmod
    这是Makefile中的参数,有些对象需要但并没加上。
    于是我修改了Makefile。

    test_CFLAGS = \
      $(KMOD_CFLAGS)
    
    .c.o:
    $(test_CFLAGS)
    

    Makefile前部分加了test_CFLAGS,然后在.c.o对象的适当位置加上$(test_CFLAGS)

    test_rtnl_manual_LDADD = \
      libsystemd-internal.la \
      libsystemd-shared.la \
      -L/home/spy/Work/program/kmod/lib -lkmod
    

    这里加上了库的目录。

    关于systemd

    /*------------------------------------------------------------------------------
    终于到了真正的init程序,这么伟大的程序,竟然没找到学习的文档。

    systemd包含了udev。

    /etc/mtab -> /proc/self/mounts
    所以/data/configuration/中应该放个mtab了。
    如果不放,启动的时候会有警告提示。


    systemd对一些目录的要求。
    参见http://www.freedesktop.org/wiki/Software/systemd/FileHierarchy/

    • /, /usr, /etc must be mounted when the host systemd is first invoked. This may
      be achieved either by using the kernel's built-in root disk mounting (
      in which case /, /usr and /etc need to be on the same file system), or
      via an initrd, which could mount the three directories from different sources.

    • /bin, /sbin, /lib (and /lib64 if applicable) should reside on /, or be symlinks
      to the /usr file system (recommended). All of them must be available
      before the host systemd is first executed.

    • /var does not have to be mounted when the host systemd is first invoked,
      however, it must be configured so that it is mounted writable
      before local-fs.target is reached (for example, by simply listing it in /etc/fstab).

    • /tmp is recommended to be a tmpfs (default), but doesn't have to. If configured,
      it must be mounted before local-fs.target is reached (for example, by listing it in /etc/fstab).

    • /dev must exist as an empty mount point and will automatically be mounted
      by systemd with a devtmpfs. Non-devtmpfs boots are not supported.

    • /proc and /sys must exist as empty mount points and
      will automatically be mounted by systemd with procfs and sysfs.

    • /run must exist as an empty mount point and will automatically be mounted by systemd with a tmpfs.

    测试

    又到了体验成就感的时候,目前,我们已经拥有的程序,
    glibc,gmp,mpfr,mpc,isl,cloog,gcc,bash,
    coreutils,linux-pam,ncurses,util-linux,libcap,xz,kmod,systemd。
    放到SD卡中。
    也许最好把SD卡中文件的用户和组改成root,但是util-linux中的wall属于tty组。
    我下面这2条命令是不全的。

    # chown -R 0:0
    # chgrp -v tty /program/util-linux/bin/wall
    

    由于有了新的程序库,而且是systemd需要用到的,所以先别急着改把init改成systemd,
    那样应该会提示找不到库的,所以先用bash,执行一下ldconfig,然后再改,
    init=/program/systemd/root/lib/systemd/systemd


    /data/configuration/中的文件,目前就有个mtab,
    如果没有passwd文件,会有登陆的提示,还会让输入密码,然后就是登陆失败,所以要创建。
    /data/configuration/passwd

    root::0:0:root:/user/root:/program/bash/bin/bash
    

    目前不能设置密码,设置了会登陆失败,不知为什么,可能为了安全吧。所以密码部分空着。


    /data/configuration/pam.conf

    other auth    required  pam_unix.so nullok
    other account   required  pam_unix.so
    other session   required  pam_unix.so
    other password  required  pam_unix.so
    

    这是pam的配置文件,可看看pam的手册,内容没深入研究,是我自己看了很多配置后定的。

    第一部分是需要pam的程序的名字,如login,改成login也可以。
    最后的nullok选项是必要的,这允许没有密码的登陆。

    前面说到,不能在passwd中设置密码,我本以为加了broken_shadow选项就可以了,但不是。

    pam也可以在/etc/pam.d/中找配置文件,这个是shadow的一部分,里面不止一个配置文件。
    如果pam.d存在,则忽略pam.conf。


    现在启动BeagleBone Black吧,
    systemd启动后,会在/data/configuration/中创建一个machine-id文件,
    最后systemd会启动在ttyO0上的登陆服务,提示登陆,输入root,确定后就看见bash了。

    一些命令,
    显示这次登陆的日志,

    # journalctl -b
    

    重启,

    $ systemctl reboot
    

    关机

    $ systemctl poweroff
    

    但我的关上后,电源指示灯还亮着,别的灯倒是灭了。

    shadow

    1
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/shadow/build
    

    看下面修改configure。

    $ ../shadow-4.2.1/configure --prefix=/program/shadow --oldincludedir=/program/shadow/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --enable-shared
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    vflg,Vflg,is_sub_uid,wflg,Wflg 未定义

    修改configure
    搜索“run test”,在附近做修改。

    if test "$cross_compiling" = ye;
    

    不是“yes”就好。

      id32bit="yes"
    

    else中的也改成“yes”。

    一切是为了实现

    ENABLE_SUBIDS_FALSE='#'
    ENABLE_SUBIDS_TRUE=''
    

    shadow中有与已安装程序相同的命令,我选择了shadow中的。
    util-linux {login,nologin,su}
    coreutils {groups}

    它的配置文件要复制一份到/etc/中。
    它的配置文件不可以直接用,看看pam.d中的login文件。
    内容的格式也就是少了第一部分,这部分用文件名表示了。
    奇怪的是你会在配置中发现include,但后面的文件没有。
    你也会看到额外的配置,先参照pam.conf改吧。

    登陆的时候,会提示一些,

    configuration error - unknown item
    

    这与shadow中的login.defs有关。

    binutils

    4
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/binutils/build
    $ ../binutils-2.24/configure --prefix=/program/binutils --oldincludedir=/program/binutils/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    这里面有汇编器,连接器等,我的目的是可以在开发板中构建程序。
    LFS的网站上说,这个要在glibc和gcc之前编译,但我是现在编译的,

    make

    1
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/make/build
    $ ../make-4.0/configure --prefix=/program/make --oldincludedir=/program/make/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    sed

    0
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/sed/build
    $ ../sed-4.2.2/configure --prefix=/program/sed --oldincludedir=/program/sed/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    configure脚本中会用到的,还有grep,gawk。

    grep

    0
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/grep/build
    $ ../grep-2.9/configure --prefix=/program/grep --oldincludedir=/program/grep/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    gawk

    1
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/gawk/build
    $ ../gawk-4.1.1/configure --prefix=/program/gawk --oldincludedir=/program/gawk/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    nano

    0
    /usr/local
    -> ncurses
    <-

    $ cd /home/spy/Work/sources/nano/build
    

    好像要修改源文件。或者修改configure的CPPFLAGS?我选择了前者。

    $ ../nano-2.2.6/configure --prefix=/program/nano --oldincludedir=/program/nano/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    
    src/nano.h:92:20: fatal error: curses.h: No such file or directory
    
    #elif defined(HAVE_NCURSES_H)
    #include <ncursesw/ncurses.h>
    #else
    /* Curses support. */
    #include <ncursesw/curses.h>
    #endif /* CURSES_H */
    

    less

    0
    /usr/local
    ->
    <-

    $ export PATH=$PATH:/home/spy/Software/arm-2013.11/bin
    $ cd /home/spy/Work/sources/less/build
    
    $ ../less-458/configure --prefix=/program/less --oldincludedir=/program/less/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    有了它,journalctl的输出就舒服了。man的输出也是放到less中。

    findutils

    /usr/local
    ->
    <-
    安装程序的时候,有时会需要这个,比如vim。
    在开发板中编译的。有个时间的问题,

    checking whether build environment is sane... configure: error: newly created file is older than distributed files!
    Check your system clock
    

    看过其他为开发板提供的系统,启动信息中有一条设置了时间,而我的不能。
    设置一下时间就好了。

    date -s 20140402
    

    diffutils

    1
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/diffutils/build
    $ ../diffutils-3.3/configure --prefix=/program/diffutils --oldincludedir=/program/diffutils/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    tar

    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/tar/build
    $ ../tar-1.27.1/configure --prefix=/program/tar --oldincludedir=/program/tar/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    gzip

    0
    /usr/local
    ->
    <-

    $ cd /home/spy/Work/sources/gzip/build
    $ ../gzip-1.6/configure --prefix=/program/gzip --oldincludedir=/program/gzip/oldinclude --build=x86_64-unknown-linux-gnu --host=arm-none-linux-gnueabi
    $ make
    $ make install DESTDIR=/home/spy/Work
    

    好了,现在我的系统已经可以编译软件了。
    虽然还缺少一些常用的软件。但构建Linux的思想已基本掌握,
    再这样安软件安下去没什么意义了。

    相关文章

      网友评论

        本文标题:【笔记】构建Linux

        本文链接:https://www.haomeiwen.com/subject/zocvottx.html