《自己动手构建Linux发行版》


1. 配置环境

[root@localhost ~]# uname -a

Linux localhost.localdomain 5.0.10-300.fc30.x86_64 #1 SMP Tue Apr 30 16:22:12 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost ~]# su - ztg

[ztg@localhost ~]$ pwd

/home/ztg

[ztg@localhost ~]$

set +h

umask 022

export MINILINUX=~/minilinux

mkdir -pv ${MINILINUX}

export LC_ALL=POSIX

export PATH=${MINILINUX}/cross-tools/bin:$PATH

// $ export PATH=${MINILINUX}/cross-tools/bin:/bin:/usr/bin

[ztg@localhost ~]$

mkdir -pv ${MINILINUX}/{bin,boot{,grub},dev,{etc/,}opt,home,lib/{firmware,modules},lib64,mnt}

mkdir -pv ${MINILINUX}/{proc,media/{floppy,cdrom},sbin,srv,sys}

mkdir -pv ${MINILINUX}/var/{lock,log,mail,run,spool}

mkdir -pv ${MINILINUX}/var/{opt,cache,lib/{misc,locate},local}

install -dv -m 0750 ${MINILINUX}/root

install -dv -m 1777 ${MINILINUX}{/var,}/tmp

install -dv ${MINILINUX}/etc/init.d

mkdir -pv ${MINILINUX}/usr/{,local/}{bin,include,lib{,64},sbin,src}

mkdir -pv ${MINILINUX}/usr/{,local/}share/{doc,info,locale,man}

mkdir -pv ${MINILINUX}/usr/{,local/}share/{misc,terminfo,zoneinfo}

mkdir -pv ${MINILINUX}/usr/{,local/}share/man/man{1,2,3,4,5,6,7,8}

for dir in ${MINILINUX}/usr{,/local}; do

    ln -sv share/{man,doc,info} ${dir}

done

install -dv ${MINILINUX}/cross-tools{,/bin}

ln -svf ../../proc/mounts ${MINILINUX}/etc/mtab

cat > ${MINILINUX}/etc/passwd << "EOF"

root::0:0:root:/root:/bin/ash

EOF

cat > ${MINILINUX}/etc/group << "EOF"

root:x:0:

bin:x:1:

sys:x:2:

kmem:x:3:

tty:x:4:

daemon:x:6:

disk:x:8:

dialout:x:10:

video:x:12:

utmp:x:13:

usb:x:14:

EOF

cat > ${MINILINUX}/etc/fstab << "EOF"

# file system  mount-point  type   options          dump  fsck

#                                                         order

rootfs          /               auto    defaults        1      1

proc            /proc           proc    defaults        0      0

sysfs           /sys            sysfs   defaults        0      0

devpts          /dev/pts        devpts  gid=4,mode=620  0      0

tmpfs           /dev/shm        tmpfs   defaults        0      0

EOF

cat > ${MINILINUX}/etc/profile << "EOF"

export PATH=/bin:/usr/bin

if [ `id -u` -eq 0 ] ; then

        PATH=/bin:/sbin:/usr/bin:/usr/sbin

        unset HISTFILE

fi

# Set up some environment variables.

export USER=`id -un`

export LOGNAME=$USER

export HOSTNAME=`/bin/hostname`

export HISTSIZE=1000

export HISTFILESIZE=1000

export PAGER='/bin/more '

export EDITOR='/bin/vi'

EOF

echo "minilinux-test" > ${MINILINUX}/etc/HOSTNAME

cat > ${MINILINUX}/etc/issue<< "EOF"

MINI LINUX 0.1

Kernel \r on an \m

EOF

cat > ${MINILINUX}/etc/inittab<< "EOF"

::sysinit:/etc/rc.d/startup

tty1::respawn:/sbin/getty 38400 tty1

tty2::respawn:/sbin/getty 38400 tty2

tty3::respawn:/sbin/getty 38400 tty3

tty4::respawn:/sbin/getty 38400 tty4

tty5::respawn:/sbin/getty 38400 tty5

tty6::respawn:/sbin/getty 38400 tty6

::shutdown:/etc/rc.d/shutdown

::ctrlaltdel:/sbin/reboot

EOF

cat > ${MINILINUX}/etc/mdev.conf<< "EOF"

# Devices:

# Syntax: %s %d:%d %s

# devices user:group mode

# null does already exist; therefore ownership has to

# be changed with command

null    root:root 0666  @chmod 666 $MDEV

zero    root:root 0666

grsec   root:root 0660

full    root:root 0666

random  root:root 0666

urandom root:root 0444

hwrandom root:root 0660

# console does already exist; therefore ownership has to

# be changed with command

console root:tty 0600 @mkdir -pm 755 fd && cd fd && for x in 0 1 2 3 ; do ln -sf /proc/self/fd/$x $x; done

kmem    root:root 0640

mem     root:root 0640

port    root:root 0640

ptmx    root:tty 0666

# ram.*

ram([0-9]*)     root:disk 0660 >rd/%1

loop([0-9]+)    root:disk 0660 >loop/%1

sd[a-z].*       root:disk 0660 */lib/mdev/usbdisk_link

hd[a-z][0-9]*   root:disk 0660 */lib/mdev/ide_links

tty             root:tty 0666

tty[0-9]        root:root 0600

tty[0-9][0-9]   root:tty 0660

ttyO[0-9]*      root:tty 0660

pty.*           root:tty 0660

vcs[0-9]*       root:tty 0660

vcsa[0-9]*      root:tty 0660

ttyLTM[0-9]     root:dialout 0660 @ln -sf $MDEV modem

ttySHSF[0-9]    root:dialout 0660 @ln -sf $MDEV modem

slamr           root:dialout 0660 @ln -sf $MDEV slamr0

slusb           root:dialout 0660 @ln -sf $MDEV slusb0

fuse            root:root  0666

# misc stuff

agpgart         root:root 0660  >misc/

psaux           root:root 0660  >misc/

rtc             root:root 0664  >misc/

# input stuff

event[0-9]+     root:root 0640 =input/

ts[0-9]         root:root 0600 =input/

# v4l stuff

vbi[0-9]        root:video 0660 >v4l/

video[0-9]      root:video 0660 >v4l/

# load drivers for usb devices

usbdev[0-9].[0-9]       root:root 0660 */lib/mdev/usbdev

usbdev[0-9].[0-9]_.*    root:root 0660

EOF

cat > ${MINILINUX}/boot/grub/grub.cfg<< "EOF"

set default=0

set timeout=5

set root=(hd0,1)

menuentry "MINI LINUX" {

        linux /boot/vmlinuz-5.1.6 root=/dev/sda1 ro quiet

}

EOF

touch ${MINILINUX}/var/run/utmp ${MINILINUX}/var/log/{btmp,lastlog,wtmp}

chmod -v 664 ${MINILINUX}/var/run/utmp ${MINILINUX}/var/log/lastlog

2. 下载软件包

[ztg@localhost ~]$

cd ${MINILINUX}/usr/src

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/binutils/binutils-2.32.tar.xz

wget -c https://busybox.net/downloads/busybox-1.30.1.tar.bz2

wget -c http://ftp.clfs.org/pub/clfs/conglomeration/bootscripts-clfs-embedded/bootscripts-clfs-embedded-1.0-pre5.tar.bz2

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/gcc/gcc-9.1.0/gcc-9.1.0.tar.xz

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/glibc/glibc-2.29.tar.xz

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/gmp/gmp-6.1.2.tar.xz

wget -c https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.1.6.tar.xz

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/mpc/mpc-1.1.0.tar.gz

wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/mpfr/mpfr-4.0.2.tar.xz

wget -c http://www.zlib.net/zlib-1.2.11.tar.xz

cd -

3. 构建交叉编译器

unset CFLAGS

unset CXXFLAGS

export MINILINUX_HOST=$(echo ${MACHTYPE} | sed "s/-[^-]*/-cross/")

export MINILINUX_TARGET=x86_64-unknown-linux-gnu

export MINILINUX_CPU=k8

export MINILINUX_ARCH=$(echo ${MINILINUX_TARGET} | sed -e 's/-.*//' -e 's/i.86/i386/')

export MINILINUX_ENDIAN=little

4. 内核头文件

cd ${MINILINUX}/usr/src

tar xJvf linux-5.1.6.tar.xz

cd linux-5.1.6

make mrproper

make ARCH=${MINILINUX_ARCH} headers_check && make ARCH=${MINILINUX_ARCH} INSTALL_HDR_PATH=dest headers_install

cp -rv dest/include/* ${MINILINUX}/usr/include

5. 编译Binutils

cd ${MINILINUX}/usr/src

tar xJvf binutils-2.32.tar.xz

mkdir binutils-build

cd binutils-build

../binutils-2.32/configure --prefix=${MINILINUX}/cross-tools --target=${MINILINUX_TARGET} --with-sysroot=${MINILINUX} --disable-nls --enable-shared --disable-multilib

make configure-host && make

ln -sv lib ${MINILINUX}/cross-tools/lib64

make install

cp -v ../binutils-2.32/include/libiberty.h ${MINILINUX}/usr/include

6. 编译GCC (Static)

cd ${MINILINUX}/usr/src

tar xJvf gcc-9.1.0.tar.xz

tar xJvf gmp-6.1.2.tar.xz

mv gmp-6.1.2 gcc-9.1.0/gmp

tar xJvf mpfr-4.0.2.tar.xz

mv mpfr-4.0.2 gcc-9.1.0/mpfr

tar xzvf mpc-1.1.0.tar.gz

mv mpc-1.1.0 gcc-9.1.0/mpc

mkdir gcc-static

cd gcc-static

AR=ar LDFLAGS="-Wl,-rpath,${MINILINUX}/cross-tools/lib" \

../gcc-9.1.0/configure --prefix=${MINILINUX}/cross-tools \

--build=${MINILINUX_HOST} --host=${MINILINUX_HOST} \

--target=${MINILINUX_TARGET} \

--with-sysroot=${MINILINUX}/target --disable-nls \

--disable-shared \

--with-mpfr-include=$(pwd)/../gcc-9.1.0/mpfr/src \

--with-mpfr-lib=$(pwd)/mpfr/src/.libs \

--without-headers --with-newlib --disable-decimal-float \

--disable-libgomp --disable-libmudflap --disable-libssp \

--disable-threads --enable-languages=c,c++ \

--disable-multilib --with-arch=${MINILINUX_CPU}

make all-gcc all-target-libgcc && make install-gcc install-target-libgcc

ln -vs libgcc.a `${MINILINUX_TARGET}-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`

7. 编译Glibc

cd ${MINILINUX}/usr/src

tar xJvf glibc-2.29.tar.xz

mkdir glibc-build

cd glibc-build

echo "libc_cv_forced_unwind=yes" > config.cache

echo "libc_cv_c_cleanup=yes" >> config.cache

echo "libc_cv_ssp=no" >> config.cache

echo "libc_cv_ssp_strong=no" >> config.cache

BUILD_CC="gcc" CC="${MINILINUX_TARGET}-gcc" \

AR="${MINILINUX_TARGET}-ar" \

RANLIB="${MINILINUX_TARGET}-ranlib" CFLAGS="-O2" \

../glibc-2.29/configure --prefix=/usr \

--host=${MINILINUX_TARGET} --build=${MINILINUX_HOST} \

--disable-profile --enable-add-ons --with-tls \

--enable-kernel=2.6.32 --with-__thread \

--with-binutils=${MINILINUX}/cross-tools/bin \

--with-headers=${MINILINUX}/usr/include \

--cache-file=config.cache

make && make install_root=${MINILINUX}/ install

8. 编译GCC (Final)

cd ${MINILINUX}/usr/src

mkdir gcc-build

cd gcc-build

AR=ar LDFLAGS="-Wl,-rpath,${MINILINUX}/cross-tools/lib" \

../gcc-9.1.0/configure --prefix=${MINILINUX}/cross-tools \

--build=${MINILINUX_HOST} --target=${MINILINUX_TARGET} \

--host=${MINILINUX_HOST} --with-sysroot=${MINILINUX} \

--disable-nls --enable-shared \

--enable-languages=c,c++ --enable-c99 \

--enable-long-long \

--with-mpfr-include=$(pwd)/../gcc-9.1.0/mpfr/src \

--with-mpfr-lib=$(pwd)/mpfr/src/.libs \

--disable-multilib --with-arch=${MINILINUX_CPU}

make && make install

cp -v ${MINILINUX}/cross-tools/${MINILINUX_TARGET}/lib64/libgcc_s.so.1 ${MINILINUX}/lib64

export CC="${MINILINUX_TARGET}-gcc"

export CXX="${MINILINUX_TARGET}-g++"

export CPP="${MINILINUX_TARGET}-gcc -E"

export AR="${MINILINUX_TARGET}-ar"

export AS="${MINILINUX_TARGET}-as"

export LD="${MINILINUX_TARGET}-ld"

export RANLIB="${MINILINUX_TARGET}-ranlib"

export READELF="${MINILINUX_TARGET}-readelf"

export STRIP="${MINILINUX_TARGET}-strip"

9. 构建目标映像文件

9.1 构建BusyBox

cd ${MINILINUX}/usr/src

tar xjvf busybox-1.30.1.tar.bz2

cd busybox-1.30.1

make CROSS_COMPILE="${MINILINUX_TARGET}-" defconfig

// make CROSS_COMPILE="${MINILINUX_TARGET}-" menuconfig

make CROSS_COMPILE="${MINILINUX_TARGET}-"

make CROSS_COMPILE="${MINILINUX_TARGET}-" CONFIG_PREFIX="${MINILINUX}" install

cp -v examples/depmod.pl ${MINILINUX}/cross-tools/bin

chmod 755 ${MINILINUX}/cross-tools/bin/depmod.pl

9.2 构建Linux Kernel

cd ${MINILINUX}/usr/src

tar xJvf linux-5.1.6.tar.xz

cd linux-5.1.6

make ARCH=${MINILINUX_ARCH} CROSS_COMPILE=${MINILINUX_TARGET}- x86_64_defconfig

// make ARCH=${MINILINUX_ARCH} CROSS_COMPILE=${MINILINUX_TARGET}- menuconfig

make ARCH=${MINILINUX_ARCH} CROSS_COMPILE=${MINILINUX_TARGET}-

make ARCH=${MINILINUX_ARCH} \

CROSS_COMPILE=${MINILINUX_TARGET}- \

INSTALL_MOD_PATH=${MINILINUX} modules_install

cp -v arch/x86/boot/bzImage ${MINILINUX}/boot/vmlinuz-5.1.6

cp -v System.map ${MINILINUX}/boot/System.map-5.1.6

cp -v .config ${MINILINUX}/boot/config-5.1.6

${MINILINUX}/cross-tools/bin/depmod.pl \

-F ${MINILINUX}/boot/System.map-5.1.6 \

-b ${MINILINUX}/lib/modules/5.1.6

9.3 启动脚本

cd ${MINILINUX}/usr/src

tar xjvf bootscripts-clfs-embedded-1.0-pre5.tar.bz2

cd bootscripts-clfs-embedded-1.0-pre5

make DESTDIR=${MINILINUX}/ install-bootscripts

ln -sv ../rc.d/startup ${MINILINUX}/etc/init.d/rcS

9.4 构建Zlib

cd ${MINILINUX}/usr/src

tar xJvf zlib-1.2.11.tar.xz

cd zlib-1.2.11

sed -i 's/-O3/-Os/g' configure

./configure --prefix=/usr --shared

make && make DESTDIR=${MINILINUX}/ install

mv -v ${MINILINUX}/usr/lib/libz.so.* ${MINILINUX}/lib

ln -svf ../../lib/libz.so.1 ${MINILINUX}/usr/lib/libz.so

ln -svf ../../lib/libz.so.1 ${MINILINUX}/usr/lib/libz.so.1

ln -svf ../lib/libz.so.1 ${MINILINUX}/lib64/libz.so.1

10. 打包目标映像文件

[ztg@localhost ~]$ du -hs ${MINILINUX}

[ztg@localhost ~]$ du -hs minilinux

8.6G    minilinux/

[ztg@localhost ~]$

cd

cp -rf ${MINILINUX}/ ${MINILINUX}-copy

rm -rfv ${MINILINUX}-copy/cross-tools

rm -rfv ${MINILINUX}-copy/usr/src/*

FILES="$(ls ${MINILINUX}-copy/usr/lib64/*.a)"

for file in $FILES; do

rm -f $file

done

find ${MINILINUX}-copy/{,usr/}{bin,lib,sbin} -type f -exec sudo strip --strip-debug '{}' ';'

find ${MINILINUX}-copy/{,usr/}lib64 -type f -exec sudo strip --strip-debug '{}' ';'

sudo chown -R root:root ${MINILINUX}-copy

sudo chgrp 13 ${MINILINUX}-copy/var/run/utmp ${MINILINUX}-copy/var/log/lastlog

sudo mknod -m 0666 ${MINILINUX}-copy/dev/null c 1 3

sudo mknod -m 0600 ${MINILINUX}-copy/dev/console c 5 1

sudo chmod 4755 ${MINILINUX}-copy/bin/busybox

cd ${MINILINUX}-copy

sudo tar cJvf ../minilinux-build-20190604.tar.xz *

11. 安装目标映像文件

11.1  创建磁盘映像文件

[root@localhost minilinux]# pwd

/mnt/iso/minilinux

[root@localhost minilinux]# dd if=/dev/zero of=minilinux_disk2.img bs=1M count=128

11.2  对磁盘分区

[root@localhost minilinux]# fdisk minilinux_disk2.img

命令(输入 m 获取帮助):n

分区类型

   p   主分区 (0个主分区,0个扩展分区,4空闲)

   e   扩展分区 (逻辑分区容器)

选择 (默认 p):p

分区号 (1-4, 默认  1): 1

第一个扇区 (2048-262143, 默认 2048):

Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-262143, 默认 262143):

创建了一个新分区 1,类型为“Linux”,大小为 127 MiB。

命令(输入 m 获取帮助):w

分区表已调整。

正在同步磁盘。

[root@localhost minilinux]#

11.3  关联磁盘分区

[root@localhost minilinux]# fdisk -l minilinux_disk2.img

Disk minilinux_disk2.img:128 MiB,134217728 字节,262144 个扇区

单元:扇区 / 1 * 512 = 512 字节

扇区大小(逻辑/物理):512 字节 / 512 字节

I/O 大小(最小/最佳):512 字节 / 512 字节

磁盘标签类型:dos

磁盘标识符:0x0d27477d

设备                启动  起点   末尾   扇区  大小 Id 类型

minilinux_disk2.img1       2048 262143 260096  127M 83 Linux

[root@localhost minilinux]# losetup -o 1048576 /dev/loop0 minilinux_disk2.img

11.4  格式化分区和挂载分区

[root@localhost minilinux]# mkfs.ext4 /dev/loop0

[root@localhost minilinux]# mkdir /mnt/minilinux2

[root@localhost minilinux]# mount -t ext4 /dev/loop0 /mnt/minilinux2

11.5  复制目标映像文件

[root@localhost minilinux]# tar xJvf /home/ztg/minilinux-build-20190604.tar.xz -C /mnt/minilinux2

11.6  安装grub2

[root@localhost minilinux]# grub2-install --boot-directory=/mnt/minilinux2/boot/ --target=i386-pc --modules=part_msdos minilinux_disk2.img

cat > /mnt/minilinux2/boot/grub2/grub.cfg<< "EOF"

set default=0

set timeout=5

set root=(hd0,1)

menuentry "MINI LINUX" {

        linux /boot/vmlinuz-5.1.6 root=/dev/sda1 ro quiet

}

EOF

[root@localhost minilinux]#

umount /mnt/minilinux2

umount /dev/loop0

losetup -d /dev/loop0

12. VirtualBox 中运行 linux

[root@localhost minilinux]# cd /mnt/iso/minilinux/

[root@localhost minilinux]# ls

initrd.img  minilinux_disk2.img  minilinux_disk2.raw  minilinux_disk2.vdi  minilinux_disk.img  minilinux_disk.raw  minilinux_disk.vdi

[root@localhost minilinux]#

qemu-img convert minilinux_disk2.img -O raw minilinux_disk2.raw

VBoxManage convertdd minilinux_disk2.raw minilinux_disk2.vdi

(OK) 自己动手构建Linux发行版---简版_ide

(OK) 自己动手构建Linux发行版---简版_linux_02