全程建议给执行的用户目标权限. 这样后面就尽量别用 sudo, 容易出错.
sudo chown -R lfs:lfs $LFS/tools $LFS/sources $LFS/usr $LFS如果没有创建该用户.
# 创建 lfs 组
sudo groupadd lfs
# 创建 lfs 用户并加入组,指定 bash 为 shell
sudo useradd -s /bin/bash -g lfs -m -k /dev/null lfs
# 给 lfs 用户设置密码
sudo passwd lfs后期恢复权限.
sudo chown -R root:root $LFS/tools
sudo chown -R root:root $LFS/sources
sudo chown -R root:root $LFS/usr安装 riscv64 所需要的模拟器.
sudo apt install qemu-user-static qemu-system-riscv64
安装编译工具链.
see more: https://github.com/riscv-collab/riscv-gnu-toolchain
sudo apt-get install gcc-riscv64-linux-gnu
sudo 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-dev
git clone https://github.com/riscv/riscv-gnu-toolchain
./configure --prefix=/opt/riscv
make安装需要 LFS 的最小软件包集合.
wget -r -l1 --no-parent --no-directories --reject "index.html*" https://ftp.osuosl.org/pub/lfs/lfs-packages/12.2/你的目录大概如下:
$ 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一些目录.
mkdir -p /mnt/lfs
mkdir $LFS/sources重要的环境变量.
export LFS=/mnt/lfs
export SOURCES=$LFS/sources
export TOOLS=$LFS/tools
export PATH=$TOOLS/bin:$PATH安装 binutils. 这一套工具是帮助我们交叉编译的.
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 build
cd build
../configure --prefix=$LFS/tools --target=riscv64-unknown-linux-gnu --disable-nls --enable-gold --enable-ld=default
make
make install首先 pull 下 linux kernel.
make mrproper
make ARCH=riscv INSTALL_HDR_PATH=$LFS/usr headers_installtar -xf gcc-14.2.0.tar.xz
cd gcc-14.2.0
# 如果 gmp, mpfr, mpc 没有拉到 gcc, 则将他们拉过去.
cp 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 gmp
mv -v mpfr-4.2.1 mpfr
mv -v mpc-1.3.1 mpc
mkdir -p build
cd 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 installcp -v glibc-2.40.tar.xz glibc-2.40-fhs-1.patch $SOURCES/
tar -xf glibc-2.40.tar.xz
cd glibc-2.40
patch -Np1 -i ../glibc-2.40-fhs-1.patch
mkdir build && cd build
# 这里 prefix=/usr 是正确的, prefix 在这里指定的是在目标机器运行时的预期位置
# 4.15 表示兼容的最低版本.
../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此时会看见多出许多文件.
$ ls $LFS
etc linux-6.18.5 sbin sources tools usr var验证是否安装正确.
# 动态链接器
ls -l $LFS/usr/lib/ld-linux-riscv64*.so.1
# 标准 C
ls -l $LFS/usr/lib/libc.so.6
file $LFS/usr/lib/libc.so.6
# 头文件
ls -l $LFS/usr/include/stdio.h
# 验证动态链接器路径
grep 'RTLDLIST=' $LFS/usr/bin/ldd
# RTLDLIST="/usr/lib/ld-linux-riscv64-lp64.so.1 /usr/lib/ld-linux-riscv64-lp64d.so.1 /usr/lib/ld-linux-riscv32-ilp32.so.1 /usr/lib/ld-linux-riscv32-ilp32d.so.1"现在来验证一下程序.
echo '#include <stdio.h>
int main() { printf("Hello, RISC-V!\n"); return 0; }' > hello.c编译.
riscv64-unknown-linux-gnu-gcc hello.c -o hello查看文件格式.
file hello
# hello: ELF 64-bit LSB pie executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, with debug_info, not stripped目前的 GCC 是不够完整的: 它没有 C++ 标准库(libstdc++), 不支持线程, 也不支持共享库.
我们删除之前编译的版本.
cd $SOURCES/gcc-14.2.0
rm -rf build
mkdir build
cd build这次配置增加了共享库, 线程, c++.
../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验证.
cat <<'EOF' > hello.cpp
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3};
for (auto i : v) {
std::cout << "Value: " << i << std::endl;
}
return 0;
}
EOF编译.
riscv64-unknown-linux-gnu-g++ hello.cpp -o hello_Cpp
file hello_Cpp现在不安装 bash 就进入 chroot 环境会黑屏一片.
cp -ar bash-5.2.32.tar.gz $LFS/sources/
cd $LFS/sources
tar -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完成之后会生成目录.
ls -l $LFS/usr/bash一个系统需要有最基础的 ls, cp, mv, mkdir 这些命令.
cp -ar coreutils-9.5* $SOURCES
cd $LFS/sources
tar -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验证.
ls -l $LFS/usr/bin/ls
ls -l $LFS/usr/bin/mkdir
ls -l $LFS/usr/bin/cp为了让进入系统的时候能够打印出系统的信息, 我们需要这个工具.
cd $SOURCES
git clone https://github.com/fastfetch-cli/fastfetch.git
cd fastfetch交叉编译.
mkdir build && cd build
cmake .. \
-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.
当内核完成硬件初始化之后, 会启动第一个 init 进程.
sysvinit 和 systemd 就是传统和现代方式的两种 init 系统.
我们选择前者, 因为它的依赖不多.
cp -ar sysvinit-3.10* $LFS/sources/
cd $LFS/sources
tar -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 等核心程序
该软件包包含 mount, umount, getty 这些基础的指令. 如果不编译的话很难成功进入安装了 sysvinit 的系统.
cp -ar util-linux-2.40.2.tar.xz $LFS/sources/
cd $LFS/sources
tar -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这里可能会报错.
我们看看自己需要的软件在不在就可以了.
ls -l $LFS/bin/mount
ls -l $LFS/sbin/agetty
ls -l $LFS/usr/lib/libmount.so.1chgrp tty /mnt/lfs/usr/bin/wall
chgrp: changing group of '/mnt/lfs/usr/bin/wall': Operation not permitted
make[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我们不用理会, 因为必要的软件其实已经成功安装了.
创建基本的目录.
sudo mkdir -pv $LFS/{dev,proc,sys,run,etc,var,tmp}
sudo mkdir -pv $LFS/usr/{bin,sbin,lib}挂载文件系统.
sudo mount -v --bind /dev $LFS/dev
sudo mount -v --bind /dev/pts $LFS/dev/pts
sudo mount -v -t proc proc $LFS/proc
sudo mount -v -t sysfs sysfs $LFS/sys
sudo mount -v -t tmpfs tmpfs $LFS/run创建必要的链接.
# 为什么创建这些链接, 因为我 chroot 的时候发现抱错了, 一个个试的.
sudo ln -sf bash $LFS/bin/sh
sudo ln -sv /usr/lib/ld-linux-riscv64-lp64d.so.1 $LFS/lib/ld-linux-riscv64-lp64d.so.1
sudo ln -sv usr/bin bin
sudo ln -sv usr/sbin sbin
sudo ln -sv usr/lib lib正式进入 chroot
sudo chroot "$LFS" /usr/bin/env -i \
HOME=/root \
TERM="$TERM" \
PS1='(ruyi chroot):' \
PATH=/usr/bin:/usr/sbin \
/bin/bash --login我们来看看 fastfetch 结果.
卸载挂载的文件系统方法如下.
sudo umount -v $LFS/run
sudo umount -v $LFS/sys
sudo umount -v $LFS/proc
sudo umount -v $LFS/dev/pts
sudo umount -v $LFS/devchroot 不需要内核, 因为它借用宿主机的, 但虚拟机需要.
当然! 如果想在虚拟机跑也是 ok 滴!
# 我们只需要一个内核就够了
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) Image首先我们在进入系统之前需要先让内核能识别到硬盘.
cat > $LFS/etc/fstab << "EOF"
/dev/vda2 / ext4 defaults 1 1
EOF如果希望系统进入之后就能够看见到 fastfetch.
echo "/usr/bin/fastfetch" >> $LFS/etc/profile创建 inittab 文件.
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, 可以跳过这一步骤.
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"继续.
# 创建目录
sudo mkdir -pv $LFS/etc/rc.d/init.d
# 写入脚本内容
sudo 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 功能.
TODO.
然后创建系统镜像.
mkdir -pb $LFS/boot
cd $LFS/boot
dd if=/dev/zero of=riscv_lfs.img bs=1M count=20480 # 20GB
mkfs.ext4 riscv_lfs.img
mkdir -p /mnt/lfs_disk
sudo mount riscv_lfs.img /mnt/lfs_disk
sudo cp -a $LFS/* /mnt/lfs_disk/
sudo umount /mnt/lfs_diskqemu-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成品链接: https://github.com/Jvlegod/lfs-from-riscv 成品校验: 点击下载压缩包
下载我给出的 rootfs.
根据 5.3 的方法操作, 然后根据 5.4 直接启动.
这会加入 insmod, rmmod 这些模块的功能.
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
