同步操作将从 deepinwiki/wiki 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
这一个项目的目的是使用国产的构建工具 xmake,从头构建起 LFS。所谓 LFS 是让用户构建自己的 linux 发行版。
对的,你可以用市面上存在的 linux 发行版,如 ubuntu、debian、gentoo、centos、fedora、redhat、deepin、uos、arch等等,也能自己从头定义一个 linux。毕竟 linux 和其组件大部分都是开源或者可以免费得到的。
不使用每个组件自身的构建系统,而是使用 xmake 来构建他们。这样有什么好处?我希望得到一个统一的、和谐的构建系统。将来用户不需要费劲心思去学习不同构建系统之间的差异,而只是使用同一个易用的 xmake 作为构建界面。
前提是我能完成这个项目。
包的种类:
存档格式:
包里面的关键文件:
常用工具:
通常的安装流程:
# 下载源码包
curl -O http://xxx.org/xxx.tar
# 查看散列值是否和官网给出的一致
md5sum xxx.tar
# 解压缩
tar -xavf xxx.tar
cd xxx
# 查看帮助文档
less README
# 配置 makefile
./configure --prefix=/usr
# 构建
make
# 安装
sudo make install
# 清理临时文件
make clean
多数开源软件都是 c 语言或 c++ 语言开发的。在 c 语言中,程序可以分成多个源文件(*.c
),如果要使用另一个源文件的内容怎么半?不需要复制,只需要添加对应的头文件(*.h
)。
这种方式叫静态链接。很多时候一个组件会被多个应用程序使用,如果都静态链接,会增大程序容量,这时候可以动态链接,即告之操作系统,我这个程序要用到那个组件,操作系统执行的时候再去把相关组件加载进来,而不需要一开始就组合到应用程序内部。
知识点:
*.o
)*.a
)*.so
)*.out
)。核心工具:
gcc 是一个智能工具,它可以调用其他工具来完成整个编译流程,因此实际使用中,用户不需要分别调用不同的工具来完成这个流程。
# 演示生成步骤
# test.h test.c main.c
# 预编译
# -o 表示输出
gcc -E test.c -o test.i # -> test.i
gcc -E main.c -o main.i # -> main.i
# 编译
gcc -S main.i # -> main.s
gcc -S test.i # -> test.s
# 汇编
gcc -c test.s # -> test.o
as main.s # -> test.o
# 归档(静态库)
# -rc 创建新的库 libtest.a
ar -rc libtest.a test.o
# 动态库
gcc -shared test.o -o libtest.so
# 使用静态库构建程序
# -L. 库的路径 . 当前目录
# -l 库的名字 libname.a 或 libname.so(自动添加其余部分)
gcc main.o -o stapp -static -L. -ltest
# 或者
gcc main.o libtest.a -o stapp
# 使用动态库
gcc main.o -o dyapp -L. -ltest
# 手动链接比较麻烦
# 1.o i.o n.o 是 c 语言程序的初始部分
# -I 是动态链接器的位置,虽然 libtest.a 是静态链接,但是 libc.so 是动态链接,每个 c 语言程序都要链接到基本的 c 库。
# -lc 就是 libc 库
ld main.o libtest.a /usr/lib/crt{1.o,i.o,n.o} -I /lib64/ld-linux-x86-64.so.2 -lc -o stapp
# 或静态链接到 c 库
ld main.o libtest.a /usr/lib/crt{1.o,i.o,n.o} -static -lgcc -lc -lgcc_eh -lc -L /usr/lib/gcc/x86_64-pc-linux-gnu/11.1.0/ -o stapp
# 运行动态链接的程序
# LD_LIBRARY_PATH 环境变量告诉动态链接器,该从哪里查找动态库 libtest.so
LD_LIBRARY_PATH=. ./dyapp
其他工具:
核心库:
elf 格式:
动态链接器:
交叉编译:
所谓交叉编译是指在当前平台上编译一个能在目标平台(和当前平台不同的)上运行的程序。支持这种编译方式的编译器,叫交叉编译器。
在交叉编译器(注意是针对编译器)这个领域,有一些专业术语需要学习:
比如你编译一个 gcc, 构建的平台就是 build。 这个 gcc 将来能在那种机器上运行,这个运行平台就是 host。 最后,这个 gcc 能够构建在什么机器上运行的程序,这个就是 target。
可见,如果不是编译器,那 target 就是没啥意义的。一般程序你可以理解 build 就是你本机,host 就是目标机器。 也可以认为 target 等于 host。
根据三者的组合,可以得到:
接下来,我会使用第四种方案,交叉编译一个交叉编译器,设置是: build != host 但 target = build 。
目的是:
bash 的启动方式:
核心包:bash、bc、binutils、coreutils、diffutils、file、findutils、gawk、grep、gzip、m4、man-db、ncurses、procps、psmisc、sed、shadow、tar、util-linux、zlib;扩展:at、batch、cpio、ed、fcrontab、lsb-tools、nspr、nss、pam、pax、sendmail、time
运行时: perl;扩展:python、libxml2、libxslt
桌面:alsa、atk、cairo、desktop-file-utils、freetype、fontconfig、gdk-pixbuf、glib2、gtk+2、icon-naming-utils、libjpeg-turbo、libpng、libtiff、libxml2、mesalib、pango、xdg-utils、xrog;扩展:qt5、gtk+3
成像:cups、cups-filters、chostscript、sane
首先构建交叉编译器和相关库。
环境变量定义:
和交叉编译系统有关的包:
xmake 支持调用第三方构建系统来构建,这样的好处就是最大的兼容现有的项目,同时可以有效的利用 xmake 的设置系统,这比第三方的设置要简易不少。
参数解析:
# binutils
curl -O https://ftp.gnu.org/gnu/binutils/binutils-2.36.1.tar.xz
tar -xavf binutils-2.36.1.tar.xz
cd binutils-2.36.1
xmake f --trybuild=autotools --tryconfigs="--prefix=$P2ROOT/usr/ \
--with-sysroot=$P2ROOT \
--target=$P2 \
--disable-nls \
--disable-werror"
xmake
下载相关包的香港镜像: https://mirror-hk.koddos.net/lfs/lfs-packages/10.1/
后续就不介绍下载和解压缩了,直接从编译开始。
gcc 依赖 mpfr 和 mpc,需要在 gcc 目录下创建两个符号链接 mpfr 和 mpc 指向他们的源代码(或者也可直接复制到这个目录)。
需要注意,gcc 需要在源文件ls目录外部构建,这种模式叫源外构建,lfs 大多数项目都应该采用源外构建的方式进行。
在此回顾交叉编译的细节:
我们想要的效果是建立一个独立的编译系统 C2,它运行在 P2 平台,然后通过 C2 交叉编译在 P1 平台运行的编译系统 C3。
那么首先得用本机 P1 上的已有编译器 C0 来构造 C2.
构造详细的流程是:
注意 C1 这个中间的编译器是需要的,因为本机上没有 p1 -> p2 的交叉编译器,因此你不能直接从 C0 -> C2,这是交叉编译。
C4 和 C3 都能正常工作,但是构建 C3 时,没有在构建时验证 C3,因为它是交叉编译的。它的验证工作要在目标机上执行。
# 创建符号链接
ln -s ../mpfr-4.1.0/ mpfr
ln -s ../gmp-6.2.1/ gmp
cd .. # 退出 gcc 的源文件目录
xmake f --trybuild=autotools --tryconfigs="--target=$P2 \
--prefix=$P2ROOT/usr \
--with-glibc-version=2.11 \
--with-sysroot=$P2ROOT \
--with-newlib \
--without-headers \
--enable-initfini-array \
--disable-nls \
--disable-shared \
--disable-multilib \
--disable-decimal-float \
--disable-threads \
--disable-libatomic \
--disable-libgomp \
--disable-libquadmath \
--disable-libssp \
--disable-libvtv \
--disable-libstdcxx \
--enable-languages=c,c++"
glibc 依赖 linux header(系统头文件)。
make headers
make headers_install INSTALL_HDR_PATH=$P2ROOT/usr
注意 glibc 不是编译器,它是库,也就是目标程序的一部分。所以它的 host 不是 P1 ,而是 P2。
glibc 的路径是相对 P2 根目录的。
因为这将进行一次交叉编译,即 p1->p2,所以路径里面要提供我们新构造的 C1 编译器。
PATH=$PATH:$P2ROOT/usr/bin ../glibc-2.33/configure \
--prefix=$P2ROOT/usr \
--host=$P2 \
--build=$P1 \
--enable-kernel=3.2 \
--with-headers=$P2ROOT/usr/include
PATH=$PATH:$P2ROOT/usr/bin make
PATH=$PATH:$P2ROOT/usr/bin make install # 安装到相对位置DESTDIR=$P2ROOT
# 修复头文件
$P2ROOT/usr/libexec/gcc/x86_64-lfs-linux-gnu/10.2.0/install-tools/mkheaders
c++ 标准库。类似 c 库的做法。
libstdc++ 属于 gcc 源码包的一部分,在里面找到 libstdc++-v3 目录。
PATH=$PATH:$P2ROOT/usr/bin ../gcc-10.2.0/libstdc++-v3/configure \
--host=$P2 \
--build=$P1 \
--prefix=$P2ROOT/usr \
--disable-multilib \
--disable-nls \
--disable-libstdcxx-pch \
--with-gxx-include-dir=$P2ROOT/usr/$P2/include/c++/10.2.0
PATH=$PATH:$P2ROOT/usr/bin make
PATH=$PATH:$P2ROOT/usr/bin make install
至此,完成了交叉编译器 C1 (build=P1, host=P1, target=P2)。
C1 是一个简化版编译器。
它其实还没能脱离宿主机(即本机 P1),构建要用到的工具,也还是本机上的,我们想构建完全独立的 P2 环境,就要使用 C1 交叉编译这些基本的工具。
基本工具包:M4、Ncurses、bash、coreutils、diffutils、file、findutils、gawk、grep、gzip、make、patch、sed、tar、xz。
准备好之后,构建 C2 (build=P1, host=P2, target=P1) 的编译器包:binutils、gcc、glibc、stdc++。
todo: gcc pass 1 没有完成结尾的修复头文件任务。。 https://www.linuxfromscratch.org/lfs/view/stable/chapter06/m4.html 宏处理器。
# 修复和 glibc 2.28 以上版本的兼容性
sed -i 's/IO_ftrylockfile/IO_EOF_SEEN/' lib/*.c
echo "#define _IO_IN_BACKUP 0x100" >> lib/stdio-impl.h
PATH=$P2ROOT/usr/bin:$PATH ../m4-1.4.18/configure \
--prefix=$P2ROOT/usr \
--host=$P2 \
--build=$P1
PATH=$P2ROOT/usr/bin:$PATH make
PATH=$P2ROOT/usr/bin:$PATH make install
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。