在 OS X 10.11 上构建 GCC

Building GCC on OS X 10.11

在这里使用命令行在 OS X 10.11.1 上构建 GCC(最新版本):

../gccx/configure --with-gmp="/opt/local" --with-mpfr="/opt/local" \
    --with-mpc="/opt/local" --with-libiconv-prefix="/opt/local" --with-pkgversion="GCCX" \
    --program-transform-name='s/^gcc$/gccx/; s/^g++$/g++x/' --enable-languages=c

完全按照构建说明进行操作,但出现此错误:

g++ -std=gnu++98   -g  -DIN_GCC    -fno-strict-aliasing
-fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wno-format -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common  -DHAVE_CONFIG_H -DGENERATOR_FILE -fno-PIE -Wl,-no_pie   -o build/genmatch \
        build/genmatch.o ../build-x86_64-apple-darwin15.0.0/libcpp/libcpp.a build/errors.o build/vec.o build/hash-table.o ../build-x86_64-apple-darwin15.0.0/libiberty/libiberty.a Undefined symbols for architecture x86_64:  "_iconv", referenced from:
     convert_using_iconv(void*, unsigned char const*, unsigned long, _cpp_strbuf*) in libcpp.a(charset.o)
    (maybe you meant: __Z14cpp_init_iconvP10cpp_reader, __cpp_destroy_iconv )  "_iconv_close", referenced from:
     __cpp_destroy_iconv in libcpp.a(charset.o)
     __cpp_convert_input in libcpp.a(charset.o)  "_iconv_open", referenced from:
     init_iconv_desc(cpp_reader*, char const*, char const*) in libcpp.a(charset.o) ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make[3]: *** [build/genmatch] Error 1 make[2]: *** [all-stage1-gcc] Error 2 make[1]: *** [stage1-bubble] Error 2 make:
*** [all] Error 2

(完整日志可在 https://gist.github.com/3cb5d044533e657f4add 获得。)

调查gcc/Makefile后,似乎BUILD_CPPLIB变量不包含$(LIBICONV),因为它在出错时处于阶段1 bootstrap。相关部分前面有

# For stage1 and when cross-compiling use the build libcpp which is
# built with NLS disabled.  For stage2+ use the host library and
# its dependencies.

但显然 build/genmatch 的 stage1 构建引用了 libcpp,它使用 libiconv 的符号。所以这里有些不对劲。

我该如何解决?

一般性讨论

在 Mac OS X 上构建 GCC 有时是一个令人担忧的过程。多年来,我在使用各种版本的 GCC 和各种版本的 Mac OS X 时遇到过各种问题。您可以看到我在 Install GCC on Mac OS X 中所做的早期解释 — 那是在 Mavericks 10.9.x(或者可能是 Mountain Lion 10.8.x 上构建 GCC 4.8.x );它还报告在 Mavericks 10.9.x 上成功构建 GCC 4.9.0,但在 Yosemite 10.10.x.

上未能成功

这是在 Mac OS X 10.11.1 El Capitan 上构建 GCC 5.2.0 的更新方法。 它开始使用 XCode 7.1.1 — 我不知道 XCode 的其他哪些版本可以。

请注意 具有 Yosemite 和更早版本中没有的 SIP(​​系统完整性保护)功能。这意味着您不能再在 /usr 下创建任意目录。我以前安装在 /usr/gcc/vX.Y.Z;这在 El Capitan 中不再被允许。因此,一个主要变化是我现在安装在 /opt/gcc/v.X.Y.Z.

我发现设置 DYLD_LIBRARY_PATH 是有问题的——尤其是在 El Capitan 上。与过去相比有重大突破,我现在根本不设置它。请注意,脚本取消了它。另请注意,该脚本显式地将阶段 1 编译器 CC 和 CXX 分别设置为 /usr/bin/clang/usr/bin/clang++(XCode 编译器)。当前版本的 GCC 需要功能强大的 C++ 编译器,而不是(或同时需要)C 编译器。

我偶尔会遇到 libiconv 的问题,但目前我通过没有安装自己的版本来避免这些问题。同样,我偶尔会遇到 GCC 源代码中一些 awk 脚本的问题。我必须破解 it/them 才能正常工作。但是,有了 GCC 5.2.0 源代码的发布副本,我似乎可以直接开箱即用。

如果您只有一个磁盘分区,那么下一点并不重要。如果您有多个磁盘,请确保目标目录不存在或确保其名称正是您想要的。在工作的机器上(不是 Mac 而是 Linux 机器等),我仍然使用 /usr/gcc/vX.Y.Z 作为 'official' 安装位置,但软件最终以某种任意方式结束有足够 space 的文件系统,例如 /work4/gcc,最终有一个符号链接使得 /usr/gcc/vX.Y.Z 到达 /work4/gcc/vX.Y.Z。但是,编译 GCC 时 /work4/gcc/vX.Y.Z 不存在至关重要,因为它将通过 realpath() 或其等效项解析名称并将 /work4/gcc/vX.Y.Z 嵌入二进制文件,而不是中性名称/usr/gcc/vX.Y.Z。这限制了安装的可移植性;它被移动到的任何其他机器都必须有一个目录 /work4/gcc/vX.Y.Z,即使您要求将它安装在 /usr/gcc/vX.Y.Z.

在 Mac OS X 10.11.1 和 XCode 7.1.1

上编译 GCC 5.2.0

我不得不使用 GMP(5.1.3 而不是 6.0.0a)和 ISL(0.14 而不是 0.15)的降级版本。以后版本的构建都给我带来了麻烦。

请注意,我将 GMP、MPC、MPFR、ISL 和 Cloog(请参阅 GCC pre-requisites)的库代码放在 GCC 源目录中,以便 GCC 构建这些库的自己的版本。我发现这是确保 GCC 正确定位这些库的最简单方法。

目标目录:/opt/gcc/v5.2.0

在 17" MacBook Pro(2011 年初)上的构建时间约为 2 小时 15 米 运行 Intel Core i7,2.3 GHz,16 GiB 1333 MHz DDR3 主内存和 750 GB 5400 rpm 硬盘驱动器。源占用约 850 MiB;构建树最终约 4.6 GiB — 你需要足够的磁盘 space。安装的代码最终约 420 MiB。

使用的脚本 — extract-gcc-5.2.0.sh

#!/bin/bash

unset DYLD_LIBRARY_PATH

TAR=tar
VER_NUM=5.2.0
GCC_VER=gcc-${VER_NUM}
TGT_BASE=/opt/gcc
TGT_DIR=${TGT_BASE}/v${VER_NUM}
CC=/usr/bin/clang
CXX=/usr/bin/clang++

extract() {
    echo "Extract "
    $TAR -xf 
}

if [ ! -d "$GCC_VER" ]
then extract ${GCC_VER}.tar.bz2 || exit 1
fi

(
cd ${GCC_VER} || exit

nbncl <<EOF |
    cloog 0.18.1 tar.gz 
    gmp 5.1.3 tar.xz 
#   gmp 6.0.0 tar.lz 
    isl 0.14 tar.bz2 
#    isl 0.15 tar.bz2 
    mpc 1.0.3 tar.gz 
    mpfr 3.1.3 tar.xz
EOF

while read file vrsn extn
do
    tarfile="../$file-$vrsn.$extn"
    if [ ! -f "$tarfile" ]
    then echo "Cannot find $tarfile" >&2; exit 1;
    fi
    if [ ! -d "$file-$vrsn" ]
    then
        (
        set -x
        extract "$tarfile" &&
        ln -s "$file-$vrsn" "$file"
        ) || exit 1
    fi
done
)

if [ $? = 0 ]
then
    mkdir ${GCC_VER}-obj
    cd ${GCC_VER}-obj
    ../${GCC_VER}/configure --prefix="${TGT_DIR}" \
        CC="${CC}" \
        CXX="${CXX}"
    make -j8 bootstrap
fi

脚本 nbncl — 非空白、非注释行

#!/usr/bin/env perl
#
# Non-blank, non-comment lines only

use warnings;
use strict;

while (<>)
{
    chomp;
    s/\s+$//;
    s/\s*#.*$//;
    print "$_\n" unless /^$/;
}

首先,请参阅 Jonathan Leffler 的非常完整的回答。我在这里还有一些建议。

gcc 配置和构建过程需要找到您系统的本机头文件和 C 运行-time 库。较新的、基于 clang 的 Xcode 版本将这些隐藏得很深,而较旧版本的 gcc 似乎不知道如何找到它们。为了完全构建 gcc 4.6,我必须创建这些符号链接:

ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include /usr
ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/lib/dylib1.10.5.o /usr/local/lib
ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/lib/crt1.10.5.o /usr/local/lib
ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/lib/bundle1.o /usr/local/lib

您的里程可能会略有不同:请注意 /Applications/Xcode.app/Contents 下面的那些路径名中包含各种版本号,这些版本号在您的系统上可能会有所不同。

(如果正如 Jonathan 所描述的那样,最新版本的 MacOS 不允许您在 /usr 中放置任何内容,您可能必须在 /usr/local/include 中创建 /usr/include 符号链接,相反,我怀疑这也行得通。)

此外,这在其他地方也提到过,但这是一个不寻常的要求,而且很容易被忽视:不要尝试在其自己的源代码树中构建 gcc。始终创建一个构建目录,该目录是您将 gcc 源代码提取到的目录的平行 sibling,而不是下面的子目录。也就是说,不要这样做:

tar xzf gcc-x.y.z.tar.bz2
cd gcc-x.y.z       # WRONG
mkdir build
cd build
../configure       # WRONG
make

相反,这样做:

tar xzf gcc-x.y.z.tar.bz2
mkdir build
cd build
../gcc-x.y.z/configure
make

这是违反直觉的,我知道,这不是许多其他包的工作方式,但它确实适用于 gcc,并且这是推荐的方式。

还有一点:如果你发现你的构建失败是因为你配置不当,以至于你必须重新运行 configure 不同的选项,删除整个构建目录更安全并从头开始。配置和构建系统有时会检测到在这种情况下可能需要重建的内容,但似乎并非 100% 可靠。 (删除并重新开始是令人沮丧的,我同意,但再次强调,它确实可以在漫长的运行中节省时间。)

最后,如果您正在尝试构建交叉编译器,请参阅 install gcc 4.6.1 on OS X 10.11 中的一些其他建议和评论。

值得一提的是,MacPorts 具有适用于所有最新版本的端口,对于每个人(知道如何编码的人!)来说应该足够容易阅读谁不想安装 MacPorts 但更喜欢安装提到的各种依赖项这里有其他方式。

gcc 6.3.0 端口的个人版本略有调整: https://github.com/RJVB/macstrop/blob/master/lang/gcc6/Portfile

我提到那个(和 post 这个答案)的原因是这个调整后的版本展示了如何让 G++ 使用 libc++ 而不是 libstdc++。这是能够使用 G++ 作为 clang++ 的真正替代品的特权,可以使用它而不必担心 C++ 运行 时间不兼容。这个补丁允许我使用 g++ 构建 KDE (KF5) 代码,并 运行 它针对 Qt5 和使用各种 clang 编译器版本构建的 KF5 框架。 (补丁文件在 .../gcc6/files 中。)

一些可能有助于解释链接文件的 Tcl 代码的解释:

忽略任何特定于 $subport == "libgcc".

如您所见,您需要 gmp、mpc、mpfr 和 isl(如果您自己安装,其他依赖项应该没有意义)。

configure.args 表达式构造配置脚本的参数列表,configure.env 和build.env 为配置和构建(make)命令添加环境变量。这里的许多配置选项是为了确保构建使用来自 MacPorts 的依赖项,但如果您想要或必须使用不受 SIP 控制且不包含在标准 PATH 定义中的位置(编译器通过重置路径的过程调用时仍然应该工作。

配置和构建是在位于源目录旁边的构建目录中完成的,这使得重新开始或只是清理而不丢弃源代码变得非常容易。 在配置步骤之后,构建完成 "make bootstrap-lean" - 它仍然在该构建目录中创建大约 1.7Gb 的数据。