在centOS7.3下编译、裁剪内核
1.安装虚拟机,增加一块20G的SCCI用来存编译的中间文件和需要安装的软件包,增加一块10G的SATA硬盘用来安装最终的linux系统(最后作为虚拟机的第一启动项)
2.安装软件包(为了解决编译过程中的软件依赖)
yum install bison flex ncurses* elfutils-devel openssl* bc -y
- 格式化第2块20G的硬盘,并挂载
[root@localhost ~]# fdisk /dev/sdb #sda sdb sdc sdb为我另加的一块20G的磁盘,用作装编译过程中的软件和中间文件
欢迎使用 fdisk (util-linux 2.32.1)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。
设备不包含可识别的分区表。
创建了一个磁盘标识符为 0x5d5fd771 的新 DOS 磁盘标签。
命令(输入 m 获取帮助):p
Disk /dev/sdb:20 GiB,21474836480 字节,41943040 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x5d5fd771
命令(输入 m 获取帮助):n
分区类型
p 主分区 (0个主分区,0个扩展分区,4空闲)
e 扩展分区 (逻辑分区容器)
选择 (默认 p):
将使用默认回应 p。
分区号 (1-4, 默认 1):
第一个扇区 (2048-41943039, 默认 2048):
上个扇区,+sectors 或 +size{K,M,G,T,P} (2048-41943039, 默认 41943039):
创建了一个新分区 1,类型为“Linux”,大小为 20 GiB。
命令(输入 m 获取帮助):w
分区表已调整。
将调用 ioctl() 来重新读分区表。
正在同步磁盘。
[root@localhost ~]# partprobe #发现分区
[root@localhost ~]# mkfs.xfs -f /dev/sdb1 #重新格式化
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=1310656 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1
data = bsize=4096 blocks=5242624, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
[root@localhost ~]# mkdir -pv /diy/ #创建被挂载的目录
[root@localhost ~]# mount /dev/sdb1 /diy/ #将这块硬盘挂载到该目录下
4.准备相关的软件包
wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/binutils/binutils-2.30.tar.xz
wget -c http://ftp.clfs.org/pub/clfs/conglomeration/bootscripts-clfs-embedded/bootscripts-clfs-embedded-1.0-pre5.tar.bz2
wget -c https://busybox.net/downloads/busybox-1.28.3.tar.bz2
wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.xz
wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/glibc/glibc-2.27.tar.xz
wget -c https://mirror.tuna.tsinghua.edu.cn/gnu/gmp/gmp-6.1.2.tar.bz2
wget -c https://mirror.bjtu.edu.cn/kernel/linux/kernel/v4.x/linux-4.16.3.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.1.tar.xz
wget -c http://www.zlib.net/zlib-1.2.11.tar.gz
4.配置编译前的shell环境
[root@localhost diy]# set +h
[root@localhost diy]# umask 022 #创建文件默认的掩码
[root@localhost diy]# export LJOS=/diy/os
[root@localhost diy]# mkdir -pv ${LJOS}
mkdir: 已创建目录 '/diy/os'
[root@localhost diy]# export LC_ALL=POSIX #导出相应的环境变量
[root@localhost diy]# export PATH=${LJOS}/cross-tools/bin:/bin/:/usr/bin #指定现在使用的命令只能在这些里面找
5.创建构建linux的根目录结构
[root@localhost diy]#
mkdir -pv ${LJOS}/{bin,boot{,grub},dev,{etc/,}opt,home,lib/{firmware,modules},lib64,mnt}
mkdir -pv ${LJOS}/{proc,media/{floppy,cdrom},sbin,srv,sys}
mkdir -pv ${LJOS}/var/{lock,log,mail,run,spool}
mkdir -pv ${LJOS}/var/{opt,cache,lib/{misc,locate},local}
install -dv -m 0750 ${LJOS}/root
install -dv -m 1777 ${LJOS}{/var,}/tmp
install -dv ${LJOS}/etc/init.d
mkdir -pv ${LJOS}/usr/{,local/}{bin,include,lib{,64},sbin,src}
mkdir -pv ${LJOS}/usr/{,local/}share/{doc,info,locale,man}
mkdir -pv ${LJOS}/usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv ${LJOS}/usr/{,local/}share/man/man{1,2,3,4,5,6,7,8}
for dir in ${LJOS}/usr{,/local}; do
ln -sv share/{man,doc,info} ${dir}
done
6.创建交叉编译工具的目录
[root@localhost diy]#
install -dv ${LJOS}/cross-tools{,/bin}
7.使用目标系统的/proc/ mounts的符号链接来维护目标系统的/etc/mtab文件中正确挂载的文件系统列表
[root@localhost diy]#
ln -svf ../proc/mounts ${LJOS}/etc/mtab
8.创建目标系统的/etc/passwd文件(目标系统的用户信息)
cat > ${LJOS}/etc/passwd << "EOF"
root::0:0:root:/root:/bin/ash
EOF
9.创建目标系统的/etc/group文件(用户组信息)
cat > ${LJOS}/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
10.创建目标系统的/etc/fstab ;(启动时需要挂载的文件系统的信息)
cat > ${LJOS}/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
11.创建目标系统的/etc/profile(保存了登录系统时需要配置的shell)
cat > ${LJOS}/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
12.设置目标系统的主机名(这个以后也可以修改)
echo "diy-test" > ${LJOS}/etc/HOSTNAME
13.设置目标系统登录时显示的标识,
cat > ${LJOS}/etc/issue<< "EOF"
LINUX DIY OS 0.1a
Kernel \r on an \m
EOF
14.设置目标系统的/etc/inittab (使用init而不是systemd)(系统启动过程的启动级别 波特率)
cat > ${LJOS}/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
15.设置目标系统的/etc/mdev (用于加载驱动后,热插拔设备后,在目标系统的/dev下创建、删除设备文件)
cat > ${LJOS}/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
16.为目标机的grub2 bootloarder创建/boot/grub2/grub.cfg
mkdir -pv ${LJOS}/boot/grub2
cat > ${LJOS}/boot/grub2/grub.cfg<< "EOF"
set default=0
set timeout=5
set root=(hd0,1)
menuentry "LINUX DIY OS 0.1a" {
linux /boot/vmlinuz-4.16.3 root=/dev/sda1 ro quiet
}
EOF
17.初始化目标机的日志文件并给它们适当的权限
touch ${LJOS}/var/run/utmp ${LJOS}/var/log/{btmp,lastlog,wtmp}
chmod -v 664 ${LJOS}/var/run/utmp ${LJOS}/var/log/lastlog
18.交叉编译器相关预处理
unset CFLAGS
unset CXXFLAGS #删除当前shell的环境变量
export LJOS_HOST=$(echo ${MACHTYPE} | sed "s/-[^-]*/-cross/")#交叉编译工具链所需要的环境变量
export LJOS_TARGET=x86_64-unknown-linux-gnu
export LJOS_CPU=k8
export LJOS_ARCH=$(echo ${LJOS_TARGET} | sed -e 's/-.*//' -e 's/i.86/i386/') #所使用的架构
export LJOS_ENDIAN=little
19.内核头文件预处理
[root@localhost diy]#
tar xvf linux-4.16.3.tar.xz
cd linux-4.16.3/
make mrproper #删除以往的配置以及中间文件
make ARCH=${LJOS_ARCH} headers_check && make ARCH=${LJOS_ARCH} INSTALL_HDR_PATH=dest headers_install
#将内核头文件安装到我们的目标目录
cp -rv dest/include/* ${LJOS}/usr/include
- Binutils预处理(在编译过程中所使用的一些编译工具)
[root@localhost diy]#
tar xvf binutils-2.30.tar.xz
mkdir binutils-build
cd binutils-build/
#配置binutils
../binutils-2.30/configure --prefix=${LJOS}/cross-tools --target=${LJOS_TARGET} --with-sysroot=${LJOS} --disable-nls --enable-shared --disable-multilib
#编译(采用四线程)
make configure-host && make -j4
ln -sv lib ${LJOS}/cross-tools/lib64
make install
cp -v ../binutils-2.30/include/libiberty.h ${LJOS}/usr/include
21.静态编译gcc
[root@localhost diy]#
tar xvf gcc-7.3.0.tar.xz
tar xvf gmp-6.1.2.tar.bz2
mv gmp-6.1.2 gcc-7.3.0/gmp
tar xvf mpfr-4.0.1.tar.xz
mv mpfr-4.0.1 gcc-7.3.0/mpfr
tar xvf mpc-1.1.0.tar.gz
mv mpc-1.1.0 gcc-7.3.0/mpc
mkdir gcc-static
cd gcc-static
#配置gcc的一些参数
AR=ar LDFLAGS="-Wl,-rpath,${LJOS}/cross-tools/lib" \
../gcc-7.3.0/configure --prefix=${LJOS}/cross-tools \
--build=${LJOS_HOST} --host=${LJOS_HOST} \
--target=${LJOS_TARGET} \
--with-sysroot=${LJOS}/target --disable-nls \
--disable-shared \
--with-mpfr-include=$(pwd)/../gcc-7.3.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=${LJOS_CPU}
#开始编译静态版的gcc文件
make all-gcc all-target-libgcc -j4 && make install-gcc install-target-libgcc -j4
#如果编译时间不够五分钟请查看gcc 和 c++ --version
ln -vs libgcc.a `${LJOS_TARGET}-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`
22.编译目标机的glibc库
[root@localhost diy]#
tar xvf glibc-2.27.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
#glic的编译配置
BUILD_CC="gcc" CC="${LJOS_TARGET}-gcc" \
AR="${LJOS_TARGET}-ar" \
RANLIB="${LJOS_TARGET}-ranlib" CFLAGS="-O2" \
../glibc-2.27/configure --prefix=/usr \
--host=${LJOS_TARGET} --build=${LJOS_HOST} \
--disable-profile --enable-add-ons --with-tls \
--enable-kernel=2.6.32 --with-__thread \
--with-binutils=${LJOS}/cross-tools/bin \
--with-headers=${LJOS}/usr/include \
--cache-file=config.cache
#编译glibc库
make -j4 && make install_root=${LJOS}/ install
23.动态编译最终的gcc
[root@localhost diy]#
mkdir gcc-build
cd gcc-build
AR=ar LDFLAGS="-Wl,-rpath,${LJOS}/cross-tools/lib" \
../gcc-7.3.0/configure --prefix=${LJOS}/cross-tools \
--build=${LJOS_HOST} --target=${LJOS_TARGET} \
--host=${LJOS_HOST} --with-sysroot=${LJOS} \
--disable-nls --enable-shared \
--enable-languages=c,c++ --enable-c99 \
--enable-long-long \
--with-mpfr-include=$(pwd)/../gcc-7.3.0/mpfr/src \
--with-mpfr-lib=$(pwd)/mpfr/src/.libs \
--disable-multilib --with-arch=${LJOS_CPU}
make -j4 && make install
--------------------------------------------------------------------------------------
cp -v ${LJOS}/cross-tools/${LJOS_TARGET}/lib64/libgcc_s.so.1 ${LJOS}/lib64
24.修改新的shell环境变量
把和编译相关的环境变量全部都换成刚才创建的交叉编译工具链
[root@localhost diy]#
export CC="${LJOS_TARGET}-gcc"
export CXX="${LJOS_TARGET}-g++"
export CPP="${LJOS_TARGET}-gcc -E"
export AR="${LJOS_TARGET}-ar"
export AS="${LJOS_TARGET}-as"
export LD="${LJOS_TARGET}-ld"
export RANLIB="${LJOS_TARGET}-ranlib"
export READELF="${LJOS_TARGET}-readelf"
export STRIP="${LJOS_TARGET}-strip"
下面的操作为编译DIYlinux系统所需要的软件
25.编译目标机busybox
[root@localhost diy]#
tar xvf busybox-1.28.3.tar.bz2
cd busybox-1.28.3
#采用默认配置
make CROSS_COMPILE="${LJOS_TARGET}-" defconfig
#对busybox进行编译
make CROSS_COMPILE="${LJOS_TARGET}-" -j4
#将编译出的命令安装到目标系统的文件夹
make CROSS_COMPILE="${LJOS_TARGET}-" CONFIG_PREFIX="${LJOS}" install
#把busybox提供的一个脚本拷贝到交叉编译工具链的目录中
#这个脚本用作选择系统需要的模块
cp -v examples/depmod.pl ${LJOS}/cross-tools/bin
chmod 755 ${LJOS}/cross-tools/bin/depmod.pl
26.编译linux内核
[root@localhost diy]#
#重新进入内核目录进行内核编译
cd ../linux-4.16.3
#使用内核默认的配置
make ARCH=${LJOS_ARCH} CROSS_COMPILE=${LJOS_TARGET}- x86_64_defconfig
#对内核进行编译
make ARCH=${LJOS_ARCH} CROSS_COMPILE=${LJOS_TARGET}- -j4
#把内核相关的驱动模块安装在目标目录
make ARCH=${LJOS_ARCH} \
CROSS_COMPILE=${LJOS_TARGET}- \
INSTALL_MOD_PATH=${LJOS} modules_install
#把内核拷贝到目标目录
cp -v arch/x86/boot/bzImage ${LJOS}/boot/vmlinuz-4.16.3
#把内核所需要的印象信息也拷贝到目标目录
cp -v System.map ${LJOS}/boot/System.map-4.16.3
#把内核所需要的配置拷贝到目标目录
cp -v .config ${LJOS}/boot/config-4.16.3
#执行busybox提供的相关脚本就可以知道系统相关模块的信息
${LJOS}/cross-tools/bin/depmod.pl \
-F ${LJOS}/boot/System.map-4.16.3 \
-b ${LJOS}/lib/modules/4.16.3
27安装启动脚本bootscripts
#从内核到启动之间的启动脚本
[root@localhost diy]#
tar xjvf bootscripts-clfs-embedded-1.0-pre5.tar.bz2
cd bootscripts-clfs-embedded-1.0-pre5
vim Makefile
修改makefile的第22行
修改前:
install -d -m ${DIRMODE}/rc.d/{init.d,start,stop}
修改后:
install -d -m ${DIRMODE} ${EXTDIR}/rc.d/init.d
install -d -m ${DIRMODE} ${EXTDIR}/rc.d/start
install -d -m ${DIRMODE} ${EXTDIR}/rc.d/stop
#将启动脚本安装到目标目录
make DESTDIR=${LJOS}/ install-bootscripts
ln -sv ../rc.d/startup ${LJOS}/etc/init.d/rcS
28.制作目标镜像的压缩包
#先对我们的系统进行备份
cp -rf ${LJOS}/ ${LJOS}-copy
#交叉编译工具链和静态编译的库是不需要的
rm -rfv ${LJOS}-copy/cross-tools
#删除内核相关的源代码
rm -rfv ${LJOS}-copy/usr/src/*
#删除运行环境上所有的静态库
FILES="$(ls ${LJOS}-copy/usr/lib64/*.a)"
for file in $FILES; do
rm -f $file
done
#将我们新拷贝的这个系统全部换为root用户和root组
chown -R root:root ${LJOS}-copy
#修改日志文件的组id
chgrp 13 ${LJOS}-copy/var/run/utmp ${LJOS}-copy/var/log/lastlog
#在新建的系统下面创建垃圾桶和控制台
mknod -m 0666 ${LJOS}-copy/dev/null c 1 3
mknod -m 0600 ${LJOS}-copy/dev/console c 5 1
#修改busybox的执行权限
chmod 4755 ${LJOS}-copy/bin/busybox
cd ${LJOS}-copy
#将整个目录进行打包压缩
tar cJf ../diy-build.tar.xz *
29.设置目标硬盘(10GB的sata硬盘划分分区,就划分1个分区)划分分区
[root@localhost ~]#
fdisk /dev/sdc
#发现分区
partprobe
#强制格式化为ext4
mkfs.ext4 /dev/sdc1
#把这个硬盘挂载出来
mkdir -pv /newdisk
mount /dev/sdc1 /newdisk
#把我们的压缩包解压到这个盘中
cd /newdisk/
[root@localhost newdisk]#
tar xJf /diy/diy-build.tar.xz
#在我们的sata盘里面装一个bootloader工具
#新建一个终端
grub2-install --root-directory=/newdisk /dev/sdc
#至此就已经安装好了系统
#接下来我们重启系统