编译狂魔笔记

前言

版本号什么的当然是越大越好!编译当然要找 master HEAD!

——窝自己说的

本文持续更新中。一些惯例,我的 prefix 都是 $HOME/.local,会有一些环境变量默认开启,所有的软件均使用静态链接:

export PATH="$HOME/.local/bin${PATH:+:$PATH}"
export LD_RUN_PATH="$HOME/.local/lib:$HOME/.local/lib64${LD_RUN_PATH:+:$LD_RUN_PATH}"
export LD_LIBRARY_PATH="$HOME/.local/lib:$HOME/.local/lib64${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export LIBRARY_PATH="$HOME/.local/lib:$HOME/.local/lib64${LIBRARY_PATH:+:$LIBRARY_PATH}"
export CPATH="$HOME/.local/include${CPATH:+:$CPATH}"

GCC 系列

毕竟是用来编译其它软件的,最新的 GCC 才能编译出最新算法优化过的二进制文件,所以首先解决 GCC 和它的依赖。具体的依赖见 https://gcc.gnu.org/install/prerequisites.html

GMP

The GNU Multiple Precision Arithmetic Library 官网 https://gmplib.org/ ,高精度处理库,无任何依赖。

使用 Mercurial 管理源码,一般来说我不会去编译版本管理系统,直接用包管理器下载 mercurial,然后 clone:

hg clone https://gmplib.org/repo/gmp/

需要去 gmp 目录下手动跑一下 ./.bootstrap 生成 configure。完事儿之后直接 ln -s 到 gcc 目录下就好了,不用手动编译。

MPFR

Multiple Precision Floating-Point Reliably,依赖于 GMP,但对于浮点数做了专精。官网 https://www.mpfr.org/

svn checkout https://scm.gforge.inria.fr/anonscm/svn/mpfr/trunk mpfr

同理,需要在 mpfr 目录下手动执行 ./autogen.sh 生成 configure,这里有个 autoconf-archive 的包依赖,包管理器或者手动安装均可。完事儿后链接到 gcc 目录下即可。

MPC

Multi Precision Complex 依赖于 MPFR 和 GMP,对于复数做了专精。官网 http://www.multiprecision.org/mpc/

git clone https://scm.gforge.inria.fr/anonscm/git/mpc/mpc.git

同理,需要在 mpc 目录下手动执行 autoreconf -fvim。完事儿后链接到 gcc 目录下即可。

ISL

似乎是个整数集合库,没用过不知道干啥的。官网 http://isl.gforge.inria.fr/(官网 UI 透露着一股贫穷的气息)。

git clone git://repo.or.cz/isl.git

同理,需要在 isl 目录下手动执行 autoreconf -fvim。完事儿后链接到 gcc 目录下即可。

GCC

第一个里程碑。官网 https://gcc.gnu.org/

GCC 最近彻底从 SVN 迁移到 Git 了,可喜可贺可喜可贺。GCC 自己有一个 git 服务器,如果不喜欢的话也可以用 github.com 上的 gcc-mirror。

git clone git://gcc.gnu.org/git/gcc.git

GCC 中除了 gcc 是自依赖的,还有一个 gnat 也就是 Ada 编译器,它也是依赖自身的,也就是我们需要一个旧版本的 gnat 编译器,如果有强迫症想要装的话可以先用包管理器装一个 gnat。

确保已经将 gmp, mpfr, mpc, isl 目录链接好以及 autoreconf 生成了 configure——当然你也可以手动安装之后在 configure 中指定 --with-* 或者用环境变量 LD_RUN_PATH 来帮助 configure 寻找。

接下来就是 configure。configure 最好不要在 gcc 目录下进行——虽然允许——否则会让预处理和编译生成的文件混杂在源码中。建议在 gcc 外新建一个目录后 ../gcc/configure。我的 configure 命令为:

../gcc/configure \
  --prefix=$HOME/.local \
  --enable-languages=all \
  --disable-multilib \
  --disable-host-shared \
  --with-boot-ldflags=-static

参数中不需要解释太多,只需要知道最后一句是将 GCC 编译成静态链接的重点参数。

然后 make 即可,视情况指定 -j。我因为不希望我的 $HOME 出现在 gcc -v 中,所以在 configure 的时候没有指定 prefix,在 configure 生成的 Makefile 中第 55 行(可能会视版本不同而变化)手动编辑了 prefix 再 make 的。

GCC 的具体编译有三个阶段:

  1. 用 bootstrap GCC(即用户指定的编译器,或默认系统自带的编译器)编译出第一版 GCC,此版 GCC 的内部仍然是 bootstrap GCC 使用的代码生成、代码优化算法生成的二进制文件。
  2. 用第一版 GCC 编译出第二版 GCC,此版 GCC 内部是新版 GCC 算法生成的二进制文件。由于传了 --with-boot-ldflags=-static,此处的 xgcc 和 xg++ 应该是静态链接的,可以在 stage_current 为 stage3 的时候测试一下 ldd prev-gcc/x{gcc,g++}
  3. 用第二版 GCC 编译出第三版 GCC,检查和第二版有无区别,如果没有差异则编译通过。同理此处也是静态链接的。

默认情况下以上三步均会被执行,可以选择跳过第三步,详细参数见 GCC 官网 configure 指令。编译期间可以在 make 目录下查看文件 stage_current 确定当前的阶段。编译耗时试机器配置大概需要半小时到一小时。

最后不出意料的话,生成的主要编译器包括 gcc, g++, gdc, gfortran, gnat, gccgo。记得重点测试一下 gcc 和 g++ 可不可用,后面用得到。

CPython 解释器及其模组

CPython 的静态编译主要分两大部分,一是解释器本身,二是各种模组。默认情况下,模组都是以动态链接的方式作为 python 的一部分的, 当我们静态编译的时候,我们就必须要把所有模组直接嵌入 python 二进制中。

GPM

GPM 全称 General Purpose Mouse,为 console 程序提供复制粘贴的能力。是 ncurses 的可选依赖之一。

官网在 https://www.nico.schottelius.org/software/gpm/,然而上面的仓库链接失效了,用 GitHub 上的。

git clone [email protected]:telmich/gpm

GPM 和 ncurses 之间有循环依赖的问题。默认情况下 GPM 依赖 ncurses,可以选择 --without-ncurses 来消除依赖。但按 LFS,这同时会导致一些依赖这种关系的软件无法通过编译(如 w3m),大部分发行版的解决方案是在编译完 ncurses 后不传入该参数再编译一次 GPM,我这里就不进行该操作了。

GPM 的源码有一些小问题,需要一些小改动:

  1. src/Makefile.in 99 行,即 $(DEPFILES) deps 目标中,需要在编译语句的参数中加入 -Iheaders,不然会出现找不到头文件的错误。注意这个无法通过 CFLAGS 解决,只能改源码(垃圾代码)。
  2. src/headers/daemon.h 183 行,即 last_selection_time 的定义处,需要在行首加入 extern,不然会出现重复定义的问题(谁叫你在头文件里定义变量……)。

GPM 的配置和编译需要在源码目录下进行,作者没有考虑过在源码目录外编译的情况(垃圾代码)。

./configure --prefix=$HOME/.local --without-ncurses

PCRE2

One Reply to “编译狂魔笔记”

  1. 这也tql, %%%

发表评论