GCC试图在OSX 10.6上编译64位代码

Dan*_*iel 4 c c++ macos gcc

我有一个全新的非CD OSX 10.6安装.我现在想将以下简单的C程序编译为64位二进制文​​件:

 #include <stdio.h>

 int main() 
 {
    printf("hello world");
    return 0;
 }
Run Code Online (Sandbox Code Playgroud)

我调用gcc如下:

gcc -m64 hello.c
Run Code Online (Sandbox Code Playgroud)

但是,这失败并出现以下错误:

未定义的符号:

  "___gxx_personality_v0", referenced from:
  _main in ccUAOnse.o
  CIE in ccUAOnse.o
  ld: symbol(s) not found
  collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么gcc会死?没有-m64标志的编译工作正常.

joh*_*hne 17

两件事情:

我不认为你真的用过gcc -m64 hello.c.你得到的错误通常是做类似的事情gcc -m64 hello.cc- 使用C编译器编译C++代码.

shell% gcc -m64 hello.c
shell% ./a.out
hello world [added missing newline]
shell% cp hello.c hello.cc
shell% gcc -m64 hello.cc
Undefined symbols:
  "___gxx_personality_v0", referenced from:
      _main in ccYaNq32.o
      CIE in ccYaNq32.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式"使其工作":

shell% gcc -m64 hello.cc -lstdc++
shell% ./a.out
hello world
Run Code Online (Sandbox Code Playgroud)

其次,-m64是不是指定你想在Mac OS X上生成64位代码的首选方式的首选方式是使用-arch ARCH,其中ARCH是之一ppc,ppc64,i386,或x86_64.可能有更多(或更少)架构可用,具体取决于您的工具设置方式(即iPhone ARM,ppc64弃用等).此外,在10.6上,gcc默认为默认值-arch x86_64或生成64位代码.

使用这种风格,编译器可以自动创建"胖二进制文件" - 您可以-arch多次使用.例如,要创建"通用二进制":

shell% gcc -arch x86_64 -arch i386 -arch ppc hello.c
shell% file a.out
a.out: Mach-O universal binary with 3 architectures
a.out (for architecture x86_64):    Mach-O 64-bit executable x86_64
a.out (for architecture i386):  Mach-O executable i386
a.out (for architecture ppc7400):   Mach-O executable ppc
Run Code Online (Sandbox Code Playgroud)

编辑:添加以下内容来回答OP的问题"我确实犯了一个错误,并调用我的文件.cc而不是.c.我仍然感到困惑,为什么这应该重要?"

嗯......这是一个复杂的答案.我会给出一个简短的解释,但我会问你有一点信心"实际上有一个很好的理由."

可以说"编译程序"是一个相当复杂的过程.出于历史和实际原因,当你执行时gcc -m64 hello.cc,它实际上分解为幕后的几个不连续的步骤.这些步骤通常将每个步骤的结果提供给下一步骤,大致是:

  • cpp正在编译的源代码上运行C预处理器.此步骤负责执行所有#include语句,各种#define宏扩展和其他"预处理"内容.
  • 在C预处理结果上正确运行C编译器.此步骤的输出是.s文件,或编译为汇编语言的C代码的结果.
  • as.s源上运行汇编程序.这将汇编语言汇编到.o目标文件中.
  • ld.o文件上运行链接器,将各种编译的目标文件以及各种静态和动态链接的库链接到可用的可执行文件中.

注意:对于大多数编译器来说,这是一个"典型"流程.编译器的单独实现不必遵循上述步骤.出于性能原因,一些编译器将多个步骤合并为一个.gcc例如,现代版本不使用单独的cpp传递.的tcc编译器,在另一方面,在执行一次通过上述所有步骤,不使用附加的外部工具或中间步骤.

在上面,传统的编译器工具链流,cc(或者,在我们的例子中gcc)命令被称为"编译器驱动程序".它是所有上述工具和步骤的"逻辑前端",并且知道如何智能地应用所有步骤和工具(如汇编器和链接器)以创建最终的可执行文件.但是,为了做到这一点,它通常需要知道它正在处理的"那种"文件.例如,您无法将已组装的.o文件提供给C编译器.因此,有一些"标准" .*名称用于指定文件的"种类"(man gcc有关详细信息,请参阅参考资料):

  • .c,.hC源代码和C头文件.
  • .m Objective-C源代码.
  • .cc,.cp,.cpp,.cxx,.c++C++的源代码.
  • .hh C++头文件.
  • .mm,.MObjective-C++源代码.
  • .s 汇编语言源代码.
  • .o 汇编目标代码.
  • .a ar 存档或静态库.
  • .dylib 动态共享库.

也可以使用各种编译器标志来覆盖这种"自动确定的文件类型"(请参阅man gcc如何执行此操作),但通常更容易遵守标准约定,以便所有内容"自行运行".

而且,如果您使用了C++"编译器驱动程序",或者g++在原始示例中,您将不会遇到此问题:

shell% g++ -m64 hello.cc
shell% ./a.out
hello world
Run Code Online (Sandbox Code Playgroud)

其原因gcc主要是"在驱动工具链时使用C规则",并g++说"在驱动工具链时使用C++规则". g++知道要创建一个工作的可执行文件,它需要传递-lstdc++给链接器阶段,而gcc显然不认为这是必要的,即使它知道在"编译源代码"阶段使用C++编译器,因为.cc文件结束.

默认情况下,一些在Mac OS X 10.6为您提供的其他C/C++编译器:gcc-4.0,gcc-4.2,g++-4.0,g++-4.2,llvm-gcc,llvm-g++,llvm-gcc-4.0,llvm-g++-4.0,llvm-gcc-4.2,llvm-g++-4.2,clang.这些工具(通常)交换工具链流程中的前两个步骤,并使用相同的低级工具,如汇编程序和链接程序.所述llvm-编译器使用的gcc前端来解析C代码,并把它在成中间表示,然后使用llvm工具来变换中间表示中的代码.自从llvm工具使用"低级虚拟机"作为其近端输出,它允许更丰富的优化策略集,最值得注意的是它可以跨不同的已编译.o文件执行优化.这通常被称为link time optimization. clang是一个全新的C编译器,它也将llvm工具作为其输出,允许相同类型的优化.

所以,你去吧.gcc -m64 hello.cc对你失败的原因并不那么简短.:)

编辑:还有一件事......

这是一种常见的"编译器驱动程序技术",它具有与同一"一体化"编译器驱动程序可执行文件相同的命令gccg++sym-link.然后,在运行时,编译器驱动程序的文件名是否与结束检查该用于创建过程和动态地切换基于规则的路径和文件名gccg++(或等同物).这允许编译器的开发人员重新使用大量的前端代码,然后只需更改两者之间所需的少量差异.