Две вещи:
Я не думаю, что вы на самом деле использовали 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
Вы можете «заставить это работать» с помощью следующего:
shell% gcc -m64 hello.cc -lstdc++
shell% ./a.out
hello world
Во-вторых, -m64
не является предпочтительным способом указания того, что вы хотите генерировать 64-битный код в Mac OS X. Предпочтительным способом является использование -arch ARCH
, где ARCH один из ppc
, ppc64
, i386
или x86_64
. Может быть доступно больше (или меньше) архитектур, в зависимости от того, как настроены ваши инструменты (например, iPhone ARM, устаревший ppc64 и т. Д.). Кроме того, в 10.6 gcc
по умолчанию равно -arch x86_64
или генерируется 64-битный код по умолчанию.
Используя этот стиль, компилятор может автоматически создавать «толстые двоичные файлы» - вы можете использовать -arch
несколько раз. Например, чтобы создать «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
РЕДАКТИРОВАТЬ: Следующее было добавлено, чтобы ответить на вопрос ОП: «Я сделал ошибку и позвонил в мой файл .cc вместо .c. Я все еще не понимаю, почему это должно иметь значение?»
Ну ... это довольно сложный ответ. Я дам краткое объяснение, но я попрошу, чтобы у вас была небольшая вера, что «на самом деле есть веская причина».
Справедливо сказать, что «компиляция программы» - довольно сложный процесс. По историческим и практическим причинам, когда вы выполняете gcc -m64 hello.cc
, он фактически разбивается на несколько отдельных шагов за кулисами. Эти шаги, каждый из которых обычно передает результат каждого шага на следующий шаг, приблизительно:
- Запустите препроцессор C,
cpp
, для исходного кода, который компилируется. Этот шаг отвечает за выполнение всех операторов #include
, различных расширений макросов #define
и других «предварительных обработок».
- Запустите компилятор C правильно для предварительно обработанных результатов C. Результатом этого шага является файл
.s
или результат кода C, скомпилированного для языка ассемблера.
- Запустите
as
ассемблер на источнике .s
. Это собирает язык ассемблера в объектный файл .o
.
- Запустите компоновщик
ld
для файлов .o
, чтобы связать различные скомпилированные объектные файлы и различные статические и динамически связанные библиотеки с используемым исполняемым файлом.
Примечание: Это «типичный» поток для большинства компиляторов. Отдельная реализация компилятора не должна следовать вышеуказанным шагам. Некоторые компиляторы объединяют несколько шагов в один из соображений производительности. Например, современные версии gcc
не используют отдельный проход cpp
. Компилятор tcc
, с другой стороны, выполняет все вышеуказанные шаги за один проход, не используя никаких дополнительных внешних инструментов или промежуточных шагов.
В приведенном выше традиционном потоке цепочек инструментов компилятора команда cc
(или, в нашем случае, gcc
) называется «драйвером компилятора». Это «логический интерфейс» для всех вышеперечисленных инструментов и этапов, и он знает, как разумно применять все этапы и инструменты (например, ассемблер и компоновщик) для создания окончательного исполняемого файла. Однако для этого ему обычно необходимо знать «тип» файла, с которым он имеет дело. Например, вы не можете действительно передать собранный файл .o
в компилятор C. Следовательно, есть пара «стандартных» .*
обозначений, используемых для указания «вида» файла (см. man gcc
для получения дополнительной информации):
.c
, .h
Исходный код C и файлы заголовков C.
.m
Исходный код Objective-C.
.cc
, .cp
, .cpp
, .cxx
, .c++
C ++ Исходный код.
.hh
Файл заголовка C ++.
.mm
, .M
Исходный код Objective-C ++.
.s
Исходный код на ассемблере.
.o
Код собранного объекта.
.a
ar
архив или статическая библиотека.
.dylib
Динамическая разделяемая библиотека.
Также возможно переопределить этот «автоматически определяемый тип файла», используя различные флаги компилятора (см. man gcc
, как это сделать), но, как правило, НАМНОГО проще придерживаться стандартных соглашений, чтобы все «просто работает "автоматически.
И, наоборот, если бы вы использовали «драйвер компилятора» C ++, или g++
, в вашем первоначальном примере, вы бы не столкнулись с этой проблемой:
shell% g++ -m64 hello.cc
shell% ./a.out
hello world
Причина этого в том, что gcc
в основном говорит: «Используйте правила C при управлении цепочкой инструментов», а g++
говорит: «Используйте правила C ++ при управлении цепочкой инструментов». g++
знает, что для создания рабочего исполняемого файла необходимо передать -lstdc++
на этап компоновщика, тогда как gcc
, очевидно, не считает это необходимым, даже если он знал, что использовать компилятор C ++ при «Компиляции исходного кода» code "stage из-за окончания файла .cc
.
Некоторые другие компиляторы C / C ++, доступные для Mac OS X 10.6 по умолчанию: 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
не удалось для вас. :)
РЕДАКТИРОВАТЬ: Еще одна вещь ...
Это обычная «техника драйвера компилятора», когда такие команды, как gcc
и g++
sym-ссылка на один и тот же исполняемый файл драйвера компилятора «все в одном». Затем во время выполнения драйвер компилятора проверяет путь и имя файла, которые использовались для создания процесса, и динамически переключает правила на основе того, заканчивается ли это имя файла gcc
или g++
(или эквивалентным). Это позволяет разработчику компилятора повторно использовать большую часть кода внешнего интерфейса, а затем просто изменить несколько различий, требуемых между ними.