ROS Noetic 中自带的 PCL 1.10 并没有 GPU 支持。如果想要启用 GPU/CUDA 支持的话,只能自己编译。
然而与 OpenCV 类似,ROS 使用了 pcl_ros, pcl_conversions 等包作为 PCL 与 在 ROS 的接口,使用自编译版本的 PCL 需要修改这些包的设置,较为麻烦。
以下是在 ROS 中使用自编译(带 GPU 支持)版本 PCL 的完整步骤。
最新版 PCL (PCL 1.14.0) 若启用 gpu 支持,需要 CUDA Toolkit v9.2+
同时,因为使用了 ccmake
,需要安装 cmake-curses-gui
:
sudo apt install cmake-curses-gui
在项目官方仓库下载 PCL,然后签出到自己需要的版本。
一般保持在 master 分支即可。若想使用特定版本,可以使用
git tag
查看版本并签出。
签出完成后,至项目目录下:
1 | mkdir build && cd build |
此时,进入 cmake 配置界面。
按 c
进入编译选项配置。
这里把选项 BUILD_CUDA
和 BUILD_GPU
打开。
多按几次 c
,会根据之前的选项生成新的选项。然后根据需要打开选项。
按 c
,直到下方出现按键 g
的提示后,按 g
。此时配置完成。
之后编译安装:
1 | make |
默认安装路径下,PCL 会被安装到 /usr/local
。
对于 pcl_conversion,需要修改的文件是 /opt/ros/noetic/share/pcl_ros/cmake/pcl_rosConfig.cmake
首先是修改头文件的目录。找到含有 include
目录的行,将 /usr/include/pcl-1.10
改为 /usr/local/include/pcl-1.14
再往下到 set(libraries
开头的行,将所有 pcl 的库路径修改至 /usr/local/lib
下。
对于 pcl_ros,也是同样操作。但 pcl_ros 可能缺少部分 pcl 库的路径,如 libpcl_registration.so
。需要手动加上。
实际路径根据安装位置确定,这里是默认安装位置。
至此,安装已全部完成。所有依赖 pcl,pcl_ros,pcl_conversion 的包应该都能正常编译。
如果发现链接器报错 undefined reference
,可能是 pcl_ros 的部分库目录没有加上,找到没有加上的路径就好。
操作完成后,这两个包在更新时可能会覆盖掉上面进行的设置,可以使用 apt-mark
屏蔽对软件包的更新:
1 | sudo apt-mark hold pcl_conversions |
1 | support for URL transfers was disabled when Octave was built |
这是因为 Gentoo 在对 ocatve 配置的 USE 中,没有加上对 curl 的支持,导致 pkg 无法使用 URL 下载软件包。
如果需要使用 pkg 安装软件包,需要为 octave 单独加上 USEcurl
。
在/etc/portage/package.use
中,加上:
sci-mathematics/octave curl
即可。
PS: 记得emerge -avuDN @world
先解压:
1 | tar -xvf linux-5.13.12.tar.xz |
清理源码树,虽然才解压没什么必要:
make mrproper
此处使用:
make menuconfig
原来我一直想使用 arch 的配置然后
oldconfig
,但试了很多次后机器启动一直失败。
配置选项说明参见金步国的博客:http://www.jinbuguo.com/kernel/longterm-linux-kernel-options.html
虽然是 4.4 的,但大部分选项都没变,尤其是驱动相关。
尽量不要改默认的配置,驱动相关的另说。
下面是具体的配置选项:
General setup 下:
1 | [*] Control Group support ---> |
Processor type and features 下:
1 | # EFI 的支持选项: |
Firmware Drivers 下
1 | [*] Export DMI identification via sysfs to userspace |
Networking support 下:
1 | Networking options ---> |
[*] Enable the block layer 下:
1 | Partition Types ---> |
Device Drivers 下:
1 | Generic Driver Options ---> |
File systems 下:
1 | [*] Inotify support for userspace |
其他的都不用管。
由于 LFS 不使用 initramfs,所以尽量打包进内核,尤其是文件系统相关的不要打成模块。
配置完成,现在开始编译:
make
安装模块:
make modules_install
复制内核:
cp -iv arch/x86_64/boot/bzImage /boot/vmlinuz-5.13.12-lfs-11.0-systemd
此处的内核文件名称可以自行改变,但要以vmlinuz-
开头。
复制System.map
:
cp -iv System.map /boot/System.map-5.13.12
手册这里将配置.config
保存到了/boot
,但我是认为只要不删除源码,放源码树里就行了。
如果要复制配置的话,运行;
cp -iv .config /boot/config-5.13.12
安装内核文档:
1 | install -d /usr/share/doc/linux-5.13.12 |
因为不删除源码树要留以后用,而且源码树里可能有不属于root
的文件,现在要切出目录改变所有者:
chown -R 0:0 .
创建文件:
1 | install -v -m755 -d /etc/modprobe.d |
打开 UEFI 支持的 grub 需要文件系统efivars
。
因为需要文件/sys/firmware/efi/efivars
,而这个文件在非 UEFI 的机器上是不存在的,因此对于我来说需要将 LFS 硬盘迁移到目标机器挂载,现在就需要 live CD 了。
运行:
mountpoint /sys/firmware/efi/efivars || mount -v -t efivarfs efivarfs /sys/firmware/efi/efivars
然后安装 grub:
grub-install --bootloader-id=LFS --recheck
手动写入grub.cfg
:
1 | cat > /boot/grub/grub.cfg << EOF |
现在手册会创建一些描述文件,模板在这,不喜欢可以跳过:
1 | echo 11.0-systemd > /etc/lfs-release |
现在是时候重启了。
退出 chroot:
logout
解挂载:
umount -Rv $LFS
重启
reboot
至此,LFS 安装完成。
]]>这里使用 systemd-networkd 和 systemd-resolved
因为我需要远程登录,因此此处选择静态 ip:
这里还不知道目标机器网卡接口名,这个值可以用于大部分有线接口,其他参数自行替换。
1 | cat > /etc/systemd/network/10-eth-static.network << "EOF" |
创建一个符号链接:
ln -sfv /run/systemd/resolve/resolv.conf /etc/resolv.conf
创建/etc/hostname
:
echo lfs > /etc/hostname
创建/etc/hosts
:
1 | cat > /etc/hosts << "EOF" |
其中写着内网 ip 的那行自行修改。
这里使用硬件时钟,在最终重启后运行:
timedatectl set-local-rtc 1
创建/etc/locale.conf
:
1 | cat > /etc/locale.conf << "EOF" |
1 | cat > /etc/inputrc << "EOF" |
1 | cat > /etc/shells << "EOF" |
限制核心转储使用的最大磁盘空间(可选):
1 | mkdir -pv /etc/systemd/coredump.conf.d |
1 | cat > /etc/fstab << "EOF" |
这是我这台机器上的,参数需要自行修改。
至此,配置阶段结束,接下来就是编译内核了。
]]>1 | tar -xvf inetutils-2.1.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查,安装:
1 | make |
移动位置:
mv -v /usr/{,s}bin/ifconfig
1 | tar -xvf less-590.tar.gz |
1 | tar -xvf perl-5.34.0.tar.xz |
让perl
找到已经安装好的库:
1 | export BUILD_ZLIB=False |
configure
1 | sh Configure -des \ |
编译,测试,安装,清理环境变量:
1 | make |
1 | tar -xvf XML-Parser-2.46.tar.gz |
1 | tar -xvf intltool-0.51.0.tar.gz |
修复由perl-5.22
及更新版本导致的警告:
sed -i 's:\\\${:\\\$\\{:' intltool-update.in
构建:
1 | ./configure --prefix=/usr |
1 | tar -xvf autoconf-2.71.tar.xz |
这里检查也要开多线程,因为测试时间会很长。
1 | tar -xvf automake-1.16.4.tar.xz |
此处检查也要开多线程,而且时间要长的多。
1 | tar -xvf kmod-29.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译
make
该包的测试因为依赖git
,因此跳过。
安装该软件包,并创建与 Module-Init-Tools (曾经用于处理 Linux 内核模块的软件包) 兼容的符号链接:
1 | make install |
libelf 在包elfutils
中
1 | tar -xvf elfutils-0.185.tar.bz2 |
configure
1 | ./configure --prefix=/usr \ |
编译,检查:
1 | make |
我编译时此处会报错FAIL: run-backtrace-native.sh
。该错误已于 11 月 14 日提交于 Gentoo 的 bug 处理,但版本是 0.186。不过这里只需要libelf
,所以问题不大。
其实跳过就好了……
只安装libelf
:
1 | make -C libelf install |
该包构建时会对特定处理器进行优化。
1 | tar -xvf libffi-3.4.2.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查,安装:
1 | make |
1 | tar -xvf openssl-1.1.1l.tar.gz |
configure
1 | ./config --prefix=/usr \ |
编译,测试:
1 | make |
已知测试30-test_afalg.t
可能会失败,忽略即可。
安装:
1 | sed -i '/INSTALL_LIBS/s/libcrypto.a libssl.a//' Makefile |
为安装目录加上版本号:
mv -v /usr/share/doc/openssl /usr/share/doc/openssl-1.1.1l
安装额外的文档(可选):
cp -vfr doc/* /usr/share/doc/openssl-1.1.1l
还是一样的别解压错了。
1 | tar -xvf Python-3.9.6.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译,安装:
1 | make |
此处不建议测试,但如果一定要,运行make test
。
安装预先格式化的文档(可选):
1 | install -v -dm755 /usr/share/doc/python-3.9.6/html |
没错,就是另外一个 python-doc 包。
1 | tar -xvf ninja-1.10.2.tar.gz |
默认情况下,ninjia
会尽量使用多进程,且进程数是 CPU 逻辑核心数 +2,以下修改可手动指定线程数:
export NINJAJOBS=4
或者使用环境变量NINJAJOBS
:
1 | sed -i '/int Guess/a \ |
编译,测试:
1 | python3 configure.py --bootstrap |
安装:
1 | install -vm755 ninja /usr/bin/ |
1 | tar -xvf meson-0.59.1.tar.gz |
这个包没有测试。
需要打补丁。
1 | tar -xvf coreutils-8.32.tar.xz |
configure
1 | autoreconf -fiv |
编译:
make
测试(可选):
1 | make NON_ROOT_USERNAME=tester check-root |
安装:
make install
将程序移动到 FHS 要求的位置:
1 | mv -v /usr/bin/chroot /usr/sbin |
1 | tar -xvf check-0.15.2.tar.gz |
1 | tar -xvf diffutils-3.8.tar.xz |
1 | tar -xvf gawk-5.1.0.tar.xz |
确保构建时不安装某些文件:
sed -i 's/extras//' Makefile.in
构建:
1 | ./configure --prefix=/usr |
安装文档(可选):
1 | mkdir -v /usr/share/doc/gawk-5.1.0 |
1 | tar -xvf findutils-4.8.0.tar.xz |
1 | tar -xvf groff-1.22.4.tar.gz |
configure,并将默认纸张改为 A4:
PAGE=A4 ./configure --prefix=/usr
编译,安装,
此处编译强制-j1
:
1 | make -j1 |
因为使用 UEFI,因此手册的安装流程不适用。
对于 BIOS,这里给出命令(不包括解压):
以下安装命令不支持 UEFI !
1 | ./configure --prefix=/usr \ |
1 | tar -xvf gzip-1.10.tar.xz |
1 | tar -xvf iproute2-5.13.0.tar.xz |
不安装arpd
:
1 | sed -i /ARPD/d Makefile |
禁用两个模块
sed -i 's/.m_ipt.o//' tc/Makefile
编译,安装:
1 | make |
安装文档(可选):
1 | mkdir -v /usr/share/doc/iproute2-5.13.0 |
需要打补丁。
1 | tar -xvf kbd-2.4.0.tar.xz |
删除多余的resizecons
程序及其 man 页面:
1 | sed -i '/RESIZECONS_PROGS=/s/yes/no/' configure |
构建:
1 | ./configure --prefix=/usr --disable-vlock |
安装文档(可选):
1 | mkdir -v /usr/share/doc/kbd-2.4.0 |
1 | tar -xvf libpipeline-1.5.3.tar.gz |
1 | tar -xvf make-4.3.tar.gz |
检查是可选的。
1 | tar -xvf patch-2.7.6.tar.xz |
1 | tar -xvf tar-1.34.tar.xz |
configure
1 | FORCE_UNSAFE_CONFIGURE=1 \ |
编译,检查:
1 | make |
测试capabilities: binary store/restore
的测试可能会失败或跳过。
安装:
1 | make install |
1 | tar -xvf texinfo-6.8.tar.xz |
再次修复在使用 Glibc-2.34 或更新版本的系统上构建该软件包时出现的问题:
1 | sed -e 's/__attribute_nonnull__/__nonnull/' \ |
编译,检查,安装:
1 | make |
安装 Tex 组件(可选):
make TEXMF=/usr/share/texmf install-tex
重更新 Info 文档(可选):
1 | pushd /usr/share/info |
不会退出 vim 的去 BLFS 找其他编辑器
1 | tar -xvf vim-8.2.3337.tar.gz |
修改vimrc
配置文件的默认位置为/etc
:
echo '#define SYS_VIMRC_FILE "/etc/vimrc"' >> src/feature.h
编译:
1 | ./configure --prefix=/usr |
测试:
1 | chown -Rv tester . |
此处输出被重定向到了文件,要自行 cat。测试成功完成后,日志文件末尾会包含 “ALL DONE”。
安装:
make install
此处手册将vi
改为了指向vim
的符号链接。虽然大部分发行版会单独安装vi
,但毕竟现在没多少人会用vi
吧。
执行:
1 | ln -sv vim /usr/bin/vi |
创建文档的符号链接:
ln -sv ../vim/vim82/doc /usr/share/doc/vim-8.2.3337
加入/etc/vimrc
:
1 | cat > /etc/vimrc << "EOF" |
可根据自己喜好修改。虽然全局的这些就够了。
1 | tar -xvf MarkupSafe-2.0.1.tar.gz |
1 | tar -xvf Jinja2-3.0.1.tar.gz |
需要打补丁。
1 | tar -xvf systemd-249.tar.gz |
从默认的 udev 规则中删除不必要的组render
和sgx
:
1 | sed -i -e 's/GROUP="render"/GROUP="video"/' \ |
准备编译,包括创建build
:
1 | mkdir -p build |
编译,安装:
1 | LANG=en_US.UTF-8 ninja |
安装 man 页面:
tar -xf ../../systemd-man-pages-249.tar.xz --strip-components=1 -C /usr/share/man
删除不必要的目录:
rm -rf /usr/lib/pam.d
初始化 machine id:
systemd-machine-id-setup
设定启动目标单元的基本结构:
systemctl preset-all
禁用一个服务:
systemctl disable systemd-time-wait-sync.service
1 | tar -xvf dbus-1.12.20.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,安装:
1 | make |
该包有测试,但需要一些不安装的依赖。
创建一个符号链接:
ln -sfv /etc/machine-id /var/lib/dbus
1 | tar -xvf man-db-2.9.4.tar.xz |
cofigure
1 | ./configure --prefix=/usr \ |
编译,检查,安装:
1 | make |
1 | tar -xvf procps-ng-3.3.17.tar.xz |
这里解压出来的目录是procps-3.3.17
,不是procps-ng-3.3.17
。
configure
1 | ./configure --prefix=/usr \ |
编译,测试,安装:
1 | make |
检查是可选的,且已知五项与 pkill 相关的测试可能失败。
1 | tar -xvf util-linux-2.37.2.tar.xz |
configure
1 | ./configure ADJTIME_PATH=/var/lib/hwclock/adjtime \ |
编译:
make
测试(可选):
1 | rm tests/ts/lsns/ioctl_ns |
安装:
make install
1 | tar -xvf e2fsprogs-1.46.4.tar.gz |
创建build
:
1 | mkdir -v build |
configure
1 | ../configure --prefix=/usr \ |
编译,测试,安装:
1 | make |
已知测试u_direct_io
可能在一些系统上失败。
删除无用的静态库:
rm -fv /usr/lib/{libcom_err,libe2p,libext2fs,libss}.a
更新系统dir
文件:
1 | gunzip -v /usr/share/info/libext2fs.info.gz |
安装额外文档(可选):
1 | makeinfo -o doc/com_err.info ../lib/et/com_err.texinfo |
这是 efibootmanager 的一个依赖。
下载连接:https://github.com/rhboot/efivar/releases/download/37/efivar-37.tar.bz2
需要补丁,连接:https://www.linuxfromscratch.org/patches/blfs/11.0/efivar-37-gcc_9-1.patch
1 | tar -xvf efivar-37.tar.bz2 |
这是 efibootmanager 的一个依赖。
下载连接:http://ftp.rpm.org/popt/releases/popt-1.x/popt-1.18.tar.gz
1 | tar -xvf popt-1.18.tar.gz |
这是 GRUB 用于支持 UEFI 的一个依赖。需要单独从 BLFS 上下载。
下载连接:https://github.com/rhboot/efibootmgr/archive/17/efibootmgr-17.tar.gz
1 | tar -xvf efibootmgr-17.tar.gz |
修复一个编译时会遇到的错误:
sed -e '/extern int efi_set_verbose/d' -i src/efibootmgr.c
编译,安装:
1 | make EFIDIR=/boot/efi/EFI EFI_LOADER=grubx64.efi |
这也是一个 GRUB 的依赖……
而且虽然在 BLFS 里写着不是必须,但用 BLFS 的命令 configure 时会报错需要该字体。
下载连接:https://downloads.sourceforge.net/freetype/freetype-2.11.0.tar.xz
1 | tar -xvf freetype-2.11.0.tar.xz |
构建:
1 | sed -ri "s:.*(AUX_MODULES.*valid):\1:" modules.cfg && |
安装:
make install
这里需要一个字体文件。
下载连接:https://unifoundry.com/pub/unifont/unifont-13.0.06/font-builds/unifont-13.0.06.pcf.gz
1 | tar -xvf grub-2.06.tar.xz |
安装字体:
1 | mkdir -pv /usr/share/fonts/unifont && |
取消编译用环境变量(虽然没设置):
unset {C,CPP,CXX,LD}FLAGS
configure
1 | ./configure --prefix=/usr \ |
编译:
make
安装:
1 | make install |
毕竟大部分人都不会调试这些软件包吧。
1 | save_usrlib="$(cd /usr/lib; ls ld-linux*) |
该命令会报错一堆文件格式无法识别,可以安全忽略。
现在所有包都安装完成了。是时候清理了。
rm -rf /tmp/*
然后登出,重新 chroot:
logout
1 | chroot "$LFS" /usr/bin/env -i \ |
这次 chroot 参数有点变化,之后 chroot 都需要执行现在改过的命令。
接着清理:
1 | find /usr/lib /usr/libexec -name \*.la -delete |
最后,移除用户tester
:
userdel -r tester
至此,系统构建部分正式结束。
]]>每次登录,都要检查$LFS
:
echo $LFS
首先先挂载/dev
和内核虚拟文件系统
1 | mount -v --bind /dev $LFS/dev |
现在开始 chroot
1 | chroot "$LFS" /usr/bin/env -i \ |
1 | tar -xvf man-pages-5.13.tar.xz |
1 | tar -xvf iana-etc-20210611.tar.gz |
这个包只需要将文件复制到/etc
下即可。
cp services protocols /etc
这应该是最后一遍了吧。
1 | tar -xvf glibc-2.34.tar.xz |
此处需要修复一个安全问题:
1 | sed -e '/NOTIFY_REMOVED)/s/)/ \&\& data.attr != NULL)/' \ |
打补丁
patch -Np1 -i glibc-2.34-fhs-1.patch
嗯,手册现在才打 patch,可能是之前编译的都是临时用的所以不用打吧。XD
建立/build
1 | mkdir build |
确保将ldconfig
和sln
工具安装到/usr/sbin
目录中:
echo "rootsbindir=/usr/sbin" > configparms
configure
1 | ../configure --prefix=/usr \ |
编译:
make
检查:
make check
glibc 这么大的包,一共 4488 项测试,有几个错误很正常,如果只有几个错误的话忽略就行。此外手册已知会出现两个错误,分别是:
io/tst-lchmod
在 chroot 里会失败misc/tst-ttyname
在 chroot 里失败我就报了这两个错
安装时,可能会报错/etc/ld.so.conf
找不到,此错误无害,建立个空的就行
touch /etc/ld.so.conf
还要修正 Makefile 跳过一个检查
sed '/test-installation/s@$(PERL)@echo not running@' -i ../Makefile
安装
make install
改正ldd
脚本中硬编码的可执行文件加载器路径
sed '/RTLDLIST=/s@/usr@@g' -i /usr/bin/ldd
安装nscd
的配置文件和运行时目录:
1 | cp -v ../nscd/nscd.conf /etc/nscd.conf |
安装nscd
对 systemd 的支持
1 | install -v -Dm644 ../nscd/nscd.tmpfiles /usr/lib/tmpfiles.d/nscd.conf |
现在安装 locale。
手册提供的只能用于满足测试,简体中文是没有的。因此下面的命令我加了zh_CN-UTF-8
。
所以此处会使用安装单个 locale 的指令。
1 | mkdir -pv /usr/lib/locale |
当然也可以全部安装,不过需要的时间就很长了:
make localedata/install-locales
创建/etc/nsswitch.conf
:
1 | cat > /etc/nsswitch.conf << "EOF" |
安装时区数据:
注意:此时仍在 glibc 的build
目录下,如果在其他目录要根据路径改下列命令。
1 | tar -xf ../../tzdata2021a.tar.gz |
此处顺手配置时区:
ln -sfv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
现在还需要配置动态加载器。
创建一个新的/etc/ld.so.conf
:
1 | cat > /etc/ld.so.conf << "EOF" |
不过下面的命令可能会更优雅:
1 | cat >> /etc/ld.so.conf << "EOF" |
以上两个命令可以全部使用,因为第二个命令不会擦除原ld.conf.d
的内容
1 | tar -xvf zlib-1.2.11.tar.xz |
此处需要删除一些无用的静态库
rm -fv /usr/lib/libz.a
这里需要加补丁
1 | tar -xvf bzip2-1.0.8.tar.gz |
需要修改 Makefile 保证安装的符号链接是相对的。
sed -i 's@\(ln -s -f \)$(PREFIX)/bin/@\1@' Makefile
确保man
被安装到正确位置:
sed -i "s@(PREFIX)/man@(PREFIX)/share/man@g" Makefile
编译前还需要进行一些处理
1 | make -f Makefile-libbz2_so |
编译:
make
安装:
1 | make PREFIX=/usr install |
此处对其共享库进行了一些处理
删除静态库
rm -fv /usr/lib/libbz2.a
1 | tar -xvf xz-5.2.5.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查和安装
1 | make |
1 | tar -xvf zstd-1.5.0.tar.gz |
如果编译时出现 “failed” 时,那没有问题,只有 “FAIL”才是失败。但测试需要全部通过。
安装
make prefix=/usr install
删除静态库
rm -v /usr/lib/libzstd.a
1 | tar -xvf file-5.40.tar.gz |
1 | tar -xvf readline-8.1.tar.gz |
重新安装Readline
会导致旧版本的库被重命名为<库名称>.old
。这一般不是问题,但某些情况下会触发ldconfig
的一个链接 bug。运行下面的两条 sed 命令防止这种情况:
1 | sed -i '/MV.*old/d' Makefile.in |
configure
1 | ./configure --prefix=/usr \ |
编译和安装:
1 | make SHLIB_LIBS="-lncursesw" |
安装文档(可选):
install -v -m644 doc/*.{ps,pdf,html,dvi} /usr/share/doc/readline-8.1
1 | tar -xvf m4-1.4.19.tar.xz |
1 | tar -xvf bc-5.0.0.tar.xz |
这个
O3
就很灵性
1 | tar -xvf flex-2.6.4.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查和安装
1 | make |
添加一个lex
到flex
的符号链接
ln -sv flex /usr/bin/lex
这是三个需要用到的测试套件其中之一。
进入安装目录后,要解压文档,在解压源码时要注意区分。
1 | tar -xvf tcl8.6.11-src.tar.gz |
这里的 configure 有点特殊
1 | SRCDIR=$(pwd) |
编译,也有点特殊
1 | make |
测试
make test
已知测试unitInit-1.2
会失败。
但我测试时全部成功了
安装,并修改安装好的库的权限:
1 | make install |
安装头文件,这是等一会要安装的expect
的依赖
make install-private-headers
创建符号链接
ln -sfv tclsh8.6 /usr/bin/tclsh
最后修改一个与 Perl man 冲突的错误:
mv /usr/share/man/man3/{Thread,Tcl_Thread}.3
三个测试套件之二。
1 | tar -xvf expect5.45.4.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,测试
1 | make |
安装
1 | make install |
三个测试套件之三。
此处需要build
1 | tar -xvf dejagnu-1.6.3.tar.gz |
configure
1 | ../configure --prefix=/usr |
直接安装
1 | make install |
当然也可以测试,虽然没有必要
make check
这应该是最后一遍了吧。
1 | tar -xvf binutils-2.37.tar.xz |
同样需要对 pty 进行测试,该命令应返回spawn ls
:
expect -c "spawn ls"
手册在这里打补丁,其实在进入目录后就可以打:
patch -Np1 -i binutils-2.37-upstream_fix-1.patch
绕过关于man
的一个问题:
1 | sed -i '63d' etc/texi2pod.pl |
创建build
:
1 | mkdir -v build |
configure
1 | ../configure --prefix=/usr \ |
编译及测试
1 | make tooldir=/usr |
一定要运行测试!
已知四项与zlib
有关的测试会失败。
嗯,我全中。
安装,删除无用的静态库
1 | make tooldir=/usr install -j1 |
1 | tar -xvf gmp-6.2.1.tar.xz |
如果宿主机硬件是 64 位但安装的 OS 是 32 位,还有CFLAGS
变量时,需要运行
ABI=32 ./configure ...
取消处理器优化,生成通用库。(可选,且如果宿主机 CPU 与目标机一致就不用选,在 live CD 里编译也不用。)
1 | cp -v configfsf.guess config.guess |
configure
1 | ./configure --prefix=/usr \ |
编译并生成文档
1 | make |
测试:
一定要测试!
因为 GMP 编译时是针对 CPU 高度优化的,有时会错误识别 CPU 功能导致测试时大概率出现一堆Illegal instruction
。此时就需要重新编译并加上--build=x86_64-pc-linux-gnu
。
以下命令查看通过测试的数量,GMP 一共 197 项测试,务必全部通过。
awk '/# PASS:/{total+=$3} ; END{print total}' gmp-check-log
安装,包括文档
1 | make install |
1 | tar -xvf mpfr-4.1.0.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译并生成文档:
1 | make |
测试:
一定要测试!
make check
确保全部通过。
安装
1 | make install |
1 | tar -xvf mpc-1.2.1.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,测试和安装
1 | make |
1 | tar -xvf attr-2.5.1.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,测试和安装
1 | make |
1 | tar -xvf acl-2.3.1.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装:
1 | make |
acl
的测试依赖于连接了 Acl 的Coreutils,如果要测试,应在 Coreutils 构建完成后进行。
因此,构建完成后源码目录暂不删除。
1 | tar -xvf libcap-2.53.tar.xz |
防止安装静态库:
sed -i '/install -m.*STA/d' libcap/Makefile
编译,测试,安装
1 | make prefix=/usr lib=lib |
修改权限
chmod -v 755 /usr/lib/lib{cap,psx}.so.2.53
1 | tar -xvf shadow-4.9.tar.xz |
禁止该包安装groups
程序和它的 man 页面,因为 Coreutils 会提供更好的版本。
1 | sed -i 's/groups$(EXEEXT) //' src/Makefile.in |
不使用默认的 crypt 加密方法,使用更安全的 SHA-512 方法加密密码,该方法也允许长度超过 8 个字符的密码。还需要把用户邮箱位置/var/spool/mail
改为/var/mail
。另外,从默认的PATH
中删除/bin
和/sbin
,因为它们只是指向/usr
中对应目录的符号链接:
1 | sed -e 's:#ENCRYPT_METHOD DES:ENCRYPT_METHOD SHA512:' \ |
修复程序中的一处低级错误:
sed -e "224s/rounds/min_rounds/" -i libmisc/salt.c
configure
1 | touch /usr/bin/passwd |
编译:
make
安装:
1 | make exec_prefix=/usr install |
启用用户密码的加密
pwconv
启用组密码加密
grpconv
shadow
带了一个useradd
的默认配置文件,其中会为新用户创建邮箱文件,若关闭,运行
sed -i 's/yes/no/' /etc/default/useradd
passwd root
这一遍需要巨长的时间。
1 | tar -xvf gcc-11.2.0.tar.xz |
修复在使用 Glibc-2.34 的系统上构建该软件包时导致libasan.a
无法使用的问题:
1 | sed -e '/static.*SIGSTKSZ/d' \ |
修改 64 位库默认路径
1 | case $(uname -m) in |
创建build
1 | mkdir -v build |
configure
1 | ../configure --prefix=/usr \ |
编译:
make
增加栈空间
ulimit -s 32768
以非特权用户身份测试编译结果,但出错时继续执行其他测试:
1 | chown -Rv tester . |
查看摘要
../contrib/test_summary
已知错误如下:
analyzer
相关的测试会失败。 asan_test.C
的测试会失败。 libstdc++
中,已知一项名为49745.cc
的测试由于 Glibc 中头文件依赖关系的变化而失败。 libstdc++
测试中,一项numpuct
测试和六项与 get_time 有关的测试会失败。这是由于 glibc 更新了 locale 定义,但是 libstdc++ 尚不支持这些变化。 同时,还有少量错误是十分正常的,毕竟这是 gcc。 (
哪怕测试时间比编译时间还要长十倍也要坚持测试!
但时间真的太长了……我跑了近 5 个小时,然而编译只需要 30 分钟不到
安装该软件包,并移除一个不需要的目录:
1 | make install |
修正之前因为测试而临时更改的文件所有者
1 | chown -v -R root:root \ |
创建一个符号链接
1 | ln -svr /usr/bin/cpp /usr/lib |
现在工具链已经完成安装,需要进行一次完整的确认。
离开源码目录,然后
1 | echo 'int main(){}' > dummy.c |
如果正常,输出的最后一行会是(具体名称取决于平台)
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
然后
grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log
正常输出应该是这样:
1 | /usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib/crt1.o succeeded |
gcc
应该找到所有三个crt*.o
文件,它们应该位于/usr/lib
目录中。
确认编译器能正确查找头文件:
grep -B4 '^ /usr/include' dummy.log
这是正常输出:
1 | #include <...> search starts here: |
其中三元组的名称取决于平台。
确认新的链接器使用了正确的搜索路径:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
路径应该要包含
1 | SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64") |
当然 32 位的路径会有不同。
确认使用了正确的 libc:
grep "/lib.*/libc.so.6 " dummy.log
应该输出
attempt to open /usr/lib/libc.so.6 succeeded
确认 GCC 使用了正确的动态链接器:
grep found dummy.log
正常输出:
found ld-linux-x86-64.so.2 at /usr/lib/ld-linux-x86-64.so.2
如果有问题,一定要修复,不能硬着头皮往下做,不然更折腾人。
如果一切正常,删除测试文件:
rm -v dummy.c a.out dummy.log
最后移动一个位置不正确的文件:
1 | mkdir -pv /usr/share/gdb/auto-load/usr/lib |
1 | tar -xvf pkg-config-0.29.2.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查,安装
1 | make |
1 | tar -xvf ncurses-6.2.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,安装
1 | make |
这个包有测试,但需要安装后面的包,所以跳过。
创建符号链接:
1 | for lib in ncurses form panel menu ; do |
删除一个 configure 脚本未处理的静态库:
rm -fv /usr/lib/libncurses++w.a
安装文档(可选):
1 | mkdir -v /usr/share/doc/ncurses-6.2 |
注意:此处没有创建非宽字符的库,部分二进制包会依赖于它。
1 | tar -xvf sed-4.8.tar.xz |
测试:
1 | chown -Rv tester . |
我在检查时会报错:
inplace-selinux.sh: set-up failure: CONFIG_HEADER not defined
,看上去与 selinux 有关,不用 selinux 应该不受影响。
但具体原因未知。
安装:
1 | make install |
1 | tar -xvf psmisc-23.4.tar.xz |
1 | tar -xvf gettext-0.21.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查
1 | make |
测试时间会和编译时间一样长。
安装:
1 | make install |
1 | tar -xvf bison-3.7.6.tar.xz |
可以测试,不过时间有点长。(可选):
make check
1 | tar -xvf grep-3.7.tar.xz |
1 | tar -xvf bash-5.1.8.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译:
make
测试(可选):
1 | chown -Rv tester . |
安装:
make install
换 shell:
exec /bin/bash --login +h
1 | tar -xvf libtool-2.4.6.tar.xz |
测试,这里建议打开多线程:
make check TESTSUITEFLAGS=-j5
这里的线程数一般为逻辑 CPU 数 + 1。
已知会有5个因循环依赖导致的失败,但安装 automake 后可通过。
安装,删除静态库:
1 | make install |
1 | tar -xvf gdbm-1.20.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译,测试:
1 | make |
已知gdbmtool
测试会失败。
安装:
make install
1 | tar -xvf gperf-3.1.tar.gz |
这里开-j1
是因为多线程会导致错误。
1 | tar -xvf expat-2.4.1.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译,检查,安装:
1 | make |
安装文档(可选):
install -v -m644 doc/*.{html,png,css} /usr/share/doc/expat-2.4.1
至此,软件包安装完成过半。
剩下的下篇再继续。
]]>76 个包,属实是体力活……
lfs
到root
。su
吧。$LFS
:export LFS=/mnt/lfs
毕竟一个正常的系统其系统文件所有者不可能是lfs
1 | chown -R root:root $LFS/{usr,lib,var,etc,bin,sbin,tools} |
首先需要建立 dev,proc,sys,run 目录
mkdir -pv $LFS/{dev,proc,sys,run}
主要是null
和console
1 | mknod -m 600 $LFS/dev/console c 5 1 |
mount -v --bind /dev $LFS/dev
1 | mount -v --bind /dev/pts $LFS/dev/pts |
此外,还要创建一些目录
1 | if [ -h $LFS/dev/shm ]; then |
1 | chroot "$LFS" /usr/bin/env -i \ |
这时的 bash 会显示 I have no name,因为没有/etc/passwd
,这是正常的,虽然有点丑 :D
如果只是退出而不关机/重启的话,直接运行上面的命令就行,不然就要重新挂载这些文件系统。
不过建议每次 chroot 前都检查一次。
现在再创建一些还需要的目录
mkdir -pv /{boot,home,mnt,opt,srv}
其实有一些目录已经创建了,但这里为了防止遗漏手册还是加上了这些目录。
现在创建子目录
1 | mkdir -pv /etc/{opt,sysconfig} |
以上目录结构全部基于 FHS,但只加了必要的目录。
先加上从/etc/mtab
到/proc
的符号链接
ln -sv /proc/self/mounts /etc/mtab
然后是创建一个最简单的/etc/hosts
1 | cat > /etc/hosts << EOF |
其实这里的
$(hostname)
在其他发行版里是需要手动改的
创建/etc/passwd
:
1 | cat > /etc/passwd << "EOF" |
可以看出这里加上了 systemd 需要的用户。
创建/etc/group
:
1 | cat > /etc/group << "EOF" |
这里用户组的标准可以看作 LFS 自己的标准了,其中用户组可以根据需要自行修改。
现在需要创建一个之后的测试中需要用到的用户,不过是临时的,最后会删除。
1 | echo "tester:x:101:101::/home/tester:/bin/bash" >> /etc/passwd |
现在,赋予 bash 以名字(无故中二 XD):
exec /bin/bash --login +h
还要创建一些日志文件,虽然都是空的:
1 | touch /var/log/{btmp,lastlog,faillog,wtmp} |
至此,初步配置完成,现在该安装额外工具了。
你没理解错,以下部分全部都以root
用户编译。
在前面第二遍编译 gcc 时,并没有编译它,因为它不能用宿主机工具链编译。
1 | tar -xvf gcc-11.2.0.tar.xz |
创建一个符号链接
ln -s gthr-posix.h libgcc/gthr-default.h
建立build
目录
1 | mkdir build |
configure
1 | ../libstdc++-v3/configure \ |
编译和安装
1 | make |
这里只安装msgfmt
,msgmerge
,以及xgettext
这三个程序
1 | tar -xvf gettext-0.21.tar.xz |
1 | tar -xvf bison-3.7.6.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
此处要加一个 patch
1 | tar -xvf perl-5.34.0.tar.xz |
configure
1 | sh Configure -des \ |
编译和安装
1 | make |
这里有两个 python 包,Python-3.9.6.tar.xz
和python-3.9.6-docs-html.tar.bz2
。
解压前面那个,后面的那个包因为没安装bzip2
无法解压。
注意区分大小写。
1 | tar -xvf Python-3.9.6.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
这里有部分模块是无法编译的,但 make 还是会报错(还是 fatal error),这里只要最外面的 make 执行成功即可。
1 | tar -xvf texinfo-6.8.tar.xz |
在编译之前,需要修复在使用 Glibc-2.34 或更新版本时编译会出现的问题
1 | sed -e 's/__attribute_nonnull__/__nonnull/' \ |
之后
1 | ./configure --prefix=/usr |
1 | tar -xvf util-linux-2.37.2.tar.xz |
根据 FHS 的建议,使用/var/lib/hwclock
:
mkdir -pv /var/lib/hwclock
configure
1 | ./configure ADJTIME_PATH=/var/lib/hwclock/adjtime \ |
编译和安装
1 | make |
至此,额外的工具就构建完成了。
首先清理文档
rm -rf /usr/share/{info,man,doc}/*
之后是libtool
的*.la
文件
find /usr/{lib,libexec} -name \*.la -delete
最后删除/tools
,现在已经不需要了
rm -rf /tools
这是可选的,但小心一点总没错。
以下操作在 chroot 外进行,且使用root
用户。
exit
备份需要至少 1G 空间。
先解除内核虚拟文件系统的挂载:
1 | umount $LFS/dev{/pts,} |
按照手册默认路径,备份于/root
1 | cd $LFS |
需要还原时,运行
1 | cd $LFS |
运行前务必检查$LFS
是否正确设置!
不然你宿主系统就 gg 了,
rm -rf /*
了解一下。
至此,构建临时系统部分结束。
]]>首先当然是登录lfs
用户。
之后检查下$LFS
是否设置正确。
echo $LFS
之后,需要检查以下部分是否正确设置,虽然大部分都不需要刻意留意,但不排除像我这样有特殊习惯的用户会不满足以下条件。
/usr/bin/awk
符号链接到 gawk。/usr/bin/yacc
是到 bison 的符号链接,或者是一个执行 bison 的小脚本。此外,对于构建过程,不要把源码放在/mnt/lfs/tools
里,以免污染。
在没有特殊说明时,软件包的标准构建步骤如下
现在,就正式开始构建。
现在先把目录切到$LFS/sources
下。
先解压软件包
tar -xvf binutils-2.37.tar.xz
之后将 patch 放入目录并应用
1 | cp binutils-2.37-upstream_fix-1.patch ./binutils-2.37 |
现在需要确认 pty 能否在 chroot 环境里工作
expect -c "spawn ls"
如果不能显示spawn ls
的话,就说明环境没有为 pty 正常工作设置好。不过大多数情况下装expect
包就行了。
根据 Binutils 手册建议,创建build
目录:
1 | mkdir build |
进行 configure
1 | ../configure --prefix=$LFS/tools \ |
开始编译:
make
安装:
make install -j1
至于加上这个-j1
的原因,是为了规避 make 中的一个问题。
解压
1 | tar -xvf gcc-11.2.0.tar.xz |
此处 gcc 需要 GMP,MPFR 和 MPC 软件包,将源码解压进 gcc 目录并随 gcc 一起编译
1 | tar -xf ../mpfr-4.1.0.tar.xz |
对于 x86-64 的宿主机,将 64 位库的默认目录设为lib
1 | case $(uname -m) in |
设置build
目录:
1 | mkdir build |
之后是一段巨长的 configure:
1 | ../configure \ |
毕竟是交叉编译还是第一遍,这里对gcc关闭了一堆功能,主要是避免编译依赖标准库的代码
编译:
make
安装:
make install
此处还要补上limits.h
,具体原因是在第一次编译时,$LFS/usr/include/limits.h
还不存在,因此此时 gcc 安装的是不完整的,自给自足的头文件。虽然不加对于编译 glibc 已经足够,但后续步骤需要完整的内部头文件,因此此时手动将 gcc 源码中的相关头文件抽出。
1 | cd .. |
国际惯例进行解压
1 | tar -xvf linux-5.13.12.tar.xz |
这里只需要编译 glibc 用到的头文件,因此在确保目录里没有什么奇奇怪怪的东西(比如从其他地方 copy 进去的配置什么的)
make mrproper
之后再从源码中提取头文件然后手动复制到工具链目录下
1 | make headers |
最后还是一样的删除整个目录。
glibc 2.34 需要加一个 patch
1 | tar -xvf glibc-2.34.tar.xz |
需要创建符合 LSB 的符号链接
1 | case $(uname -m) in |
之后是创建 build 目录:
1 | mkdir -v build |
现在要确保ldconfig
和sln
被安装到了/usr/bin
echo "rootsbindir=/usr/sbin" > configparms
configure
1 | ../configure \ |
编译
make
安装
make DESTDIR=$LFS install
此处最好检查$LFS
,如果该变量是空的话 glibc 是会装的宿主机的。
此处要修复一个ldd
的硬编码错误:
sed '/RTLDLIST=/s@/usr@@g' -i $LFS/usr/bin/ldd
当上述包都安装完了之后,就需要检查工具链的基本功能能否正常工作。
找一个不会污染源码的目录,运行
1 | echo 'int main(){}' > dummy.c |
如果一切正常,就只会有以下输出
1 | [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] |
在 32 位机器上,解释器名字应该是/lib/ld-linux.so.2.
。
现在删除刚刚创建的文件
rm -v dummy.c a.out
现在用 gcc 的工具安装limits.h
$LFS/tools/libexec/gcc/$LFS_TGT/11.2.0/install-tools/mkheaders
虽然我在运行时会报错找不到文件,但
limits.h
确实安装到了目录include-fixed
里
第一次编译 gcc 时,因为没有 glibc,因此并没有编译 libstdc++,现在安装了 glibc 后就需要编译它了。
现在解压 gcc 目录并创建 build
:
1 | tar -xvf gcc-11.2.0.tar.xz |
之后是 configure
1 | ../libstdc++-v3/configure \ |
之后就是编译安装二连
1 | make |
现在只是编译安装了基础的工具链,在此之上还要安装一些额外工具。
虽然说这些工具是在chroot
之后用的,但现在就要编译。
1 | tar -xvf m4-1.4.19.tar.xz |
此处不需要build
目录。
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf ncurses-6.2.tar.gz |
首先要确保在 configure 时要找得到gawk
sed -i s/mawk// configure
之后需要编译tic
程序
1 | mkdir build |
之后**不要进入build
**,直接开始 configure
1 | ./configure --prefix=/usr \ |
编译
make
安装
1 | make DESTDIR=$LFS TIC_PATH=$(pwd)/build/progs/tic install |
1 | tar -xvf bash-5.1.8.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
加上sh
到bash
的符号链接
ln -sv bash $LFS/bin/sh
此处要加一个 patch
1 | tar -xvf coreutils-8.32.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译安装二连
1 | make |
此处需要移动部分文件的位置以适应有些硬编码的程序
1 | mv -v $LFS/usr/bin/chroot $LFS/usr/sbin |
1 | tar -xvf diffutils-3.8.tar.xz |
三连
1 | ./configure --prefix=/usr --host=$LFS_TGT |
1 | tar -xvf file-5.40.tar.gz |
这里的file
命令需要与宿主机上的版本一致,因此需要特殊编译
1 | mkdir build |
再进行三连,同样不要进入build
1 | ./configure --prefix=/usr --host=$LFS_TGT --build=$(./config.guess) |
1 | tar -xvf findutils-4.8.0.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf gawk-5.1.0.tar.xz |
首先确保不安装不需要的文件
sed -i 's/extras//' Makefile.in
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf grep-3.7.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf gzip-1.10.tar.xz |
1 | tar -xvf make-4.3.tar.gz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf patch-2.7.6.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf sed-4.8.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf tar-1.34.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
1 | tar -xvf xz-5.2.5.tar.xz |
configure
1 | ./configure --prefix=/usr \ |
编译和安装
1 | make |
这一次和第一次差不多,但有一些微妙的差别
1 | tar -xvf binutils-2.37.tar.xz |
configure
1 | ../configure \ |
编译
make
安装,并绕过导致libctf.so
链接到宿主发行版 zlib 的问题
1 | make DESTDIR=$LFS install -j1 |
1 | tar -xvf gcc-11.2.0.tar.xz |
还是一样的解压 GMP, MPFR 和 MPC
1 | tar -xf ../mpfr-4.1.0.tar.xz |
还是一样的设置 64 位库的符号链接
1 | case $(uname -m) in |
建立build
目录
1 | mkdir build |
创建一个符号链接以在构建libgcc
时启用对 posix 线程的支持
1 | mkdir -pv $LFS_TGT/libgcc |
configure
1 | ../configure \ |
编译和安装
1 | make |
一样的创建cc
到gcc
的符号链接
ln -sv gcc $LFS/usr/bin/cc
至此本文就到这里,接下来就要进行 chroot 了。
]]>11.0 的手册相较于 9.0 而言第二部分的内容实在是太多了……
不理解为什么要把 chroot 后的操作也要放在这一部分。
/dev/sdb
。 目前的分区方案如下
分区位置 | 大小 | 类型(挂载点) |
---|---|---|
/dev/sdb1 | 256M | EFI 分区 |
/dev/sdb2 | 4G | swap |
/dev/sdb3 | 剩余部分 | / |
现在采用 parted
进行分区
1 | # parted /dev/sdb |
分区完成后,接下来就是格式化。
目前,ESP 分区采用 fat32,根分区采用 ext4。
1 | mkfs.vfat /dev/sdb1 |
首先,根据 LFS 手册的要求,设置LFS
环境变量。
从现在开始,宿主机就要进入 root 进行操作了,当然理论上一直 sudo 也可以,但为了方便且预防一些奇奇怪怪的错误,还是进入 root 操作吧。
此处$LFS
的值为 LFS 根分区在宿主机挂载点的位置。
export LFS=/mnt/lfs
当然,也可以直接写在~/.bashrc
里,方便。
现在就可以挂载分区了。
再设置好$LFS
后,进行这些需要输入路径的操作就方便多了。
考虑到标准位置,把 ESP 挂载到$LFS/boot/efi
下。
1 | # mount /dev/sdb3 $LFS |
首先建立一个软件包存放目录,且这个目录 LFS 会要求打开粘滞模式。
1 | mkdir -v $LFS/sources |
这里使用 ustc 的镜像,镜像地址:
http://mirrors.ustc.edu.cn/lfs/lfs-packages/11.0/
本来要打算使用镜像里的 wget-list
,但是好家伙,打开一看地址都是源地址,完美镜像。
而且此时 LCTT 给的列表是9.0的……
不过好心的 ustc 给了 tar 包。
1 | # cd $LFS/sources |
此处对文件进行一些整理
1 | # mv $LFS/sources/11.0/* $LFS/sources/ |
此处也可以检查下 checksum。
该部分主要是设置目录,用户,环境变量等一系列配置。
建立一些之后编译安装软件包时会用到的系统目录。
但此处创建的目录并不完全。
使用下面的脚本,以 root 运行。
1 | #!/bin/bash |
还要建立一个存放临时工具链的目录。
1 | # mkdir -pv $LFS/tools |
相比于 9.0 的手册,11.0 版本少了将这个工具目录连接到
/
的操作,emmmmmm
毕竟在 root 下进行编译是十分危险的,创建一个普通用户很有必要。
虽说自用的用户就行,但在安装过程中还要设置一大堆环境变量,没人想把自己用户的环境变量搞得一团糟吧?
1 | # groupadd lfs |
此处创建用户的参数就根据自己的喜好了。
记得设置密码。
1 | # passwd lfs |
接下来要将 $LFS
的目录的所有权改为 lfs。
因为指南提供的是多行代码,因此使用脚本运行要方便些。
1 | #!/bin/bash |
当然这些目录的所有者后期是要改回来的,不然会出事情的。
同时软件包源码目录的所有者也要改
1 | # chown -v lfs $LFS/sources |
现在,就要登录 lfs 用户进行操作了。
如果要直接切换,使用su - lfs
。
首先在~/.bash_profile
里加上如下内容:
1 | exec env -i HOME=$HOME TERM=$TERM PS1='\u:\w\$ ' /bin/bash |
用于清除多余的环境变量。
之后再在~/.bashrc
里加上如下内容:
1 | set +h |
如果 lfs 使用了其他的 shell,需要根据具体 shell 确定写入的文件。
比如我用的是zsh,以上内容就要写到~/.zprofile
和~/.zshrc
里,同时 shell 的路径也要相应改动。
别无脑写进 bashrc,不然之后环境变量没配置成功还不知道呢。
最后,运行
1 | source ~/.bash_profile |
至此,准备部分结束。
]]>其实一开始要搭建 LFS 时,我是拒绝的。
但奈何自己手贱加学校的教务系统出问题,我同时选择了操作系统和操作系统课程设计。
而正常情况下是不能同时选择的。
而操作系统课程设计的大作业,就是搭 LFS。
也罢,这也是我的终极目标,虽然早了点,时间还被一大堆大作业和实验报告占满了,还有 ddl 催命。
于是,我就只能硬着头皮上了。
秉承要安装就要最新版的原则,我选择了最新的11.0
对了,是 systemd 版本的。
不过根据现在 LCTT 的进度,中文版最新到 9.0,因此 11.0 的版本只能硬啃生肉。
当然,不同版本之间差距应该并不大,所以我会参考中文最新版的就是了。
也许这一波流程后我就可以去 LCTT 翻译文档了吧。 XD
首先,当然是一份 LFS 文档(
对于 LFS 的搭建,需要一个宿主机,目前选择为我现在在服务器上跑的 Gentoo 开发机。当然也可以选择用 liveCD,不过考虑到 LFS 要装很长时间,liveCD 并不好用。
至于要安装的机器,当然是虚拟机啦,配置如下:
考虑到兼容性,目前不使用任何半虚拟化驱动
LFS 的安装一般分为以下几个流程:
具体流程其实和安装 Gentoo 差不多,但 LFS 既不会帮你自动编译也不提供 stage。可谓是真·从零开始。
我在安装 LFS时,不会完全按照文档进行。
首先,我可能会使用一些其他发行版的工具,比如 Gentoo 的 genkernel 之类的(虽然这玩意真的很难用)
以及我会大量使用已经存在的配置文件,比如其他发行版的 fstab 等
我也会参考 Gentoo 或 Arch 等相关 wiki,毕竟这些文档可是相当好用的。
撒,开始吧。
]]>PVE 7.0 已经添加了 TPM 支持,只需在 Web 界面添加设备即可。
本文已经过时!
本文已经过时!
本文已经过时!
虽然 Windows 11 的镜像早就泄露了,但在 6 月 24 日 23 点 Microsoft 才正式发布。发布会结束后,MS 官网放出了 Windows 11 的系统要求,其中一个必须要求是 TPM 2.0。
然而,Proxmox VE 并没有官方支持 vTPM , 虽然有qemu 有相应支持,但网上对此的文档很少。因此,本文在此写出让 PVE 支持 qemu vTPM 的方法以在虚拟机安装 Windows 11 预览版。
目前,qemu 已经通过 swtpm 支持了 vTPM ,但Proxmox 对此的支持还在开发中,并且预期时间未知。(Proxmox 工作人员的最近回复在今年 1 月。)
但可以安装 swtpm 并手动改配置文件,就是有亿点麻烦。
具体情况见这里。
不过 PVE 对 qemu vTPM 支持的要求已经上 bug 追踪列表了。耐心等吧,总会有的。
Bugzilla – Bug 3075
swtpm 有一个依赖 libtpms 也需要单独编译安装,这里也一起安装了。
swtpm 的源码:
git clone https://github.com/stefanberger/swtpm.git
libtpms 的源码:
git clone https://github.com/stefanberger/libtpms.git
查看分支
$ git branch -a
签出时选择最新的稳定版即可。
在写这篇文章时最新版是0.6
$ git checkout stable-0.6
(这是签出 swtpm 的命令,libtpms 请自行选择版本)
安装依赖:
sudo apt-get -y install automake autoconf libtool gcc build-essential libssl-dev dh-exec pkg-config gawk
编译:
1 | ./autogen.sh --with-openssl |
之后回到父目录,就可以看见 libtpms 的 deb 包了。
安装:
sudo dpkg -i libtpms0_0*_amd64.deb libtpms-dev_0*_amd64.deb
安装依赖:
sudo apt-get -y install libfuse-dev libglib2.0-dev libgmp-dev expect libtasn1-dev socat tpm-tools python3-twisted gnutls-dev gnutls-bin libjson-glib-dev python3-setuptools softhsm2 libseccomp-dev
编译:
dpkg-buildpackage -us -uc -j$(nproc)
编译完成后,编译父目录会生成很多包,其中以下几个包是最终使用的:
libtpms-dev_*_amd64.deb
这个应该是 swtpm 的编译依赖,但还是装在生产环境上吧,我也不清楚。libtpms0_*_amd64.deb
swtpm-libs_*_amd64.deb
swtpm_*_amd64.deb
swtpm-tools_*_amd64.deb
其它的包就不用装了,用于 debug 的。
已经有人写好一键安装脚本了,在这里:
rayures/vTPM
仅用于 Debian/Ubuntu。
portage 中是有 swtpm 的 ebuild 的,但被~amd64
mask 了。
因此,生产环境慎用!!!
将 keyword 加入 /etc/portage/package.keywords
=app-crypt/swtpm-0.5.2 ~amd64=dev-libs/libtpms-0.8.3 ~amd64
此时运行
sudo emerge --ask swtpm
即可。
首先当然是把编译好的 deb 包装到 PVE 上。
记得用dpkg --info
看看依赖,尤其是swtpm-tools
。
在安装swtpm-tools
时注意先安装它的依赖,不然 dpkg 后再安装依赖的话就会出现循环依赖。
swtpm 可以通过套接字/字符设备/CUSE 让 guest 访问 TPM。
此处使用这个脚本创建套接字设备:
1 | #!/bin/bash |
之后应该可以在/tmp/
下看见设备。
获取 VNC 端口号:
我也不知道这是什么,但后面添加参数需要这个数字,求大佬告知。
1 | #!/bin/bash |
之后再虚拟机配置文件里加一行:
args: -drive file=${disk},format=raw,if=virtio,cache=none -chardev socket,id=chrtpm,path=/$tpm/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 -vnc :$nextvnc -m 2048
${disk}
为虚拟机磁盘镜像路径,$tpm
为 tpm 设备路径,$nextvnc
是上面脚本的输出。全部为绝对路径。
启动虚拟机,就可以再 sealBIOS 里看到TPM 设置了。
脚本不是我写的,原帖在这里:
S3hh’s Blog
但该脚本似乎无法直接使用,于是我把它拆成上面的几个脚本和操作。
进行上述操作后,如果将虚拟机以裸机启动后再强行关机,会导致无法再启动,需要重新创建设备。
]]>其实 PVE 虚拟机创建向导很舒服,在一般情况下照着来就行。但对于 Gentoo,从这里开始就有坑了。
首先是 CPU,这个虽然不是坑,但这是我的一个小小的建议,将 CPU 类型设置为 host。毕竟由于 Gentoo 的特性,可以针对 CPU 进行优化,对于像好好玩 Gentoo 的人来说,个人认为这一点蛮重要的。而且由于要编译嘛,CPU 性能能榨干一点是一点。
此外就是各驱动了。千万不要选 VirtIO 驱动!除非你第一次安装就自己配置内核而且不使用 genkernel 生成的 initramfs。
因为以前被坑过无数次了,所以这次第一次安装我选择 genkernel 直接搞定。而 genkernel 在不加参数的情况下是不会选中任何 virtIO 相关选项的……(这是我后来才知道的)。所以如果不想被 genkernel 坑死的话就不要上 virtIO 驱动,至少安装系统时不要选。
本文不会完整记录安装 Gentoo 的流程,因为相比于我自己写的,官方的安装手册要专业得多。而对于大多数流程来说,参考手册就行了。
此外,相比几年前 Gentoo 安装手册中的不完整而且烂的翻译,现在的中文手册已经看不到英文了,而且中文的翻译质量也不差。所以大可以安心照手册安装,不会有什么让人摸不着头脑的地方的。
此处为安装手册的链接:Gentoo AMD64 Handbook 感谢每一位翻译贡献者的努力!
由于我本次安装使用的 init 是 systemd,而手册默认是为 openRC 准备的,因此我会写下不同于手册的,有关于 systemd 的配置。
如果要用 systemd 的话,记得选带 systemd 的 stage3。
虽然使用 openRC 的也行,但是切换完配置后会下载编译 systemd 及其相关依赖,挺耗时间的。
对了,建议到镜像站下载,比如 tuna。
由于 PVE 默认使用 SeaBIOS,所以就不用 ESP 了。但如果硬盘使用 GPT 的话记得加一个 BIOS 启动分区。
如果你使用的是最新的 stage3 而且类型选择正确的话,这一步是可以跳过的。不过保险起见,还是用eselect profile list
看一眼吧。
如果你发现系统默认的配置文件不是你想要的话,恭喜你,你多半选错 stage3 了!但其实也没什么,重新选择配置就行了,就是要多等一会了(指至少 1 小时,具体时间取决于机器配置,XD。
在更改/etc/locale.gen
,运行locale-gen
后,最后的选择 locale 就不能按照手册来了。直接修改/创建/etc/locale.conf
,在里面输入LANG="en_US.utf8"
即可。
此处非常不建议选择有关 zh_CN 的任何 locale。除非在安装时就安装好了桌面环境并确保一旦重新启动就能进入桌面,不然就等着满屏幕的口口口吧。
如果在这时配置 kernel 也是可以的,但我更喜欢在系统能正常使用的时候再折腾,所以使用 genkernel 一条龙服务吧。
而如果选择 genkernel 的话,之前的驱动选择就十分重要了。当然,如果你和我一样在安装时选择了 virtIO 驱动,很快就会看到我之前被卡了无数次的错误,以及 genkernel 对于 virtIO 无尽的坑。
systemd 需要一个 machine ID,运行systemd-machine-id-setup
。
对于主机名,直接在/etc/hostname
写就行了。默认该文件是自己创建的,所以看到 nano 显示是新文件时不用惊慌。
对了,记得把/etc/hosts
中的localhost
改为自己的主机名。
如果使用 dhcp 的话,记得重启后一波systemctl enable dhcpcd.service
和systemctl start dhcpcd.service
二连就行。
但如果你和我一样使用静态 IP 的话,就不能使用 dhcpcd 了。
其实按照 wiki,是可以使用 dhcpcd 配置静态 IP 的,但我尝试了没成功。
此处使用 systemd-networkd 配置静态 IP。在/etc/systemd/network
下创建 network 配置文件,比如下面的配置文件20-wired.network
:
1 | [Match] |
记得把Name
改为自己的网卡名称。
对了,重启后也要进行systemctl enable systemd-networkd.service
与systemctl start systemd-networkd.service
二连。
因为 systemd 已经自带了,所以手册关于安装日志工具的部分跳过就好。
如果你和我一样在安装时 scsi 控制器选择了 virtIO 驱动时,就会在开机时看到以下类似错误:
1 | /dev/loop0: TYPE="squashfs" |
并且只能进入紧急命令行。
不要急,进入紧急命令行,看看/dev/
下有什么。
如果我没猜错,安装根文件的 sda,要么不见了,要么变成了 hda。
对于我的情况,是直接不见了。
这种情况一般是 scsi 控制器出问题了,而且多半是驱动问题,导致根文件所在的硬盘无法加载。
而我的情况是,内核没有打入任何 virtIO 驱动,initramfs 也没有。
这就是 genkernel 对于 virtIO 的巨坑,因为它对 genkernel 支持不佳,内核编译时不会选中相关选项,就算自己选上了,在制作 initramfs 时也不会打入 virtIO 相关模块。
如果想要 genkernel 加上 virtIO 选项以及在 initramfs 中打入相关模块,请加上--virtio
的选项。
同时,要自己配置内核时,也要选中 virtIO 的相关选项。
具体可参见User:Flow/Gentoo as KVM guest
当然,用 QEMU 加上 WebVirtMgr 自己糊一个 Hypervisor 也是可以的,我之前本来要使用这个方案的。
但毕竟稳定性最重要,而自己糊的肯定比不上专业的,而且看了看 PVE 的手册后……真香。
本 Blog 不会写出完整安装过程,只有在安装时的注意事项和各种坑。毕竟安装这玩意就比安装 Debian 复杂一点,看手册就行了。
推荐这篇 Proxmox VE 6.2 的翻译版手册,虽然是 6.2 版本稍微有点老,但可参考性还是不用担心的。
这里是链接:Proxmox6.2中文手册
在此感谢翻译该手册的大佬。
HPE Gen 10 Plus 具有网络挂载 ISO 的功能,直接提供 ISO 的 URL 就行了。但这功能只有在网速极快(比如千兆/万兆内网内有装有 ISO 的 NAS)的环境下才有意义。
如果在大多数情况下使用该功能的话,就是一杯茶,一包烟,ISO 载入看一天了。
因为这个功能是直接挂载,而不是下载到本地再加载。
毕竟想想也是,硬盘都还没分区表呢下载的文件放哪?
天真的我之前一度以为这功能是自动下载后在加载……蠢哭了。
所以老老实实做启动 U 盘吧。记得插在机器后面的 USB 插槽上。
当然,从 Debian 上安装 Proxmox VE 也是可以的,但此处不过多说明,详情请见手册。
Proxmox VE 的分区设置很奇怪,坑也很多,所以我也没研究透,但此处我在此写下我遇到的坑以及些许建议。
首先,安装 PVE 时,只能在一块盘上进行分区,所以像我这样有多硬盘的数据盘在安装完成后再分区吧。
在选择分区硬盘的旁边有 Options 的高级设置,可以设置分区的文件系统,但此处不建议改动,最多取消掉 swap 分区(此机器的 Hypervisor 上使用 swap 没有意义,尤其是我上了 32G 内存),除非你知道自己在做什么。
在 PVE 的默认分区方案下,硬盘会分别生成一个 bios 启动分区,一个 EFI 分区,剩下的空间会被划分为叫做 pve 的 lVM 卷组,里面是 root, data, swap 逻辑卷。
对于 data 卷,该分区就是 PVE 存储各种数据的分区,在安装后的管理界面上有两个卷,分别是 local 和 local-lvm,就是在 data 卷里的。其中 local 卷存储各种 ISO 镜像和容器模板,而 local-lvm 则存储虚拟机硬盘和容器。
如要取消 swap,则将 Options 中的 swapsize 设置为 0。
当然,在多硬盘情况下,可以取消 data 卷,将 maxvz 设置为 0 即可(但我没试验过,慎用)。
别问我为什么会同时有 bios 启动分区和 esp,我也不知道。
PVE 的地点设置不是选择的,需要自己输入,输入 China 就好。
对于时区,选择 Asia/Shanghai 或 Asia/Hong_Kong 都行,都是 GMT+8。
PVE 的网络管理界面地址默认是本机 IP:8006,开机后机器如果链接 tty 的话会显示这个地址。
在 PVE 的管理界面,设置用户很简单,但在我的使用场景下,只用 root 就足够了。如果有多个用户要维护 PVE 的话,可以看看 PVE 复杂的权限系统。
管理界面创建 zpool 储存池也很方便,单盘创建 zpool 或创建 raidz 都不难,还可以设置各种参数和选项,比如我就打开了压缩功能。
对了,zpool 创建时是以硬盘为单位,创建 zpool 需要至少一块硬盘。
此外,ZFS 对内存的要求很高,现在推荐的使用 ZFS 的最小内存容量为基础 4G,zpool 总容量每 1T 额外加 1G。
而且 ZFS 在使用时会将大量内存用作缓存,我的机器平时运行就用了 20G+,而其中虚拟机的内存一共 10G。不过可以设置 ZFS 的内存使用上限,在 /etc/modprobe.d/zfs.conf 中输入options zfs zfs_arc_max=[number]
即可。[number]
为你想要设置的上限。
当然,也可以为储存池设置 SSD 缓存盘或 ZIL 日志盘,比如在我的分区方案下,SSD 上不设置 data 卷,剩余空间作为缓存盘,可以改善 ZFS 的性能。
]]>但我还是想把一部分虚拟机硬盘放在 SSD 上。
这是 HPE Gen 10 Plus 正面:
前面板背后是四个横置的硬盘柜,面板上铭牌处的凹槽其实是个提手,往外一拉就可以拆卸。在外壳打开后侧面会有两个卡扣用以锁定前面板防止在正常使用时把面板抽出来(虽然可能性很小)。左下角是两个 USB3.2 接口,而且据称在后面的 USB 插槽还有空余的时候就不会识别插在这两个端口的 WTG 设备。
具体可以参考这篇文章:[整机搭建] <更新软件篇>HPE ProLiant MicroServer Gen10 Plus 开箱与扩展
主机的背后是风扇和各种插槽。包括四个 USB 2.0 插槽,一个 VGA 接口,一个 DP 1.0 接口,四个 RJ45 端口,速度应该是千兆。此外还有两个预置插槽,但上面的是 ILO 网卡预置的,下面的才是标准 PCI-E。
机身背后有两颗手拧螺丝和两颗涂黑的螺丝。卸下手拧螺丝后就可以卸下外壳,但只有在卸下那两颗黑色的螺丝后才能抽出主板。
整台机器的所有螺丝都是六角形的,但有一字刻痕,所以没有六角螺丝刀的话也可以试试大一些的一字螺丝刀。
这是抽出主板后的侧面照:
上面的内存就是用了国产颗粒的光威奕 Pro:
包装也是充满中国风的:
硬盘柜是标准 3.5 英寸的。不过当我把硬盘插在上面的口时,硬盘一晃一晃的,有点糟心。不过范围很小,只要不是天天搬机器玩应该问题不大。
不过如果要插 2.5 英寸的硬盘就只能买硬盘盒了。不要买硬盘支架! SATA 接口是固定在硬盘柜内侧的,而一般的支架是为用连接线的硬盘柜而设计的,如果非要装的话,硬盘柜的接口与硬盘接口会有近 1 厘米的偏差。老老实实买硬盘盒吧,别贪便宜。
主机上的 ILO 不是直接能用的,按正常方法,开启 ILO只能插专用的 ILO 网卡。这玩意在某宝/某鱼上不到 50 块就能买。
但,也有邪门的方法。
根据这篇文章,只需短接两个端口,就可以以共享网卡的形式使用 ILO。如果动手能力强的话,可以在槽内插铜线或者飞线,不过前者不稳定后者要改回来又太麻烦。
于是有位老哥自己画了一个破解卡的 PCB 设计图,送去嘉立创 5 块钱就可以激活 ILO。这是原帖:
[NAS] HPE MicroServer Gen10+ ILO5破解卡制作方式共享,包括电路板文件
这是我自己下单的成品:
也就是说 ILO 控制芯片是集成在主板内的,那个 ILO 网卡里只有一个网卡模块。
反正我觉得这个网卡纯属智商税……
在设置 ILO 前,路由器要先分配静态 IP,毕竟没人想每次登录都要进路由器看看 IP 不是?
开机按 F9 和 F10 都可以进入 BIOS。不过按 F9 是直接的 BIOS 界面,F10 进入的是 Intelligent Provisioning 界面。后者界面更友好也支持鼠标操作。有鼠标的话建议后者。
如果使用共享端口的话,请注意这个端口只能是端口 1 或 2 而且默认是 1。
搭建 Home Lab 的想法,起源于我有一次运行虚拟机的时候。
虽然我现在的主力笔记本性能不差,16G 内存 + 256G SSD,但众所周知 Chrome 是著名的性能消耗大户,导致我的内存有一半被它吞了;而且由于笔记本上安装的重型软件和游戏实在太多了,尤其是游戏,占了 60G+ 的空间,导致剩余硬盘空间捉襟见肘。因此每一次使用虚拟机时,都要扣扣索索的盘算着分配的内存和虚拟磁盘的容量。更令人恼火的是,每次创建虚拟机,都要删掉一个游戏或者是占用了大量磁盘空间的软件,而且每次跑虚拟机只是测试一下而已,没过多久就要删,而删去虚拟机的时候再去下载这些程序是十分痛苦的事情。因此我便产生了专门买服务器跑虚拟机的想法。
而搭建 Home Lab 的另外一个原因,是因为折腾。
曾经我一直在一台 10 年前购入的 Lenovo 笔记本上跑 Gentoo,但由于各 种 各 样的原因,Gentoo 一直没安装成功,这称为了我心中的一根刺;而且我手头缺少一台 Linux 开发机,虽然 WSL 已经能满足大部分需求,但有些东西是 WSL 做不到的。而搭建一台 Home Lab,能做到All in One,开发机什么的将不再是问题。
虽然缺少 Linux 开发机是一个伪需求……
既然要选择买服务器搭建 Home Lab,那就一步到位吧。
那我对 Home Lab的需求是什么呢?
本人学生党,对硬件的选择自然是越便宜越好,但在金钱与性能之间权衡是一件很痛苦的事情。死来想去,确认了如下方案。
看了几个月,最终确认了购入服务器的型号:HPE ProLiant MicroServer Gen10 Plus。
为什么要选择这台机器呢?
我的机器是在闲鱼上买的二手未开封机器,相比与狗东上 6000+ 的价格,闲鱼上的价格只有三分之二,而且和全新的没区别。(除了容易被坑,毕竟虽然只有三分之二还是 将近 4000 RMB,被骗了就真的难受了。)
内存本来是准备一条 16G 的,但下单的时候没注意买成了两条,于是变成了 32G。型号的光威奕 PRO,国产颗粒。虽说支持国产是一个因素,但更重要的原因是便宜。
至于硬盘,由于要建 NAS,硬盘不敢买差的,于是选择了 2T 的希捷酷狼和一个金士顿的 128G SATA SSD 用作系统盘。
由于要开各种网络服务,一个路由器是很有必要的,但只需要有就行了。不过由于需要校园网拨号,于是买了一个二手小娱 C3 刷 Open WRT,不到 100 RMB。
曾经我打算在主机上直接装 Gentoo,其他的开虚拟机,但毕竟实验/开发环境天天挂,最后还是选择在主机上装 Hypervisor,各种服务跑虚拟机上的方案。这个 Hypervisor 将同时运行至少两台虚拟机,NAS 和开发机。有时还要同时运行测试机和跑各种 docker/LXC 的虚拟机。
Hypervisor 我最终选择了 Proxmox VE。这玩意如果不订阅每次登录都要弹警告很烦人,因此我曾一度打算装 kvm 和 qemu 自己糊,但实际用起来后我直呼真香。NAS 我选择了OpenMediaVault,开发机不用多说自然是 Gentoo。
我们先尝试直接打开main.lua:
???
lua不是门脚本语言吗,为什么像用记事本打开二进制文件一样的全是乱码?
一通Google之后,我发现原来lua是可以编译为字节码的,编译后文件叫做luac。
那么反编译不就行了?
于是我用unluac反编译时,得到了这个:
意思是这不是luac文件喽?
二进制文件的文件头都会标注文件类型,那用16进制编辑器打开看看:
没有文件头?
既然没有文件头,程序却能以lua文件运行,那只能说明被加密了。
但我在外壳程序怎么都找不到解密的代码。
绝望的我只好上知乎寻找已经逆向成功的大佬。
幸好,一位好心的大佬一语点醒梦中人:
请无视那个“2条回复”。第二条是我成功后对他的感谢
那意思是这个apk和去年那个几乎一样喽?
不管了先试试吧。
于是经过一下午的百度后,我找到了这篇文章:
这位博主根据壳里的解密代码写了一个程序:
1 |
|
按照这篇blog的使用方法,编译后运行,果然成功解密了。
那么就能成功反编译了。
以下是main.lua反编译后的代码:
1 | local L0, L1, L2, L3 |
别问我那些L0,L1哪来的,这是unluac自己加的,而且我也懒得修饰了。
以下是同文件夹内的另一个lua文件init.lua:
1 | local L0, L1 |
关于这个app与去年“927”中那个app的区别,我会在后面说明的。
下一篇我们来逆向另外一“存档人物修改2.0.apk”
1 | . |
1 | . |
mc.mp3
就是O泡果奶的广告音频。我们打AndroidManifest.xml,查看apk包名等信息。
AndroidManifest.xml文件如下:
1 |
|
可以看到作者把ID留在了versionName
里,心够大的。
以及可以看到申请的权限只有储存权限,这样看来估计没有窃取信息等行为了。
不过
package="com.lc.nb"
凉城NB!(个鬼)
下载好Jadx后,用它打开这个apk
看,一键反编译,自动反混淆!
文件里有很多第三方包,看上去很可疑。
注意AndroidManifest.xml中的这一个标签:
1 | <activity |
可见入口文件在com.android.Main
中。
那么打开看看:
确定了,这是AndroidLua应用,而/asset
中的lua脚本才是本体。
OK,先到这里,下次我们重点解析作为本体的lua文件。
当我关注到这个app时,是我一个现居异地的朋友发的一条说说。
其实早在几个小时前,宿舍里放出O泡果奶广告的声音时,我就体会过这个app的威力了,但我以为它只在我们学校内传播。
直到我看见了那条说说。
当我顺手转发了之后,十多条评论纷纷抱怨他们的经历,我一个朋友还给我发了他们大学流传的apk,我逐渐意识到不对劲。
但真正使我打算认真分析这个app的,是我另一个朋友让我发这个apk的hash的消息。
于是,我便走上了逆向工程之路。
不同地方流传的apk,名字可能会不一样。就比如我手上的两个apk:“一份礼物.apk”和“存档人物修改2.0.apk”,要验证这两个apk是否是同一个,就只能比对hash。
这是“一份礼物.apk”的hash:
这是“存档人物修改2.0.apk”的hash:
显然二者不是同一个apk。
后来跟朋友的hash比对,“一份礼物.apk”的hash与他的一致。
注:以下内容大部分参考了这篇post,这篇post讲的比我清楚多了,人家是专业的。
Github Actions是Github自己推出的持续集成服务,可以自动地进行各种各样的构建并发布到正确的地方。
在本Blog中,我就使用了Github Actions来自动构建Hexo的静态网页并将它发布到Github Pages上。
这些构建,发布之类的操作,在Github Actions中被称为actions。用户可以将actions写成独立的脚本并供给其他人使用。Github建立了一个官方市场,可以找到我们需要的actions。
打开你的Github 账户设置页,转到Developer settings -> Personal access tokens,生成时记得勾选repo项,admin:repo_hook和workflow项。
之后复制生成的字符串,回到hexo仓库,打开仓库设置,转到Secrets,把字符串以环境变量的形式存储。变量名凭喜好自取。
首先我们在GitHub打开Hexo的仓库,转到actions选项。
根据网页的提示,建立一个workflow。这样你就会进入一个编辑.yml文件的界面,文件就是workflow的配置文件。
这时在右边有市场界面,让我们在里面搜”hexo”,可以看到许多发布hexo博客的actions,这里我选择的是hexo-deploy,选择版本,将代码框的内容粘贴到workflow文件中,按注释改一下配置,保存。
根据actions的不同,所需要的token/key类型也不同。有的使用Personal Access Token(PAT),有的使用ssh key,具体看action的说明。
我倾向于使用PAT,因为PAT只用存储在hexo仓库上。相比之下,用ssh key需要将公钥放在hexo仓库,私钥放在pages仓库,较为麻烦。
将hexo仓库push一下,actions就会自动运作,几分钟后Blog就可以访问了。
]]>在这里下载,然后一路安装。
包管理工具,请。
npm install hexo-cli -g
首先,在本地见一个文件夹,名字最好是英文,然后
npx hexo install <folder>
之后
cd <folder>
最后
npm install
一个Hexo文件夹就这样初始化好了。
其实是不需要的,我只是好奇而已。
当然,之后这个操作是非常重要的,你可以把它当作熟悉Hexo操作。
首先,让Hexo生成静态网页
npx hexo generate
然后,启动Hexo的本地服务
npx hexo server
之后就可以访问localhost:4000访问本地的网页了。
如果你不知道什么是git, Github,你现在就可以把本Blog关了。
在Github上,建立一个名为\<username>.github.io
的仓库,然后放着。
之后,Hexo文件夹用git初始化,commit之后push到Github。
OK,其余的操作就主要在Github上进行了。