download: https://github.com/Jvlegod/lfs-from-riscv/releases/
1 环境搭建 全程建议给执行的用户目标权限. 这样后面就尽量别用 sudo, 容易出错.
1 sudo chown -R lfs:lfs $LFS /tools $LFS /sources $LFS /usr $LFS
如果没有创建该用户.
1 2 3 4 5 6 sudo groupadd lfssudo useradd -s /bin/bash -g lfs -m -k /dev/null lfssudo passwd lfs
后期恢复权限.
1 2 3 sudo chown -R root:root $LFS /toolssudo chown -R root:root $LFS /sourcessudo chown -R root:root $LFS /usr
安装 riscv64 所需要的模拟器.
1 2 sudo apt install qemu-user-static qemu-system-riscv64
安装编译工具链.
see more: https://github.com/riscv-collab/riscv-gnu-toolchain
1 2 3 4 5 6 7 8 sudo apt-get install gcc-riscv64-linux-gnusudo apt install autoconf automake autotools-dev curl python3 python3-pip sudo apt install libmpc-dev libmpfr-dev libgmp-dev gawk sudo apt install build-essential bison flex texinfo gperf libtool patchutils sudo apt install bc zlib1g-dev libexpat-dev ninja-build git cmake libglib2.0-devgit clone https://github.com/riscv/riscv-gnu-toolchain ./configure --prefix=/opt/riscv make
安装需要 LFS 的最小软件包集合.
1 wget -r -l1 --no-parent --no-directories --reject "index.html*" https://ftp.osuosl.org/pub/lfs/lfs-packages/12.2/
你的目录大概如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ ls acl-2.3.2.tar.xz e2fsprogs-1.47.1.tar.gz gperf-3.1.tar.gz libpipeline-1.5.7.tar.gz patch-2.7.6.tar.xz tcl8.6.14-html.tar.gz attr-2.5.2.tar.gz elfutils-0.191.tar.bz2 grep-3.11.tar.xz libtool-2.4.7.tar.xz perl-5.40.0.tar.xz tcl8.6.14-src.tar.gz autoconf-2.72.tar.xz expat-2.6.2.tar.xz groff-1.23.0.tar.gz libxcrypt-4.4.36.tar.xz pkgconf-2.3.0.tar.xz texinfo-7.1.tar.xz automake-1.17.tar.xz expect-5.45.4-gcc14-1.patch grub-2.12.tar.xz linux-6.10.5.tar.xz procps-ng-4.0.4.tar.xz tzdata2024a.tar.gz bash-5.2.32.tar.gz expect5.45.4.tar.gz gzip-1.13.tar.xz lz4-1.10.0.tar.gz psmisc-23.7.tar.xz udev-lfs-20230818.tar.xz bc-6.7.6.tar.xz extra.sh iana-etc-20240806.tar.gz m4-1.4.19.tar.xz python-3.12.5-docs-html.tar.bz2 util-linux-2.40.2.tar.xz binutils-2.43.1.tar.xz file-5.45.tar.gz inetutils-2.5.tar.xz make-4.4.1.tar.gz Python-3.12.5.tar.xz vim-9.1.0660.tar.gz bison-3.8.2.tar.xz findutils-4.10.0.tar.xz intltool-0.51.0.tar.gz man-db-2.12.1.tar.xz readline-8.2.13.tar.gz wget-list bzip2-1.0.8-install_docs-1.patch flex-2.6.4.tar.gz iproute2-6.10.0.tar.xz man-pages-6.9.1.tar.xz sed-4.9.tar.xz wheel-0.44.0.tar.gz bzip2-1.0.8.tar.gz flit_core-3.9.0.tar.gz jinja2-3.1.4.tar.gz MarkupSafe-2.1.5.tar.gz setuptools-72.2.0.tar.gz XML-Parser-2.47.tar.gz check-0.15.2.tar.gz gawk-5.3.0.tar.xz kbd-2.6.4-backspace-1.patch md5sums shadow-4.16.0.tar.xz xz-5.6.2.tar.xz check.sh gcc-14.2.0.tar.xz kbd-2.6.4.tar.xz meson-1.5.1.tar.gz sysklogd-2.6.1.tar.gz zlib-1.3.1.tar.gz coreutils-9.5-i18n-2.patch gdbm-1.24.tar.gz kmod-33.tar.xz mpc-1.3.1.tar.gz systemd-256.4.tar.gz zstd-1.5.6.tar.gz coreutils-9.5.tar.xz gettext-0.22.5.tar.xz less-661.tar.gz mpfr-4.2.1.tar.xz systemd-man-pages-256.4.tar.xz dbus-1.14.10.tar.xz glibc-2.40-fhs-1.patch lfs-bootscripts-20240825.tar.xz ncurses-6.5.tar.gz sysvinit-3.10-consolidated-1.patch dejagnu-1.6.3.tar.gz glibc-2.40.tar.xz libcap-2.70.tar.xz ninja-1.12.1.tar.gz sysvinit-3.10.tar.xz diffutils-3.10.tar.xz gmp-6.3.0.tar.xz libffi-3.4.6.tar.gz openssl-3.3.1.tar.gz tar-1.35.tar.xz
2 一些重要的环境变量 一些目录.
1 2 mkdir -p /mnt/lfsmkdir $LFS /sources
重要的环境变量.
1 2 3 4 export LFS=/mnt/lfsexport SOURCES=$LFS /sourcesexport TOOLS=$LFS /toolsexport PATH=$TOOLS /bin:$PATH
3 正式开始安装 3.1 binutils 安装 binutils. 这一套工具是帮助我们交叉编译的.
1 2 3 4 5 6 7 8 9 cp -ar binutils-2.43.1.tar.xz $SOURCES cd $SOURCES tar -xf binutils-2.43.1.tar.xz -C $SOURCES cd binutils-2.43.1/mkdir buildcd build../configure --prefix=$LFS /tools --target=riscv64-unknown-linux-gnu --disable-nls --enable-gold --enable-ld=default make make install
首先 pull 下 linux kernel.
1 2 make mrproper make ARCH=riscv INSTALL_HDR_PATH=$LFS /usr headers_install
3.3 gcc stage1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 tar -xf gcc-14.2.0.tar.xz cd gcc-14.2.0cp gmp-6.3.0.tar.xz mpfr-4.2.1.tar.xz mpc-1.3.1.tar.gz $SOURCES /gcc-14.2.0/tar -xf gmp-6.3.0.tar.xz tar -xf mpfr-4.2.1.tar.xz tar -xf mpc-1.3.1.tar.gz mv -v gmp-6.3.0 gmpmv -v mpfr-4.2.1 mpfrmv -v mpc-1.3.1 mpcmkdir -p buildcd build../configure \ --target=riscv64-unknown-linux-gnu \ --prefix=$LFS /tools \ --with-glibc-version=2.40 \ --with-sysroot=$LFS \ --with-newlib \ --without-headers \ --enable-default-pie \ --enable-default-ssp \ --disable-nls \ --disable-shared \ --disable-multilib \ --disable-threads \ --disable-libatomic \ --disable-libgomp \ --disable-libquadmath \ --disable-libssp \ --disable-libvtv \ --disable-libstdcxx \ --enable-languages=c,c++ make -j$(nproc ) make install
3.4 glibc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cp -v glibc-2.40.tar.xz glibc-2.40-fhs-1.patch $SOURCES /tar -xf glibc-2.40.tar.xz cd glibc-2.40patch -Np1 -i ../glibc-2.40-fhs-1.patch mkdir build && cd build../configure \ --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --build=$(../scripts/config.guess) \ --enable-kernel=4.15 \ --with-headers=$LFS /usr/include \ --disable-soft-fp \ libc_cv_slibdir=/usr/lib \ libc_cv_rtlddir=/usr/lib make -j$(nproc ) make DESTDIR=$LFS install
此时会看见多出许多文件.
1 2 $ ls $LFS etc linux-6.18.5 sbin sources tools usr var
验证是否安装正确.
1 2 3 4 5 6 7 8 9 10 ls -l $LFS /usr/lib/ld-linux-riscv64*.so.1ls -l $LFS /usr/lib/libc.so.6file $LFS /usr/lib/libc.so.6 ls -l $LFS /usr/include/stdio.hgrep 'RTLDLIST=' $LFS /usr/bin/ldd
现在来验证一下程序.
1 2 echo '#include <stdio.h> int main() { printf("Hello, RISC-V!\n"); return 0; }' > hello.c
编译.
1 riscv64-unknown-linux-gnu-gcc hello.c -o hello
查看文件格式.
3.5 gcc stage2 目前的 GCC 是不够完整的: 它没有 C++ 标准库(libstdc++), 不支持线程, 也不支持共享库.
我们删除之前编译的版本.
1 2 3 4 cd $SOURCES /gcc-14.2.0rm -rf buildmkdir buildcd build
这次配置增加了共享库, 线程, c++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ../configure \ --target=riscv64-unknown-linux-gnu \ --prefix=$LFS /tools \ --with-glibc-version=2.40 \ --with-sysroot=$LFS \ --enable-default-pie \ --enable-default-ssp \ --disable-nls \ --disable-multilib \ --disable-libvtv \ --enable-languages=c,c++ \ --enable-shared \ --enable-threads=posix \ --enable-libstdcxx \ --enable-libatomic \ --enable-libgomp \ --enable-libquadmath \ --enable-libssp \ --enable-libitm make -j$(nproc ) make install
验证.
1 2 3 4 5 6 7 8 9 10 11 12 cat <<'EOF' > hello.cppint main () { std::vector<int> v = {1, 2, 3}; for (auto i : v) { std::cout << "Value: " << i << std::endl; } return 0; } EOF
编译.
1 2 riscv64-unknown-linux-gnu-g++ hello.cpp -o hello_Cpp file hello_Cpp
3.6 bash 现在不安装 bash 就进入 chroot 环境会黑屏一片.
1 2 3 4 5 6 7 8 9 10 cp -ar bash-5.2.32.tar.gz $LFS /sources/cd $LFS /sourcestar -xf bash-5.2.32.tar.gz cd bash-5.2.32/./configure --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --without-bash-malloc \ CFLAGS="-g -O2 -Wno-implicit-function-declaration" make -j$(nproc ) make DESTDIR=$LFS install
完成之后会生成目录.
3.7 coreutils 一个系统需要有最基础的 ls, cp, mv, mkdir 这些命令.
1 2 3 4 5 6 7 8 9 10 11 12 cp -ar coreutils-9.5* $SOURCES cd $LFS /sourcestar -xf coreutils-9.5.tar.xz cd coreutils-9.5/patch -Np1 -i ../coreutils-9.5-i18n-2.patch ./configure --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --enable-install-program=hostname \ --enable-no-install-program=kill ,uptime \ FORCE_UNSAFE_CONFIGURE=1 make -j$(nproc ) make DESTDIR=$LFS install
验证.
1 2 3 ls -l $LFS /usr/bin/lsls -l $LFS /usr/bin/mkdirls -l $LFS /usr/bin/cp
3.8 安装 fastfetch 为了让进入系统的时候能够打印出系统的信息, 我们需要这个工具.
1 2 3 cd $SOURCES git clone https://github.com/fastfetch-cli/fastfetch.git cd fastfetch
交叉编译.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 mkdir build && cd buildcmake .. \ -DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc \ -DCMAKE_CXX_COMPILER=riscv64-unknown-linux-gnu-g++ \ -DCMAKE_INSTALL_PREFIX=/usr \ -DENABLE_EGL=OFF \ -DENABLE_GLX=OFF \ -DENABLE_X11=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_XEXT=OFF \ -DENABLE_WAYLAND=OFF \ -DENABLE_VULKAN=OFF -DENABLE_OPENCL=OFF -DENABLE_DRM=OFF \ -DENABLE_GIO=OFF -DENABLE_DBUS=OFF -DENABLE_PULSE=OFF \ -DENABLE_ZLIB=OFF -DENABLE_SQLITE3=OFF -DENABLE_IMAGEMAGICK=OFF -DENABLE_XFCONF=OFF \ -DCMAKE_DISABLE_FIND_PACKAGE_X11=ON \ -DCMAKE_DISABLE_FIND_PACKAGE_OpenGL=ON \ -DCMAKE_DISABLE_FIND_PACKAGE_OpenCL=ON \ -DCMAKE_DISABLE_FIND_PACKAGE_Wayland=ON make -j$(nproc ) sudo make DESTDIR=$LFS install
到目前为止, 已经可以直接去 4 了, 但是要是想在真机或者虚拟机运行的话, 还是得继续完成 3.9.
3.9 安装 sysvinit 当内核完成硬件初始化之后, 会启动第一个 init 进程.
sysvinit 和 systemd 就是传统和现代方式的两种 init 系统.
我们选择前者, 因为它的依赖不多.
1 2 3 4 5 6 7 cp -ar sysvinit-3.10* $LFS /sources/cd $LFS /sourcestar -xf sysvinit-3.10.tar.xz cd sysvinit-3.10/patch -Np1 -i ../sysvinit-3.10-consolidated-1.patch make CC=riscv64-unknown-linux-gnu-gcc sudo make ROOT=$LFS install
此时我们可以看到 $LFS/sbin/ 目录下已经生成了 init, halt, shutdown 等核心程序
3.10 安装 utils-linux 该软件包包含 mount, umount, getty 这些基础的指令. 如果不编译的话很难成功进入安装了 sysvinit 的系统.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 cp -ar util-linux-2.40.2.tar.xz $LFS /sources/cd $LFS /sourcestar -xf util-linux-2.40.2.tar.xz cd util-linux-2.40.2/./configure --host=riscv64-unknown-linux-gnu \ --build=$(build-aux/config.guess) \ --libdir=/usr/lib \ --runstatedir=/run \ --disable-chfn-chsh \ --disable-login \ --disable-nologin \ --disable-su \ --disable-setpriv \ --disable-runuser \ --disable-pylibmount \ --disable-static \ --disable-liblastlog2 \ --without-python \ --without-tinfo \ --without-ncurses \ --without-readline \ ADJTIME_PATH=/var/lib/hwclock/adjtime make -j$(nproc ) sudo env PATH="$PATH " LFS="$LFS " make DESTDIR="$LFS " install
这里可能会报错.
我们看看自己需要的软件在不在就可以了.
1 2 3 ls -l $LFS /bin/mountls -l $LFS /sbin/agettyls -l $LFS /usr/lib/libmount.so.1
1 2 3 4 5 6 7 8 9 10 11 chgrp tty /mnt/lfs/usr/bin/wallchgrp : changing group of '/mnt/lfs/usr/bin/wall' : Operation not permittedmake[4]: *** [Makefile:18850: install-exec-hook-wall] Error 1 make[4]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2' make[3]: *** [Makefile:18004: install-exec-am] Error 2 make[3]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2' make[2]: *** [Makefile:17269: install-am] Error 2 make[2]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2' make[1]: *** [Makefile:16951: install-recursive] Error 1 make[1]: Leaving directory '/mnt/lfs/sources/util-linux-2.40.2' make: *** [Makefile:17262: install] Error 2
我们不用理会, 因为必要的软件其实已经成功安装了.
4 进入 chroot 环境 创建基本的目录.
1 2 sudo mkdir -pv $LFS /{dev,proc,sys,run,etc,var,tmp}sudo mkdir -pv $LFS /usr/{bin,sbin,lib}
挂载文件系统.
1 2 3 4 5 sudo mount -v --bind /dev $LFS /devsudo mount -v --bind /dev/pts $LFS /dev/ptssudo mount -v -t proc proc $LFS /procsudo mount -v -t sysfs sysfs $LFS /syssudo mount -v -t tmpfs tmpfs $LFS /run
创建必要的链接.
1 2 3 4 5 6 sudo ln -sf bash $LFS /bin/shsudo ln -sv /usr/lib/ld-linux-riscv64-lp64d.so.1 $LFS /lib/ld-linux-riscv64-lp64d.so.1sudo ln -sv usr/bin binsudo ln -sv usr/sbin sbinsudo ln -sv usr/lib lib
正式进入 chroot
1 2 3 4 5 6 sudo chroot "$LFS " /usr/bin/env -i \ HOME=/root \ TERM="$TERM " \ PS1='(ruyi chroot):' \ PATH=/usr/bin:/usr/sbin \ /bin/bash --login
我们来看看 fastfetch 结果.
卸载挂载的文件系统方法如下.
1 2 3 4 5 sudo umount -v $LFS /runsudo umount -v $LFS /syssudo umount -v $LFS /procsudo umount -v $LFS /dev/ptssudo umount -v $LFS /dev
5 在虚拟机运行 LFS 的系统 chroot 不需要内核, 因为它借用宿主机的, 但虚拟机需要.
当然! 如果想在虚拟机跑也是 ok 滴!
5.1 编译内核 1 2 3 make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc ) Image
5.2 完善系统 首先我们在进入系统之前需要先让内核能识别到硬盘.
1 2 3 cat > $LFS /etc/fstab << "EOF" /dev/vda2 / ext4 defaults 1 1 EOF
如果希望系统进入之后就能够看见到 fastfetch.
1 echo "/usr/bin/fastfetch" >> $LFS /etc/profile
创建 inittab 文件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo bash -c "cat > $LFS /etc/inittab << 'EOF' id:3:initdefault: # 系统启动的第一格脚本. si::sysinit:/etc/rc.d/init.d/rc S # ID 不能太长, 亲测试会报错. # 如果不需要用户则执行下面这一行替换最下面的一行 # 目前用户登陆还没有更新, 后续有时间我登陆, 原因是需要安装 login # login 必须要在 chroot 之后安装, 还要安装一些其他包, 比较麻烦 # s0:2345:respawn:/bin/sh s0:2345:respawn:/sbin/agetty 115200 ttyS0 vt100 EOF" sudo ln -sf agetty $LFS /sbin/getty
然后编辑我们的启动脚本.
这里我选择加入了 logo.txt.
这里如果不想加入自己的 logo, 可以跳过这一步骤.
1 2 3 4 5 6 7 8 9 sudo bash -c "printf ' \033[1;36m _ _ \033[1;36m (_)_ __ | | ___ \033[1;32m | \ \ / / | |/ _ \ \033[1;32m | |\ V / | | __/ \033[1;33m _/ | \_/ |_|\___| \033[1;33m |__/ \033[1;34m --- RISC-V LFS --- \033[0m ' > $LFS /usr/share/jvle_logo.txt"
继续.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 sudo mkdir -pv $LFS /etc/rc.d/init.dsudo bash -c "cat > $LFS /etc/rc.d/init.d/rc << 'EOF' #!/bin/sh export PATH=/bin:/sbin:/usr/bin:/usr/sbin export LD_LIBRARY_PATH=/lib:/usr/lib mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev mount -t tmpfs tmpfs /run echo -e '\033[1;32mBooting jvle Custom System...\033[0m' # 这里我添加了自己的 logo /usr/bin/fastfetch --file /usr/share/logo.txt --logo-color-1 32 echo 'jvle-RISCV' > /proc/sys/kernel/hostname PS1='[jvle@riscv \W]# ' EOF" sudo chmod +x $LFS /etc/rc.d/init.d/rc
加入 login 功能, 这里需要安装 shadow 软件包.
首先我们需要配置一些基础的用户数据文件.
这里给出基本的模板, 有些用户我也不了解为什么会存在, 跟历史原因有关.
1 2 3 4 5 6 7 cat > $LFS /etc/passwd << "EOF" root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/dev/null:/usr/bin/false daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false nobody:x:99:99:Unprivileged User:/dev/null:/usr/bin/false EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 cat > $LFS /etc/group << "EOF" root:x:0: bin:x:1:daemon sys:x:2: kmem:x:3: tape:x:4: tty :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: messagebus:x:18: input:x:24: mail:x:34: kvm:x:61: wheel:x:97: nogroup:x:99: users :x:999:EOF
安装 libxcrypt, 下面的 shadow 需要.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 tar -xf libxcrypt-4.4.36.tar.xz cd libxcrypt-4.4.36/./configure --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --enable-hashes=strong,glibc \ --enable-obsolete-api=no \ --disable-static \ --disable-failure-tokens make -j$(nproc ) make DESTDIR=$LFS install
安装 shadow 软件包进行多用户管理.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 tar -xf shadow-4.16.0.tar.xz cd shadow-4.16.0/sed -i 's/groups$(EXEEXT) //' src/Makefile.in find man -name Makefile.in -exec sed -i 's/groups\.1 / /' {} \; find man -name Makefile.in -exec sed -i 's/getspnam\.3 / /' {} \; find man -name Makefile.in -exec sed -i 's/passwd\.5 / /' {} \; ./configure --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --sysconfdir=/etc \ --without-libbsd \ --without-selinux make -j$(nproc ) make DESTDIR=$LFS install
创建 shadow 文件.
1 2 3 4 5 6 7 8 9 10 11 cat > $LFS /etc/shadow << "EOF" root::19000:0:99999:7::: bin:*:19000:0:99999:7::: daemon:*:19000:0:99999:7::: messagebus:*:19000:0:99999:7::: nobody:*:19000:0:99999:7::: EOF sudo chmod 600 $LFS /etc/shadowsudo chmod 644 $LFS /etc/passwd $LFS /etc/group
创建 /etc/nsswitch.conf 文件.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 cat > $LFS /etc/nsswitch.conf << "EOF" passwd: files group: files shadow: files hosts: files dns networks: files protocols: files services: files ethers: files rpc: files EOF
之后进入系统.
1 echo "<your password>" | passwd --stdin root
此操作会修改 /etc/shadow
修改初始化相关配置.
1 2 3 4 5 6 7 8 9 10 11 cat > /root/.bashrc << "EOF" export PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ ' alias ls ='ls --color=auto' EOF cat > /etc/profile << "EOF" export PS1='[\u@\h \W]\$ ' for i in $(ls /etc/profile.d/*.sh 2> /dev/null); do . $i done EOF
替换 /etc/initab 的最后一行.
这样 getty 会主动调用 login 登陆.
1 2 3 ... s0:2345:respawn:/sbin/getty -L 115200 ttyS0 vt100 ...
重启系统登陆.
当我们输入 root 并尝试登录时,系统的动作如下: 查询方向: 系统查看 /etc/nsswitch.conf,确定查用户信息要找 files. 查找用户: 去 /etc/passwd 确认是否有 root 用户,找到其 UID 和家目录. 验证密码: 去 /etc/shadow 比对输入的密码经过计算后是否与存储的加密字符串一致. 确定权限: 去 /etc/group 看看 root 还属于哪些额外的组. 开启环境: 一切通过后,加载 /etc/passwd 中指定的 /bin/bash.
在有了系统镜像之后, 并且我们设置了多用户之后, 会展现出一个系统应有的模样.
5.3 创建系统镜像 然后创建系统镜像.
1 2 3 4 5 6 7 8 mkdir -pb $LFS /bootcd $LFS /bootdd if =/dev/zero of=riscv_lfs.img bs=1M count=20480 mkfs.ext4 riscv_lfs.img mkdir -p /mnt/lfs_disksudo mount riscv_lfs.img /mnt/lfs_disksudo cp -a $LFS /* /mnt/lfs_disk/sudo umount /mnt/lfs_disk
5.4 启动系统 1 2 3 4 5 qemu-system-riscv64 -nographic -machine virt \ -kernel $LFS /linux-6.18.5/arch/riscv/boot/Image \ -append "root=/dev/vda rw console=ttyS0" \ -drive file=$LFS /boot/riscv_lfs.img,format=raw,id =hd0 \ -device virtio-blk-device,drive=hd0
6 快速启动成品 成品链接: https://github.com/Jvlegod/lfs-from-riscv/releases/tag/v0.1.0 成品校验: 点击下载压缩包
下载我给出的 rootfs.
根据 5.3 的方法操作, 然后根据 5.4 直接启动.
7 可选功能包 7.1 kmod 这会加入 insmod, rmmod 这些模块的功能.
1 2 3 4 5 6 7 8 9 10 11 12 13 tar -xf kmod-33.tar.xz cd kmod-33./configure --host=riscv64-unknown-linux-gnu \ --prefix=/usr \ --bindir=/bin \ --sysconfdir=/etc \ --with-zlib=no \ --with-xz=no \ --with-zstd=no \ --with-openssl=no \ --disable-manpages make -j$(nproc ) sudo make DESTDIR=${LFS} install
7.2 自编译系统 最初我们只可以在宿主机系统编译程序, 从这里开始我们将尝试从自己构建的系统上开始编译程序.
7.2.1 binutils 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cd binutils-2.43.1/mkdir build && cd build../configure --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --target=riscv64-unknown-linux-gnu \ --disable-nls \ --enable-ld=default \ --enable-gold make -j$(nproc ) make DESTDIR=$LFS install
7.2.2 gcc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 cd gcc-14.2.0cp gmp-6.3.0.tar.xz mpfr-4.2.1.tar.xz mpc-1.3.1.tar.gz $SOURCES /gcc-14.2.0/tar -xf gmp-6.3.0.tar.xz tar -xf mpfr-4.2.1.tar.xz tar -xf mpc-1.3.1.tar.gz mv -v gmp-6.3.0 gmpmv -v mpfr-4.2.1 mpfrmv -v mpc-1.3.1 mpccp -ar zlib-1.3.1.tar.gz $SOURCES /gcc-14.2.0tar -xf zlib-1.3.1.tar.gz mv zlib-1.3.1 zlibmkdir build && cd build../configure \ --build=$(../config.guess) \ --host=riscv64-unknown-linux-gnu \ --target=riscv64-unknown-linux-gnu \ --prefix=/usr \ --enable-shared \ --enable-languages=c,c++ \ --enable-threads=posix \ --enable-clocale=gnu \ --enable-default-pie \ --enable-default-ssp \ --disable-multilib \ --disable-bootstrap \ --disable-libvtv \ --disable-libsanitizer \ --enable-libstdcxx-time=yes \ --enable-libgomp \ --enable-libatomic \ --enable-linker-build-id \ --disable-nls \ --disable-werror make -j$(nproc ) make DESTDIR=$LFS install
7.3 make 我们通常需要 make 来协助我们编译需要的软件.
1 2 3 4 5 6 7 8 9 10 11 12 13 tar -xf make-4.4.1.tar.gz cd make-4.4.1./configure \ --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --build=$(./build-aux/config.guess) \ --without-guile make -j(nproc ) make DESTDIR=$LFS install
7.4 tar, xz, gzip 1 2 3 4 5 6 7 8 9 10 11 12 13 tar -xf tar-1.35.tar.xz cd tar-1.35FORCE_UNSAFE_CONFIGURE=1 ./configure \ --prefix=/usr \ --bindir=/bin \ --host=riscv64-unknown-linux-gnu make -j$(nproc ) make DESTDIR=$LFS install
继续.
1 2 3 4 5 6 7 8 9 10 11 tar -xf xz-5.6.2.tar.xz cd xz-5.6.2./configure \ --prefix=/usr \ --host=riscv64-unknown-linux-gnu \ --disable-static \ --docdir=/usr/share/doc/xz-5.6.2 make -j$(nproc ) make DESTDIR=$LFS install
继续.
1 2 3 4 5 6 7 tar -xf gzip-1.13.tar.xz cd gzip-1.13./configure --prefix=/usr --host=riscv64-unknown-linux-gnu make -j$(nproc ) make DESTDIR=$LFS install
7.5 sed, grep, gawk 几乎所有的 ./configure 都是 sed, grep, gawk 来解析的, 因此我们需要安装它.
sed.
1 2 3 4 5 6 7 tar -xf sed-4.9.tar.xz cd sed-4.9./configure --prefix=/usr --host=riscv64-unknown-linux-gnu make -j$(nproc ) make DESTDIR=$LFS install
grep.
1 2 3 4 5 6 7 tar -xf grep-3.11.tar.xz cd grep-3.11./configure --prefix=/usr --host=riscv64-unknown-linux-gnu make -j$(nproc ) make DESTDIR=$LFS install
gawk.
1 2 3 4 5 6 7 8 9 tar -xf gawk-5.3.0.tar.xz cd gawk-5.3.0./configure --prefix=/usr --host=riscv64-unknown-linux-gnu make -j$(nproc ) make DESTDIR=$LFS install
至此, 我们的所有编译工作已经可以放在自己编译的系统上了. 之前我们为了宿主机编译的 $LFS/tools 已经可以删除了.
8 拓展 8.1 EFI 启动 首先我们要让 kernel 支持 UEFI 启动, 需要配置 config.
1 2 3 4 CONFIG_EFI=y CONFIG_EFI_STUB=y CONFIG_EFI_EARLYCON=y
然后制作启动盘.
1 qemu-img create -f raw qemu-virt_riscv64.raw 4G
挂载文件为回环设备.
1 sudo losetup -fP qemu-virt_riscv64.rawa
查看当前挂载的设备.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ losetup NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC /dev/loop1 0 0 1 1 /var/lib/snapd/snaps/bare_5.snap 0 512 /dev/loop17 0 0 1 1 /var/lib/snapd/snaps/core22_2292.snap 0 512 /dev/loop8 0 0 1 1 /var/lib/snapd/snaps/firmware-updater_210.snap 0 512 /dev/loop15 0 0 1 1 /var/lib/snapd/snaps/snapd-desktop-integration_315.snap 0 512 /dev/loop6 0 0 1 1 /var/lib/snapd/snaps/firefox_7672.snap 0 512 /dev/loop13 0 0 1 1 /var/lib/snapd/snaps/snapd_24792.snap 0 512 /dev/loop4 0 0 1 1 /var/lib/snapd/snaps/docker_3377.snap 0 512 /dev/loop11 0 0 1 1 /var/lib/snapd/snaps/snap-store_1270.snap 0 512 /dev/loop2 0 0 1 1 /var/lib/snapd/snaps/core22_2216.snap 0 512 /dev/loop0 0 0 0 0 <path这里我隐藏了绝对路径>/lfs-from-riscv/qemu-virt_riscv64.raw 0 512 /dev/loop9 0 0 1 1 /var/lib/snapd/snaps/gnome-42-2204_202.snap 0 512 /dev/loop16 0 0 1 1 /var/lib/snapd/snaps/snapd-desktop-integration_343.snap 0 512 /dev/loop7 0 0 1 1 /var/lib/snapd/snaps/firmware-updater_167.snap 0 512 /dev/loop14 0 0 1 1 /var/lib/snapd/snaps/snapd_25935.snap 0 512 /dev/loop5 0 0 1 1 /var/lib/snapd/snaps/firefox_7633.snap 0 512 /dev/loop12 0 0 1 1 /var/lib/snapd/snaps/gtk-common-themes_1535.snap 0 512 /dev/loop3 0 0 1 1 /var/lib/snapd/snaps/core24_1267.snap 0 512 /dev/loop10 0 0 1 1 /var/lib/snapd/snaps/gnome-42-2204_247.snap 0 512
之后我们来进行分区.
步骤:
创建 GPT 分区表
创建 ESP 分区
创建 rootfs 分区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 $ sudo fdisk /dev/loop0 Welcome to fdisk (util-linux 2.39.3). Changes will remain in memory only, until you decide to write them. Be careful before using the write command . Device does not contain a recognized partition table. Created a new DOS (MBR) disklabel with disk identifier 0x5d26fc48. Command (m for help ): g Created a new GPT disklabel (GUID: 84F79F19-7BFC-45F5-9A17-6EA1EC18E1D8). Command (m for help ): n Partition number (1-128, default 1): 1 First sector (2048-8388574, default 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-8388574, default 8386559): +100M Created a new partition 1 of type 'Linux filesystem' and of size 100 MiB. Command (m for help ): t Selected partition 1 Partition type or alias (type L to list all): 1 Changed type of partition 'Linux filesystem' to 'EFI System' . Command (m for help ): n Partition number (2-128, default 2): 2 First sector (206848-8388574, default 206848): Last sector, +/-sectors or +/-size{K,M,G,T,P} (206848-8388574, default 8386559): Created a new partition 2 of type 'Linux filesystem' and of size 3.9 GiB. Command (m for help ): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks.
查看 loop0 的分区情况.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 $ sudo fdisk -l /dev/loop0 Disk /dev/loop0: 4 GiB, 4294967296 bytes, 8388608 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type : gpt Disk identifier: 84F79F19-7BFC-45F5-9A17-6EA1EC18E1D8 Device Start End Sectors Size Type /dev/loop0p1 2048 206847 204800 100M EFI System /dev/loop0p2 206848 8386559 8179712 3.9G Linux filesystem $ lsblk /dev/loop0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 4G 0 loop ├─loop0p1 259:5 0 100M 0 part └─loop0p2 259:6 0 3.9G 0 part
分区.
1 2 3 4 5 6 $ sudo partprobe /dev/loop0 sudo mkfs.vfat -F32 /dev/loop0p1sudo mkfs.ext4 /dev/loop0p2
挂载分区.
1 2 3 mkdir -p mnt_esp mnt_rootsudo mount /dev/loop0p1 mnt_espsudo mount /dev/loop0p2 mnt_root
此时查看挂载情况.
1 2 3 4 5 $ lsblk /dev/loop0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7:0 0 4G 0 loop ├─loop0p1 259:7 0 100M 0 part /home/jvle/Desktop/works/lfs-from-riscv/mnt_esp └─loop0p2 259:8 0 3.9G 0 part /home/jvle/Desktop/works/lfs-from-riscv/mnt_root
扩容(这里根据情况来看, 因为作者发现这里空间不够, 遂扩容)
1 2 3 4 5 6 7 8 9 10 11 sudo umount /home/jvle/Desktop/works/lfs-from-riscv/mnt_espsudo umount /home/jvle/Desktop/works/lfs-from-riscv/mnt_rootqemu-img resize qemu-virt_riscv64.raw +2G sudo losetup -c /dev/loop0sudo parted /dev/loop0 unit s print sudo parted /dev/loop0 resizepart 2 100%sudo resize2fs /dev/loop0p2
继续
将 rootfs 的内容拷贝到分区.
1 sudo cp -ar $LFS /* mnt_root/
制作 efi 分区的内容.
1 2 3 sudo mkdir -p mnt_esp/EFI/BOOTsudo mkdir -p mnt_esp/EFI/systemd
目录结构如下.
1 2 3 4 5 6 7 $ tree mnt_esp/ mnt_esp/ └── EFI ├── BOOT │ └── BOOTRISCV64.EFI └── systemd └── systemd-bootriscv64.efi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sudo mkdir -p mnt_esp/loadersudo mkdir -p mnt_esp/loader/entriessudo tee mnt_esp/loader/loader.conf << EOF default lfs.conf timeout 3 console-mode keep EOF sudo tee mnt_esp/loader/entries/lfs.conf << EOF title Linux From Scratch (RISC-V) version 6.18.5 linux /vmlinuz-linux options root=/dev/vda2 rw console=ttyS0 earlycon=sbi EOF
我们还需要将编译好的 kernel 也传入进去.
1 2 3 4 5 6 7 8 9 10 11 12 $ tree mnt_esp/ mnt_esp/ ├── EFI │ ├── BOOT │ │ └── BOOTRISCV64.EFI │ └── systemd │ └── systemd-bootriscv64.efi ├── loader │ ├── entries │ │ └── lfs.conf │ └── loader.conf └── vmlinuz-linux
卸载挂载的文件.
1 2 3 sudo umount mnt_esp mnt_rootsudo losetup -d /dev/loop0
启动.
会看到我们准备好的启动项.
9 在自己编译的系统上安装更多软件 这里除了软件无法搬移到自己编译的系统以外, 可以完全用自己编译的系统操作了.
9.2 编辑器 这里我们安装 nano, vim.
实际上安装一个就够了.
但是首先要安装 ncurses, 这是所有编辑器的基础.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 tar -xf ncurses-6.5.tar.gz cd ncurses-6.5./configure --prefix=/usr \ --mandir=/usr/share/man \ --with-shared \ --without-debug \ --without-normal \ --with-cxx-binding \ --enable-pc-files \ --enable-widec make make install ln -sfv libncursesw.so /usr/lib/libncurses.soln -sfv libncursesw.a /usr/lib/libncurses.aln -sfv ncursesw.pc /usr/lib/pkgconfig/ncurses.pc
nano.
1 2 3 4 5 6 7 8 9 10 11 12 13 wget https://www.nano-editor.org/dist/latest/nano-8.1.tar.gz cd /sources/nano-8.1./configure --prefix=/usr \ --sysconfdir=/etc \ --enable-utf8 \ --docdir=/usr/share/doc/nano-8.1 make make install
vim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 tar -xf vim-9.1.0000.tar.gz cd vim-9.1.0000echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> src/feature.h./configure --prefix=/usr \ --with-features=huge \ --enable-multibyte make -j$(nproc ) make install ln -sv vim /usr/bin/vi