文章目录
前言
linux操作系统除了需要内核以外,还需要各种基础软件辅助,才能正常运行,而基础软件是由文件系统存储并管理的,本章将展示一个最简嵌入式linux发行版需要的基础软件包的构建过程。
一、文件系统框架
拓展知识: 文件系统层级标准FHS
mkdir -pv ${CLFS}/targetfs/{bin,boot,dev,etc,home,lib/{firmware,modules}}
mkdir -pv ${CLFS}/targetfs/{mnt,opt,proc,sbin,srv,sys}
mkdir -pv ${CLFS}/targetfs/var/{cache,lib,local,lock,log,opt,run,spool}
install -dv -m 0750 ${CLFS}/targetfs/root
install -dv -m 1777 ${CLFS}/targetfs/{var/,}tmp
mkdir -pv ${CLFS}/targetfs/usr/{,local/}{bin,include,lib,sbin,share,src}
二、系统权限配置
ln -svf ../proc/mounts ${CLFS}/targetfs/etc/mtab
cat > ${CLFS}/targetfs/etc/passwd << "EOF"
root::0:0:root:/root:/bin/ash
EOF
cat > ${CLFS}/targetfs/etc/group << "EOF"
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
tape:x:5:
daemon:x:6:
floppy:x:7:
disk:x:8:
lp:x:9:
dialout:x:10:
audio:x:11:
video:x:12:
utmp:x:13:
usb:x:14:
cdrom:x:15:
adm:x:16:root,adm,daemon
console:x:17:
cdrw:x:18:
mail:x:30:mail
news:x:31:news
uucp:x:32:uucp
users:x:100:
nogroup:x:65533:
nobody:x:65534:
EOF
touch ${CLFS}/targetfs/var/log/lastlog
chmod -v 664 ${CLFS}/targetfs/var/log/lastlog
三、编译libgcc
cp -v ${CLFS}/cross-tools/${CLFS_TARGET}/lib/libgcc_s.so.1 ${CLFS}/targetfs/lib/
# ${CLFS_TARGET}-strip ${CLFS}/targetfs/lib/libgcc_s.so.1
mkdir -pv ${CLFS}/build/musl-libgcc
pushd ${CLFS}/build/musl-libgcc
${CLFS}/sources/musl-1.1.16/configure \
CROSS_COMPILE=${CLFS_TARGET}- \
--prefix=/ \
--disable-static \
--target=${CLFS_TARGET}
make -j `nproc`
DESTDIR=${CLFS}/targetfs make install-libs -j `nproc`
popd
四、编译busybox
tar -xf ${CLFS}/archive/busybox-1.24.2.tar.bz2 -C ${CLFS}/sources
mkdir -pv ${CLFS}/build/busybox
pushd ${CLFS}/sources/busybox-1.24.2
make ARCH="${CLFS_ARCH}" O="${CLFS}/build/busybox" defconfig
sed -i 's/\(CONFIG_\)\(.*\)\(INETD\)\(.*\)=y/# \1\2\3\4 is not set/g' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_IFPLUGD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_FEATURE_WTMP\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_FEATURE_UTMP\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_UDPSVD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
sed -i 's/\(CONFIG_TCPSVD\)=y/# \1 is not set/' ${CLFS}/build/busybox/.config
make ARCH="${CLFS_ARCH}" CROSS_COMPILE="${CLFS_TARGET}-" O="${CLFS}/build/busybox" -j `nproc`
make ARCH="${CLFS_ARCH}" CROSS_COMPILE="${CLFS_TARGET}-"\
CONFIG_PREFIX="${CLFS}/targetfs" O="${CLFS}/build/busybox" install -j `nproc`
cp -v examples/depmod.pl ${CLFS}/cross-tools/bin
chmod -v 755 ${CLFS}/cross-tools/bin/depmod.pl
popd
五、iana配置
tar -xf ${CLFS}/archive/iana-etc-2.30.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/iana-etc-2.30
patch -Np1 -i ${CLFS}/archive/iana-etc-2.30-update-2.patch
cat > iana.patch << EOF
--- old/get.gawk 2024-05-19 12:58:37.570720304 +0800
+++ new/get.gawk 2024-05-19 12:58:21.170724431 +0800
@@ -14,9 +14,10 @@
path = "/assignments/"
# file is set by the caller
socket = "/inet/tcp/0/" host "/80"
+ agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"
- print "Getting http://" host path file >"/dev/stderr"
- printf "GET %s%s HTTP/1.0\r\nHost: %s\r\n\r\n", path, file, host |& socket
+ print "Getting https://" host path file >"/dev/stderr"
+ printf "GET %s%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n", path, file, host, agent |& socket
printf "Request sent, waiting for data... " >"/dev/stderr"
NR = 0
EOF
patch -Np1 -i iana.patch
popd
cp -rfv ${CLFS}/sources/iana-etc-2.30 ${CLFS}/build/iana-etc
pushd ${CLFS}/build/iana-etc
make get
make STRIP=yes
make DESTDIR=${CLFS}/targetfs install
popd
六、文件系统挂载配置
cat > ${CLFS}/targetfs/etc/fstab << "EOF"
# file-system mount-point type options dump fsck
EOF
七、编译linux内核
mkdir -pv ${CLFS}/build/linux
pushd ${CLFS}/sources/linux-4.9.22
# 解决yylloc多重定义问题
sed -i "305a\HOSTCFLAGS += -fcommon" Makefile
make mrproper
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" defconfig
# 添加initramfs支持
sed -i "s/# CONFIG_BLK_DEV_RAM is not set/CONFIG_BLK_DEV_RAM=y/g" ${CLFS}/build/linux/.config
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" olddefconfig
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- O="${CLFS}/build/linux" Image modules -j `nproc`
make ARCH=${CLFS_ARCH} CROSS_COMPILE=${CLFS_TARGET}- \
INSTALL_MOD_PATH=${CLFS}/targetfs O="${CLFS}/build/linux" modules_install -j `nproc`
install ${CLFS}/build/linux/vmlinux ${CLFS}/build
install ${CLFS}/build/linux/arch/arm64/boot/Image ${CLFS}/build
popd
八、启动脚本配置
tar -xf ${CLFS}/archive/master.tar.gz -C ${CLFS}/sources
pushd ${CLFS}/sources/bootscripts-embedded-master
make DESTDIR=${CLFS}/targetfs install-bootscripts
popd
九、设备识别规则配置
cat > ${CLFS}/targetfs/etc/mdev.conf<< "EOF"
# /etc/mdev/conf
# 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 @chmod 600 $MDEV && mkdir -p vc && ln -sf ../$MDEV vc/0
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
fd0 root:floppy 0660
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
md[0-9] root:disk 0660
tty root:tty 0666
tty[0-9] root:root 0600
tty[0-9][0-9] root:tty 0660
ttyS[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
# dri device
card[0-9] root:video 0660 =dri/
# alsa sound devices and audio stuff
pcm.* root:audio 0660 =snd/
control.* root:audio 0660 =snd/
midi.* root:audio 0660 =snd/
seq root:audio 0660 =snd/
timer root:audio 0660 =snd/
adsp root:audio 0660 >sound/
audio root:audio 0660 >sound/
dsp root:audio 0660 >sound/
mixer root:audio 0660 >sound/
sequencer.* root:audio 0660 >sound/
# 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/
mice root:root 0640 =input/
mouse[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/
# dvb stuff
dvb.* root:video 0660 */lib/mdev/dvbdev
# load drivers for usb devices
usbdev[0-9].[0-9] root:root 0660 */lib/mdev/usbdev
usbdev[0-9].[0-9]_.* root:root 0660
# net devices
tun[0-9]* root:root 0600 =net/
tap[0-9]* root:root 0600 =net/
# zaptel devices
zap(.*) root:dialout 0660 =zap/%1
dahdi!(.*) root:dialout 0660 =dahdi/%1
# raid controllers
cciss!(.*) root:disk 0660 =cciss/%1
ida!(.*) root:disk 0660 =ida/%1
rd!(.*) root:disk 0660 =rd/%1
sr[0-9] root:cdrom 0660 @ln -sf $MDEV cdrom
# hpilo
hpilo!(.*) root:root 0660 =hpilo/%1
# xen stuff
xvd[a-z] root:root 0660 */lib/mdev/xvd_links
EOF
十、bash环境配置
cat > ${CLFS}/targetfs/etc/profile << "EOF"
# /etc/profile
# Set the initial path
export PATH=/bin:/usr/bin
if [ `id -u` -eq 0 ] ; then
PATH=/bin:/sbin:/usr/bin:/usr/sbin
unset HISTFILE
fi
# Setup 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'
# End /etc/profile
EOF
十一、init脚本配置
cat > ${CLFS}/targetfs/etc/inittab<< "EOF"
# /etc/inittab
::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
# Put a getty on the serial line (for a terminal). Uncomment this line if
# you're using a serial console on ttyAMA0, or uncomment and adjust it if using a
# serial console on a different serial port such as ttyS0.
::respawn:/sbin/getty -L ttyAMA0 115200 vt100
::shutdown:/etc/rc.d/shutdown
::ctrlaltdel:/sbin/reboot
EOF
十二、主机名配置
echo "[clfs]" > ${CLFS}/targetfs/etc/HOSTNAME
十三、hosts配置
cat > ${CLFS}/targetfs/etc/hosts << "EOF"
# Begin /etc/hosts (network card version)
127.0.0.1 localhost
# [192.168.1.1] [<HOSTNAME>.example.org] [HOSTNAME]
# End /etc/hosts (network card version)
EOF
十四、网络配置
mkdir -pv ${CLFS}/targetfs/etc/network/if-{post-{up,down},pre-{up,down},up,down}.d
mkdir -pv ${CLFS}/targetfs/usr/share/udhcpc
cat > ${CLFS}/targetfs/etc/network/interfaces << "EOF"
auto eth0
iface eth0 inet dhcp
EOF
cat > ${CLFS}/targetfs/usr/share/udhcpc/default.script << "EOF"
#!/bin/sh
# udhcpc Interface Configuration
# Based on http://lists.debian.org/debian-boot/2002/11/msg00500.html
# udhcpc script edited by Tim Riker <Tim@Rikers.org>
[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
RESOLV_CONF="/etc/resolv.conf"
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"
case "$1" in
deconfig)
/sbin/ifconfig $interface 0.0.0.0
;;
renew|bound)
/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
if [ -n "$router" ] ; then
while route del default gw 0.0.0.0 dev $interface ; do
true
done
for i in $router ; do
route add default gw $i dev $interface
done
fi
echo -n > $RESOLV_CONF
[ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
for i in $dns ; do
echo nameserver $i >> $RESOLV_CONF
done
;;
esac
exit 0
EOF
chmod +x ${CLFS}/targetfs/usr/share/udhcpc/default.script
十五、编译zlib
tar -xf ${CLFS}/archive/zlib-1.2.8.tar.gz -C ${CLFS}/sources
cp -rvf ${CLFS}/sources/zlib-1.2.8 ${CLFS}/build/zlib
pushd ${CLFS}/build/zlib
CFLAGS="-Os" ./configure --shared
make -j `nproc`
make prefix=${CLFS}/cross-tools/${CLFS_TARGET} install -j `nproc`
cp -v ${CLFS}/cross-tools/${CLFS_TARGET}/lib/libz.so.1.2.8 ${CLFS}/targetfs/lib/
ln -sv libz.so.1.2.8 ${CLFS}/targetfs/lib/libz.so.1
popd
十六、编译netplug
tar -xf ${CLFS}/archive/netplug-1.2.9.2.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/netplug-1.2.9.2
patch -Np1 -i ${CLFS}/archive/netplug-1.2.9.2-fixes-1.patch
cat > not_support_hg.patch << EOF
--- old/Makefile 2024-05-19 14:11:38.039630691 +0800
+++ new/Makefile 2024-05-19 14:16:44.249553189 +0800
@@ -30,19 +30,5 @@
install $(install_opts) -m 755 scripts/rc.netplugd $(DESTDIR)/$(initdir)/netplugd
install $(install_opts) -m 444 man/man8/netplugd.8 $(DESTDIR)/$(mandir)/man8
-hg_root := $(shell hg root)
-tar_root := netplug-$(version)
-tar_file := $(hg_root)/$(tar_root).tar.bz2
-files := $(shell hg manifest)
-
-tarball: $(tar_file)
-
-$(tar_file): $(files)
- mkdir -p $(hg_root)/$(tar_root)
- echo $(files) | tr ' ' '\n' | \
- xargs -i cp -a --parents {} $(hg_root)/$(tar_root)
- tar -C $(hg_root) -c -f - $(tar_root) | bzip2 -9 > $(tar_file)
- rm -rf $(hg_root)/$(tar_root)
-
clean:
-rm -f netplugd *.o *.tar.bz2
EOF
patch -Np1 -i not_support_hg.patch
popd
cp -rvf ${CLFS}/sources/netplug-1.2.9.2 ${CLFS}/build/netplug
pushd ${CLFS}/build/netplug
make -j `nproc`
make DESTDIR=${CLFS}/targetfs install -j `nproc`
popd
pushd ${CLFS}/sources/bootscripts-embedded-master
make install-netplug DESTDIR=${CLFS}/targetfs
popd
十七、编译dropbear
tar -xf ${CLFS}/archive/dropbear-2013.60.tar.bz2 -C ${CLFS}/sources
pushd ${CLFS}/sources/dropbear-2013.60
sed -i 's/.*mandir.*//g' Makefile.in
popd
mkdir -pv ${CLFS}/build/dropbear
pushd ${CLFS}/build/dropbear
CC="${CC} -Os" ${CLFS}/sources/dropbear-2013.60/configure --prefix=/usr --host=${CLFS_TARGET}
make MULTI=1 \
PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" -j `nproc`
make MULTI=1 \
PROGRAMS="dropbear dbclient dropbearkey dropbearconvert scp" \
install DESTDIR=${CLFS}/targetfs -j `nproc`
install -dv ${CLFS}/targetfs/etc/dropbear
popd
pushd ${CLFS}/sources/bootscripts-embedded-master
make install-dropbear DESTDIR=${CLFS}/targetfs
popd
十八、编译wireless tools
tar -xf ${CLFS}/archive/wireless_tools.29.tar.gz -C ${CLFS}/sources
pushd ${CLFS}/sources/wireless_tools.29
sed -i s/gcc/\$\{CLFS\_TARGET\}\-gcc/g Makefile
sed -i s/\ ar/\ \$\{CLFS\_TARGET\}\-ar/g Makefile
sed -i s/ranlib/\$\{CLFS\_TARGET\}\-ranlib/g Makefile
popd
cp -rvf ${CLFS}/sources/wireless_tools.29 ${CLFS}/build/wireless_tools
pushd ${CLFS}/build/wireless_tools
make PREFIX=${CLFS}/targetfs/usr -j `nproc`
make install PREFIX=${CLFS}/targetfs/usr -j `nproc`
echo "include /usr/lib/" >> ${CLFS}/targetfs/etc/ld.so.conf
popd
十九、修改目标文件系统权限并打包
以root权限执行以下命令
扩展知识: ramfs、rootfs、initramfs的差别
export CLFS=/opt/clfs
chown -Rv root:root ${CLFS}/targetfs
chgrp -v 13 ${CLFS}/targetfs/var/log/lastlog
pushd ${CLFS}/targetfs
# 让initrd识别为initramfs
cp -rf linuxrc init
tar jcfv ${CLFS}/build/clfs-embedded.tar.bz2 *
find . | cpio -H newc -o | gzip -9 > ${CLFS}/build/initramfs.cpio.gz
popd
总结
本章对linux内核和基础系统工具进行编译集成,最终生成了一个用于操作系统启动的文件系统。