Как исправить ошибку линкера ‘Undefined symbols for architecture arm64: _main’ при сборке Google Test на Mac с процессором Apple Silicon?
Я столкнулся с ошибкой линкера при сборке Google Test на моем Mac с процессором ARM64:
Undefined symbols for architecture arm64:
"_main", referenced from:
<initial-undefines>
ld: symbol(s) not found for architecture arm64
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
Информация о системе:
uname -a
Darwin Martins-MacBook-Pro-2.local 25.0.0 Darwin Kernel Version 25.0.0: Wed Sep 17 21:41:45 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T6000 arm64
Как я могу проверить, что все файлы собираются для архитектуры ARM64, а не случайно создаются в режиме обратной совместимости?
Мой процесс сборки Google Test:
cd ${GTEST_ROOT}
g++ -std=c++20 -I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest -c ${GTEST_ROOT}/googletest/src/gtest-all.cc
g++ -std=c++20 -I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest -c ${GTEST_ROOT}/googletest/src/gtest_main.cc
ar -rv libgtest.a gtest-all.o gtest_main.o
Я подтвердил, что main() находится в статической библиотеке:
nm ${GTEST_ROOT}/libgtest.a | grep main
gtest_main.o:
0000000000000000 T _main
Моя итоговая команда линковки:
g++ \
-o coverage/unittest.prog \
-L/opt/homebrew/lib \
coverage/BasicUpTest.o \
coverage/FixTest.o \
coverage/FrameTest.o \
coverage/unittest.o \
-fPIC \
-g \
-std=c++20 \
-L./coverage \
-lUnitTest \
-L../coverage \
-L${GTEST_ROOT} \
-lgtest \
-fprofile-arcs \
-ftest-coverage \
-lpthread
Ошибка “Undefined symbols for architecture arm64: _main” возникает из-за того, что процесс сборки не правильно нацелен на архитектуру ARM64 или символ функции main не включается в конечный исполняемый файл. На компьютерах Mac с Apple Silicon необходимо явно указать флаги архитектуры и убедиться, что команды сборки совместимы с arm64, а не с x86_64.
Содержание
- Понимание ошибки линковщика ARM64
- Диагностика процесса сборки
- Исправление проблем с целевой архитектурой
- Исправление процесса сборки Google Test
- Проверка совместимости архитектур
- Полный пример решения
Понимание ошибки линковщика ARM64
Сообщение об ошибке “Undefined symbols for architecture arm64: _main” указывает на то, что линковщик пытается собрать исполняемый файл для архитектуры ARM64, но не может найти требуемый символ _main. Как объясняется в Ruby on Mac, “компьютеры Mac с Apple Silicon используют архитектуру arm64, которая несовместима с архитектурой x86_64”. Это создает несоответствие, когда ваша система сборки случайно нацелена на неправильную архитектуру.
Символ _main является точкой входа для программ на C++, и его отсутствие указывает на то, что либо:
- исходный файл, содержащий
main(), не компилируется - скомпилированный объектный файл не линкуется в конечный исполняемый файл
- существует несоответствие архитектуры между скомпилированными объектами и целевой архитектурой линковщика
Диагностика процесса сборки
Ваш текущий процесс сборки имеет несколько проблем, которые необходимо решить:
-
Несоответствие компилятора: Вы используете
g++, который может быть неправильно настроен для ARM64 в macOS. Apple рекомендует использоватьclang++илиclangдля нативных сборок ARM64. -
Отсутствие флагов архитектуры: Ни одна из ваших команд сборки явно не указывает целевую архитектуру, что может привести к тому, что линковщик по умолчанию будет использовать x86_64, когда доступен Rosetta.
-
Проблема со структурой библиотеки: Вы собираете Google Test как статическую библиотеку, но функция main обычно должна находиться в вашем исполняемом файле теста, а не в библиотеке фреймворка тестирования.
-
Порядок линковки: Ваша команда линковки помещает объектные файлы основного исполняемого файла (
BasicUpTest.o,FixTest.oи т.д.) перед библиотеками, что может повлиять на разрешение символов.
Исправление проблем с целевой архитектурой
Чтобы убедиться, что все файлы собраны для архитектуры ARM64, добавьте эти флаги в команды сборки:
# Явно установить целевую архитектуру
-arch arm64
-target arm64-apple-macos
Измените команды сборки, чтобы включить эти флаги архитектуры:
# Для сборки Google Test
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
-c ${GTEST_ROOT}/googletest/src/gtest-all.cc
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
-c ${GTEST_ROOT}/googletest/src/gtest_main.cc
# Для компиляции ваших тестов
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include \
-c your_test_file.cpp
Исправление процесса сборки Google Test
Вот исправленный процесс сборки Google Test для ARM64:
cd ${GTEST_ROOT}
# Сборка библиотеки Google Test с флагами ARM64
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
-c ${GTEST_ROOT}/googletest/src/gtest-all.cc -o gtest-all.o
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
-c ${GTEST_ROOT}/googletest/src/gtest_main.cc -o gtest_main.o
# Создание статической библиотеки
ar -rv libgtest.a gtest-all.o gtest_main.o
Для финальной линковки убедитесь, что у вас есть функция main в вашем тестовом коде и все правильно слинковано:
clang++ -arch arm64 -target arm64-apple-macos \
-o coverage/unittest.prog \
coverage/BasicUpTest.o \
coverage/FixTest.o \
coverage/FrameTest.o \
coverage/unittest.o \
-fPIC -g -std=c++20 \
-L./coverage -L../coverage -L${GTEST_ROOT} \
-L/opt/homebrew/lib \
-lgtest -lpthread \
-fprofile-arcs -ftest-coverage
Проверка совместимости архитектур
Чтобы убедиться, что все файлы собраны для ARM64, используйте эти команды:
# Проверка архитектуры объектных файлов
file coverage/*.o
file gtest-all.o gtest_main.o
# Проверка архитектуры статической библиотеки
file libgtest.a
# Проверка наличия функции main в правильной архитектуре
nm -arch arm64 coverage/unittest.o | grep main
nm -arch arm64 gtest_main.o | grep main
Весь вывод должен показывать архитектуру arm64. Если какие-либо файлы показывают x86_64, вам нужно пересобрать их с правильными флагами архитектуры.
Полный пример решения
Вот полный рабочий пример:
- Сборка Google Test для ARM64:
cd ${GTEST_ROOT}
mkdir -p build && cd build
cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_CXX_COMPILER=clang++ ..
make
- Или ручная сборка с правильными флагами:
cd ${GTEST_ROOT}
# Сборка с явным указанием ARM64
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I./googletest/include -I./googletest \
-c ./googletest/src/gtest-all.cc -o gtest-all.o
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I./googletest/include -I./googletest \
-c ./googletest/src/gtest_main.cc -o gtest_main.o
ar -rv libgtest.a gtest-all.o gtest_main.o
- Сборка и линковка ваших тестов:
# Компиляция ваших тестов с функцией main
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include \
-c your_tests_with_main.cpp -o your_tests.o
# Линковка всего вместе
clang++ -arch arm64 -target arm64-apple-macos \
-o your_tests \
your_tests.o \
-L${GTEST_ROOT} \
-lgtest -lpthread
Заключение
Чтобы устранить ошибку “Undefined symbols for architecture arm64: _main”:
- Используйте компилятор clang++ от Apple вместо g++ для лучшей совместимости с ARM64
- Добавляйте явные флаги архитектуры (
-arch arm64 -target arm64-apple-macos) во все команды сборки - Обеспечьте правильный порядок линковки с объектными файлами перед библиотеками
- Проверяйте совместимость архитектур с помощью команд
fileиnm -arch arm64 - Рассмотрите возможность использования CMake с
CMAKE_OSX_ARCHITECTURES="arm64"для более надежной сборки
Ключевым моментом является явное указание целевой архитектуры ARM64 на протяжении всего процесса сборки, от отдельных исходных файлов до финального шага линковки исполняемого файла.