如何从x86_64-apple-darwin主机构建一个i386-apple-darwin目标的交叉编译器?

8

问题概述

我正在尝试学习如何构建交叉编译器,具体来说是在一个64位Intel OS X主机上针对i386-apple-darwin(32位Intel)构建GNU gcc 4.7.2的版本。然而,我一直卡在同一个错误上:

...
checking for i386-apple-darwin-gcc... /Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/xgcc -B/Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/bin/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/lib/ -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/include -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/sys-include
checking for suffix of object files... configure: error: in `/Users/alexpreynolds/Developer/third-party/build-gcc/i386-apple-darwin/libgcc':
configure: error: cannot compute suffix of object files: cannot compile
See `config.log' for more details.
make[1]: *** [configure-target-libgcc] Error 1
make: *** [all] Error 2

构建过程

我首先构建了一个针对 i386-apple-darwin 目标的 GNU binutils 版本,它可以访问 GNU gcc 构建文件夹:

$ cd third-party
$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.23.2.tar.bz2
$ tar xjvf binutils-2.23.2.tar.bz2
$ mkdir i386-apple-darwin
$ mkdir build-binutils && cd build-binutils
$ ../binutils-2.23.2/configure --target=i386-apple-darwin --prefix="/Users/alexpreynolds/Developer/third-party/i386-apple-gcc"
$ make all && make install
...

然后我尝试按如下方式构建一个针对特定目标的gcc版本:

$ cd ..
$ pwd
/Users/alexpreynolds/Developer/third-party
$ wget http://ftp.gnu.org/pub/gnu/gcc/gcc-4.7.2/gcc-4.7.2.tar.bz2
$ tar xvjf gcc-4.7.2.tar.bz2
$ cd gcc-4.7.2
$ ./contrib/download_prerequisites
... /* this grabs GMP, MPC and MPFR dependencies */
$ cd ..
$ mkdir build-gcc && cd build-gcc
$ ../gcc-4.7.2/configure --target=i386-apple-darwin --prefix="/Users/alexpreynolds/Developer/Bedops/bedops/third-party/i386-apple-gcc"
$ make
...

大约编译了30分钟后,出现了上面显示的错误信息。

错误详情

为了追踪错误来源,这里提供了build-gcc/i386-apple-darwin/libgcc/config.log的代码片段:

configure:3344: /Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/xgcc -B/Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/bin/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/lib/ -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/include -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/sys-include    -V >&5
xgcc: error: unrecognized command line option '-V'
xgcc: fatal error: no input files
compilation terminated.
configure:3355: $? = 1
configure:3344: /Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/xgcc -B/Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/bin/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/lib/ -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/include -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/sys-include    -qversion >&5
xgcc: error: unrecognized command line option '-qversion'
xgcc: fatal error: no input files
compilation terminated.
configure:3355: $? = 1
configure:3371: /Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/xgcc -B/Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/bin/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/lib/ -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/include -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/sys-include    -o conftest -g -O2   conftest.c  >&5
Assembler messages:
Fatal error: invalid listing option `r'
configure:3374: $? = 1
configure:3562: checking for suffix of object files
configure:3584: /Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/xgcc -B/Users/alexpreynolds/Developer/third-party/build-gcc/./gcc/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/bin/ -B/Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/lib/ -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/include -isystem /Users/alexpreynolds/Developer/third-party/i386-apple-gcc/i386-apple-darwin/sys-include    -c -g -O2  conftest.c >&5
Assembler messages:
Fatal error: invalid listing option `r'
configure:3588: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "GNU C Runtime Library"
| #define PACKAGE_TARNAME "libgcc"
| #define PACKAGE_VERSION "1.0"
| #define PACKAGE_STRING "GNU C Runtime Library 1.0"
| #define PACKAGE_BUGREPORT ""
| #define PACKAGE_URL "http://www.gnu.org/software/libgcc/"
| /* end confdefs.h.  */
|
| int
| main ()
| {
|
|   ;
|   return 0;
| }
configure:3602: error: in `/Users/alexpreynolds/Developer/third-party/build-gcc/i386-apple-darwin/libgcc':
configure:3605: error: cannot compute suffix of object files: cannot compile
See `config.log' for more details.

我正在引导启动的编译器

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/opt/local/libexec/gcc/x86_64-apple-darwin12/4.7.2/lto-wrapper
Target: x86_64-apple-darwin12
Configured with: ../gcc-4.7.2/configure --prefix=/opt/local --build=x86_64-apple-darwin12 --enable-languages=c,c++,objc,obj-c++,lto,fortran,java --libdir=/opt/local/lib/gcc47 --includedir=/opt/local/include/gcc47 --infodir=/opt/local/share/info --mandir=/opt/local/share/man --datarootdir=/opt/local/share/gcc-4.7 --with-libiconv-prefix=/opt/local --with-local-prefix=/opt/local --with-system-zlib --disable-nls --program-suffix=-mp-4.7 --with-gxx-include-dir=/opt/local/include/gcc47/c++/ --with-gmp=/opt/local --with-mpfr=/opt/local --with-mpc=/opt/local --with-ppl=/opt/local --with-cloog=/opt/local --enable-cloog-backend=isl --disable-cloog-version-check --enable-stage1-checking --enable-lto --enable-libstdcxx-time --with-as=/opt/local/bin/as --with-ld=/opt/local/bin/ld --with-ar=/opt/local/bin/ar --with-bugurl=https://trac.macports.org/newticket --disable-ppl-version-check --with-pkgversion='MacPorts gcc47 4.7.2_2+universal'
Thread model: posix
gcc version 4.7.2 (MacPorts gcc47 4.7.2_2+universal) 

问题

我在设置coreutilsgcc的构建环境时是否错过了某个步骤,导致出现此错误?

在尝试解决此错误时,我还可以查找什么其他故障排除方法?我的谷歌搜索并没有带来太多收获。


更改

我按照以下方式更改了构建脚本:

#!/bin/bash -x

WORK_DIR=$PWD
INSTALL_DIR=$WORK_DIR/gcc-4.7.2-darwin
MIN_OSX_VERSION=10.5

if [ -d "$INSTALL_DIR" ]; then
    echo "Directory $INSTALL_DIR already exists";
    exit 1
fi

BINUTILS=binutils-2.23.2
TARBALL_BINUTILS=$BINUTILS.tar.bz2
URL_BINUTILS=http://ftp.gnu.org/gnu/binutils/$TARBALL_BINUTILS
SOURCE_BINUTILS_DIR=$WORK_DIR/$BINUTILS
BUILD_BINUTILS_DIR=$WORK_DIR/build-$BINUTILS

GCC=gcc-4.7.2
TARBALL_GCC=$GCC.tar.bz2
URL_GCC=http://ftp.gnu.org/pub/gnu/gcc/$GCC/$TARBALL_GCC
SOURCE_GCC_DIR=$WORK_DIR/$GCC
BUILD_GCC_DIR=$WORK_DIR/build-$GCC

curl -O $URL_BINUTILS
mkdir -p $SOURCE_BINUTILS_DIR
tar -xjvf $TARBALL_BINUTILS
rm $TARBALL_BINUTILS
mkdir -p $BUILD_BINUTILS_DIR
cd $BUILD_BINUTILS_DIR
$SOURCE_BINUTILS_DIR/configure --prefix=$INSTALL_DIR
make -j $(sysctl -n hw.availcpu) all CFLAGS='-Wno-error' && make install

find $INSTALL_DIR -name '*strip*' -delete

cd $WORK_DIR

curl -O $URL_GCC
mkdir -p $SOURCE_GCC_DIR
tar -xvjf $TARBALL_GCC
rm $TARBALL_GCC
cd $SOURCE_GCC_DIR
sed -i '' -e 's/wget/curl -O/g' $SOURCE_GCC_DIR/contrib/download_prerequisites
$SOURCE_GCC_DIR/contrib/download_prerequisites
cd $WORK_DIR
mkdir -p $BUILD_GCC_DIR
cd $BUILD_GCC_DIR
$SOURCE_GCC_DIR/configure --prefix=$INSTALL_DIR --enable-languages=c,c++
make -j $(sysctl -n hw.availcpu) CFLAGS="-mmacosx-version-min=$MIN_OSX_VERSION" && make install

find $INSTALL_DIR -name '*.a' -print0 | xargs -0 -n1 ranlib

rm -Rf $BUILD_GCC_DIR
rm -Rf $BUILD_BINUTILS_DIR
rm -Rf $SOURCE_GCC_DIR
rm -Rf $SOURCE_BINUTILS_DIR

由于构建库的过程中出现了许多错误,所以需要进行 ranlib 步骤。

要构建一个 i386 二进制文件,需要在 Makefile 中执行以下操作:

ARCH                 = i386
...
GCCDIR               = ${PARTY3}/gcc-4.7.2-darwin
GCCBINDIR            = ${GCCDIR}/bin
GCCLIBDIR            = ${GCCDIR}/lib
GCCINCDIR            = ${GCCDIR}/include
...
LIBCPP               = libgcc_eh.a
LIBCXX               = libstdc++.a
...
INCLUDES             = -I${GCCINCDIR} ...
...
CC                   = ${GCCBINDIR}/gcc
CXX                  = ${GCCBINDIR}/g++
...
GCCCPPLIBPATH        = ${GCCLIBDIR}/gcc/x86_64-apple-darwin12.3.0/4.7.2/${ARCH}/${LIBCPP}
GCCCXXLIBPATH        = ${GCCLIBDIR}/${ARCH}/${LIBCXX}
...
FLAGS                = ${SFLAGS} ${NONSTATICFLAGS} ${OBJS} -L${GCCLIBDIR} ...
...
run: dependencies
    mkdir -p ${BIN} && ${CXX} -o ${BIN}/${PROG}_${ARCH} ${FLAGS} -static-libgcc -mmacosx-version-min=${MIN_OSX_VERSION} -arch ${ARCH} ... ${GCCCPPLIBPATH} ${GCCCXXLIBPATH} ${SOURCE1}

Makefile更改摘要:

  1. 我不得不添加-static-libgcc标志,并省略-static-libstdc++,它没有任何效果(除了导致构建失败,直到我在静态库上运行ranlib,这修复了构建失败,但对-static-libstdc++没有影响)。

  2. 我将${GCCCPPLIBPATH}${GCCCXXLIBPATH}添加到run目标中,每个目标分别指向静态C和C++库libgcc_eh.alibstdc++.a

这使我能够编译一个可用的i386(32位)二进制文件,但是同一GCC安装无法构建一个可用的x86_64(64位)二进制文件。


我还没有构建编译器的目标,但是那些选项 xgcc 失败的情况看起来像是针对 IBM 的 xlc 等编译器的选项。也就是说,配置脚本是否对正在使用的编译器感到困惑了?我会通过追溯生成错误的配置行并尝试理解如何生成该配置行来开始调查。 - Nathan Kidd
1个回答

4

经过一番思考,我发现最简单的解决方案是为x86_64编译GCC,然后在构建i386时只需加上-m32参数。如果没有特殊要求,这样做已经足够了。这种方式的构建方法明显更简单,不需要下面所描述的任何疯狂操作。按照以下步骤进行操作可以得到一个工作正常的编译器,可以生成i386二进制文件:

WORK_DIR=$PWD
INSTALL_DIR=$WORK_DIR/install

curl -O http://ftp.gnu.org/gnu/binutils/binutils-2.23.2.tar.bz2
tar xjvf binutils-2.23.2.tar.bz2
mkdir build-binutils && cd build-binutils
../binutils-2.23.2/configure --prefix=$INSTALL_DIR
make -j $(sysctl -n hw.availcpu) all CFLAGS='-Wno-error' && make install

find $INSTALL_DIR -name '*strip*' -delete

cd $WORK_DIR

curl -O http://ftp.gnu.org/pub/gnu/gcc/gcc-4.7.2/gcc-4.7.2.tar.bz2
tar xvjf gcc-4.7.2.tar.bz2
cd gcc-4.7.2
sed -i '' -e 's/wget/curl -O/g' ./contrib/download_prerequisites
./contrib/download_prerequisites
cd ..
mkdir build-gcc && cd build-gcc
../gcc-4.7.2/configure --prefix=$INSTALL_DIR --enable-languages=c,c++
make -j $(sysctl -n hw.availcpu) && make install

一旦完成,您可以像这样看到它的效果:
mrowe@falcon:~/tmp$ cat > test.cpp
#include <iostream>

int main(int argc, char **argv) {
    std::cerr << "Built with GCC 4.7" << std::endl;
    return 0;
}

^D
mrowe@falcon:~/tmp$ ./install/bin/g++ -o test test.cpp 
mrowe@falcon:~/tmp$ file test
test: Mach-O 64-bit executable x86_64
mrowe@falcon:~/tmp$ ./install/bin/g++ -m32 -static-libgcc -static-libstdc++ -o test test.cpp 
mrowe@falcon:~/tmp$ file test
test: Mach-O executable i386
mrowe@falcon:~/tmp$ otool -L ./test
./test:
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1192.0.0)
mrowe@falcon:~/tmp$ ./test 
Built with GCC 4.7
mrowe@falcon:~/tmp$ 

如果你看到以下警告信息:

ignoring file …/4.7.2/i386/libgcc.a, file was built for archive which is not the architecture being linked (i386)

您可以通过在静态库上运行ranlib来修复它们:
find $INSTALL_DIR -name '*.a' -print0 | xargs -0 -n1 ranlib

以下是我帮助您走上正确道路的尝试。我认为这不是理想的方法,而且存在很多问题。
您报告看到的错误是由于您的GCC构建尝试使用binutils中的GNU汇编器,而生成的汇编代码意图使用来自Apple的cctools的GNU汇编器进行汇编。可支持的汇编语言方言在这两者之间有所不同,因为Apple的汇编器在许多年前就与上游GNU汇编器分离了。
我找到的所有构建cctools的指令都已经过时了,因此我进行了一些实验,直到找到一些可行的方法。我做了类似于以下的事情:
curl -O http://opensource.apple.com/tarballs/cctools/cctools-829.tar.gz
tar xvzf cctools-829.tar.gz
cd cctools-829

为了在没有LLVM的情况下进行构建,您需要修补两个文件:

diff -ru cctools-829/libstuff/lto.c cctools-829.modified/libstuff/lto.c
--- cctools-829/libstuff/lto.c  1969-12-31 16:00:00.000000000 -0800
+++ cctools-829.modified/libstuff/lto.c 2013-04-05 03:18:34.000000000 -0700
@@ -376,4 +376,18 @@
        lto_dispose(mod);
 }

+#else 
+
+#include <stdlib.h>
+
+__private_extern__
+int
+is_llvm_bitcode(
+                struct ofile *ofile,
+                char *addr,
+                size_t size)
+{
+    return 0;
+}
+
 #endif /* LTO_SUPPORT */
diff -ru cctools-829/misc/libtool.c cctools-829.modified/misc/libtool.c
--- cctools-829/misc/libtool.c  1969-12-31 16:00:00.000000000 -0800
+++ cctools-829.modified/misc/libtool.c 2013-04-05 03:20:21.000000000 -0700
@@ -1369,8 +1369,11 @@
                    }
                }
                 }
-                else if(ofiles[i].arch_type == OFILE_Mach_O ||
-                        ofiles[i].arch_type == OFILE_LLVM_BITCODE){
+                else if(ofiles[i].arch_type == OFILE_Mach_O
+#ifdef LTO_SUPPORT
+                            || ofiles[i].arch_type == OFILE_LLVM_BITCODE
+#endif
+                            ){
                if(cmd_flags.ranlib == TRUE){
                    error("for architecture: %s file: %s is not an "
                          "archive (no processing done on this file)",

接着构建:

make install USE_DEPENDENCY_FILE=NO BUILD_DYLIBS=NO LTO= TRIE= DSTROOT=../build-cctools

并手动安装必要的部分:

cd ..
cp build-cctools/usr/bin/as i386-apple-gcc/bin/i386-apple-darwin-as
cp build-cctools/usr/bin/as i386-apple-gcc/i386-apple-darwin/bin/as
cp build-cctools/usr/bin/lipo i386-apple-gcc/bin/i386-apple-darwin-lipo
cp build-cctools/usr/bin/lipo i386-apple-gcc/i386-apple-darwin/bin/lipo
cp build-cctools/usr/bin/strip i386-apple-gcc/bin/i386-apple-darwin-strip
cp build-cctools/usr/bin/strip i386-apple-gcc/i386-apple-darwin/bin/strip

如果我们尝试再次构建GCC,我们会发现构建过程出现了问题,因为我们新构建的汇编程序无法针对x86_64。由于这似乎与您想要实现的目标无关,因此您可以向GCC的配置脚本添加--disable-multilib参数以防止它尝试这样做。
在这一点上,我在尝试构建libgcc时遇到了错误。这些错误是因为找不到合适的链接器,因此我猜现在您需要下载并构建ld64。
在这一点上,我已经没有时间继续下去了。祝你好运!

我会尝试使用你的方法,看看我能否在我的端上复制它。感谢你添加了这么多细节。 - Alex Reynolds
我还尝试了第二个单独的尝试,其中我使用了 llvm-gcc42 并在 ./configure 语句中添加了 CFLAGS='-m32'。在编译约20分钟后,make 步骤失败了。 - Alex Reynolds
你能解释一下为什么你认为常规的64位构建,没有任何特殊选项,不能满足你的需求吗?正如我上面提到的,它默认构建一个编译器和支持库,可以针对32位和64位。它不需要构建cctools,因为它会愉快地使用你的系统版本。当我尝试这种方法时,唯一稍微有点不标准的事情是在配置GCC之前从安装前缀中删除binutils版本的strip,以便使用系统版本。 - bdash
不是我认为它不能做到我想要的,而是它确实不能。无论是使用Xcode开发者工具(LLVM GCC 4.2)还是MacPorts GCC 4.7.2构建它都行不通。在构建过程中,“make”步骤会在某个时刻出现致命错误。在我上面给出的描述中,编译大约一个小时后便会因致命错误而停止。 - Alex Reynolds
我建议您在两个配置脚本中不使用--target=i386-apple-darwin选项尝试上述步骤。这正是我在玩弄了一段时间的cctoolsld64之后尝试的,而且没有任何麻烦。另一个可能有用的提示是使用make -j $(sysctl -n hw.availcpu)进行构建,以确保所有核心都将被使用,甚至可以使用--enable-languages=c,c++配置GCC,以便它不会花费大量时间构建Fortran和Java支持。 - bdash
显示剩余18条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接