快速构建 GCC 并自定义编译标志 (禁用 Bootstrap)
2025-03-22 03:17:16
如何在不进行 Bootstrap 的情况下构建 GCC 并指定编译标志?
遇到一个棘手的问题:想要快速构建 GCC,同时还想精确控制编译选项,尤其是去除调试信息。常规的 Bootstrap 流程耗时太长,而直接禁用 Bootstrap 又无法应用自定义的编译标志。 真是左右为难!
问题根源:GCC 的构建机制
GCC 的构建过程比较复杂。为了确保编译器的稳定性和可靠性,默认采用了一种称为“Bootstrap”的机制。这个过程大致是:
- 用系统现有的编译器(通常也是 GCC)编译一个初始版本的 GCC(stage1)。
- 用 stage1 版本的 GCC 编译第二个版本的 GCC(stage2)。
- 用 stage2 版本的 GCC 编译最终版本的 GCC(stage3)。
- 比较stage2 和 stage3 产物。
这样做的目的是检测编译器自身的缺陷。如果 stage2 和 stage3 编译出来的程序行为不一致,说明编译器可能存在 bug。
--disable-bootstrap
选项直接跳过了这个多阶段的编译过程,只进行一次编译。 这样速度是快了,但是无法像使用--with-build-config
来通过 BOOT_CFLAGS
精确的修改 flag.
问题在于,不同的构建阶段会使用不同的编译标志变量。直接设置 CFLAGS
、CFLAGS_FOR_BUILD
等变量可能不会对最终安装的 GCC 生效。需要找到正确的变量。
解决方案:精确定位编译标志变量
经过一番探索和试验, 以及大量搜索, 发现要达到目标,需要组合拳。以下几种方法供您参考:
1. 使用 make install-strip
(最简便,推荐)
这是最简单粗暴的办法。虽然不能在编译时就去除调试信息,但是可以在安装阶段解决:
-
原理:
make install-strip
会在安装 GCC 的同时,自动调用strip
命令移除可执行文件中的符号表和调试信息。 -
操作:
./configure --disable-bootstrap # 仍然禁用 Bootstrap make make install-strip
-
额外安全建议 : 这个操作, 文件只会在被strip过的阶段受到保护. 之前还是有可能拿到带有调试符号的版本.
-
进阶使用:
如果您只需要strip特定的target(例如libgcc, libstdc++),可以只单独strip他们:make install-libgcc-strip install-libstdc++-strip
(仅为举例,不一定准确. 自行查阅对应target名称).
2. 修改 Makefile (细粒度控制,复杂)
如果上面的方法不能满足你的需求,想要更精细地控制编译选项,可以尝试修改生成的 Makefile
。
-
原理: GCC 的构建系统会根据
configure
脚本的配置生成一系列的Makefile
文件。这些文件中定义了编译目标、依赖关系和编译选项。通过直接修改Makefile
,可以更直接地控制编译过程。 -
操作:
- 先执行
configure
和make
:./configure --disable-bootstrap make
- 找到相关的
Makefile
: 通常,要修改的目标文件会位于gcc
目录下。比如, 要想控制最终生成的cc1
的编译选项,需要找到其相关的Makefile(比如gcc/Makefile
). - 修改编译选项: 在找到的
Makefile
中,搜索并修改相关的编译标志变量.- 举例: 你可以搜索类似于
cc1$(exeext): $(objpfx)cc1.o
(注意这是例子! 不保证通用).找到类似这样的语句:
$(CC) $(CFLAGS) $(INCLUDES) -o cc1$(exeext) $(objpfx)cc1.o ...
. 此时, CFLAGS就是需要修改的点, 你可以直接加到CFLAGS上, 比如:$(CC) $(CFLAGS) -s $(INCLUDES) ...
- 举例: 你可以搜索类似于
- 继续进行
make
和make install
.
- 先执行
-
额外安全建议 :直接编辑Makefile, 修改难度大,出错几率也高.
-
进阶使用:
这种方法灵活性很高,你可以控制任意的flag,甚至单独控制部分文件的编译flag. 但是每次
./configure
之后, 都需要重复这些编辑操作. 你可以考虑自己写脚本来进行自动编辑.
3. 利用 CFLAGS_FOR_TARGET
和 LDFLAGS_FOR_TARGET
(可能有用,不保证)
根据有限的文档, 和我的部分尝试, 可以试试看使用CFLAGS_FOR_TARGET
和 LDFLAGS_FOR_TARGET
.
-
原理: 虽然文档没说清楚, 但是从名字判断, 这些变量可能是用来控制编译目标库和程序的标志.
-
操作:
./configure --disable-bootstrap CFLAGS_FOR_TARGET="-O2 -s" LDFLAGS_FOR_TARGET="-s" make make install
-
额外建议: 这个效果我没有完整的测试出来. 在一些情况下, 对最终的
install
阶段产物, 可能并没有生效. 请务必自己测试确认. -
进阶使用: 同Makefile 部分的分析, 如果发现这个确实会影响到部分的Makefile, 但不完全是想要的, 可以结合 Makefile 编辑来最终达成效果.
4. 使用自定义的配置文件(config.make)
GCC允许你在顶层目录创建一个名为 config.make
的文件, 你可以在此指定某些flag.
-
原理 :
config.make
文件提供了一种在不改变 configure 脚本的情况下更改默认设置的方式. -
操作 :
1. 在GCC源代码根目录中创建config.make文件。
2. 添加相应的选项:
makefile CFLAGS_FOR_TARGET = -O2 -s LDFLAGS_FOR_TARGET = -s
-
注意事项 : 如同方法3, 这个也可能有局限性, 请充分测试。
其他提示
- 如果你对具体的 flag 来源感到困惑, 一个debug 的小技巧是利用
make -n
, 或者make --dry-run
. 这个命令不会实际编译, 但是会打出实际要执行的编译命令. 从中你就可以找到flag是如何一步步添加进去的。
总结下, 这几个方法, 从易到难. make install-strip
最省事。 修改 Makefile
最灵活, 但需要仔细寻找。 最后的几个flag设置有不确定性。 请大家自行按需选择!