Two things:
I do not think you used gcc -m64 hello.c . The error you received is usually the result of doing something like gcc -m64 hello.cc - using the C compiler to compile C ++ code.
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
You can "make it work" with the following:
shell% gcc -m64 hello.cc -lstdc++ shell% ./a.out hello world
Secondly, -m64 not the preferred way to indicate that you want to generate 64-bit code on Mac OS X. The preferred way is to use -arch ARCH , where ARCH is one of ppc , ppc64 , i386 or x86_64 . Depending on how your tools are configured (e.g. iPhone ARM, ppc64 are outdated, etc.), there may be more (or less) architectures. Also, at 10.6, gcc defaults to -arch x86_64 or generates 64-bit code by default.
Using this style, you can automatically create the "fat binaries" compiler - you can use -arch several times. For example, to create a "Universal binary":
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
EDIT: To answer the OP question, the following was added: "I made a mistake and called the .cc file instead of .c. I'm still confused, why does this matter?"
Well ... that's kind of a tricky answer. I will give a short explanation, but I will ask you to believe a little that "there really is a good reason."
In fairness, it should be said that “compiling a program” is a rather complicated process. For historical and practical reasons, when you run gcc -m64 hello.cc , it actually breaks down into several discrete steps backstage. These stages, each of which usually delivers the result of each step to the next step, are approximately:
- Run the C preprocessor,
cpp , in the source code that compiles. This step is responsible for executing all of the #include statements, various #define macro extensions, and other "preprocesses." - Run your own C compiler for C Pre-Processed results. The result of this step is a
.s file or the result of C code compiled into assembly language. - Run the
as assembler in the .s source. It collects assembly language into an .o object file. - Run the
ld linker in the .o files to link the various compiled object files and various static and dynamically linked libraries with the available executable.
Note: This is a typical thread for most compilers. A separate compiler implementation should not follow the steps described above. Some compilers combine several steps into one of performance considerations. Modern versions of gcc , for example, do not use a separate cpp pass. On the other hand, the tcc compiler performs all of the above steps in one go, without using any additional external tools or intermediate steps.
In the above example, the traditional compiler tool flow, the cc command (or, in our case, gcc ) is called the "compiler driver". This is the “logical interface” for all of the above tools and steps and knows how to intelligently apply all the steps and tools (such as assembler and linker) to create the final executable. However, for this you usually need to know the "look" of the file with which it is dealing. For example, you cannot put the assembled .o file into the C compiler. Thus, there are several “standard” .* Notations used to indicate the “appearance” of a file (see man gcc for more information):
.c , .h source code C and header files C..m Objective-C source code..cc , .cp , .cpp , .cxx , .c++ C ++ source code..hh C ++ header file..mm , .m Objective-C ++ source code..s Source code of source code..o Assembled Object Code..a ar archive or static library..dylib Dynamic shared library.
It is also possible to convince this “automatically determined file type” using various compiler flags (see man gcc how to do this), but as a rule, it’s much simpler to just stick to standard conventions so that everything “just works” automatically.
And in the round, if you used the "compiler" C ++ or g++ , in your original example you would not encounter this problem:
shell% g++ -m64 hello.cc shell% ./a.out hello world
The reason for this is that gcc essentially says: "Use the C rules when managing the tool chain" and g++ says: "Use the C ++ rules when managing the tool chain." g++ knows that in order to create a working executable, it needs to pass -lstdc++ to the linker stage, while gcc obviously doesn’t think it is necessary, even if it knew to use the C ++ compiler in the section “Compile the source of code” because the end of the .cc file.
Some of the other default C / C ++ compilers available to you in Mac OS X 10.6 are: 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 . These tools (usually) replace the first two steps in the tool chain thread and use the same lower level tools as the assembler and linker. llvm- compilers use the external end of gcc to parse C code and convert it to an intermediate representation, and then use the llvm tools to convert this intermediate representation to code. Since llvm tools use a "low-level virtual machine" as its final result, it allows you to use a richer set of optimization strategies, the most notable being that it can perform optimization in different already compiled .o files. This is usually called link time optimization . clang is a completely new C compiler that also targets llvm tools as its output, allowing you to use the same kinds of optimizations.
So you go. Not so short explanation why gcc -m64 hello.cc failed for you. :)
EDIT: One more thing ...
This is a common “compiler driver technique” to have commands like gcc and g++ sym-link with the same all-in-one compiler executable. Then, at run time, the compiler driver checks the path and file name that were used to create the process, and dynamically switches the rules based on whether the file name ends with gcc or g++ (or the equivalent). This allows the compiler developer to reuse the bulk of the front-end code, and then simply change a few differences needed between them.