НейроАгент

Исправление ошибки линковщика Google Test ARM64: Полное руководство

Решение ошибки 'Undefined symbols for architecture arm64: _main' при сборке Google Test на Mac с процессором Apple Silicon. Полное руководство с флагами архитектуры и решениями для линковки.

Вопрос

Как исправить ошибку линкера ‘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

Сообщение об ошибке “Undefined symbols for architecture arm64: _main” указывает на то, что линковщик пытается собрать исполняемый файл для архитектуры ARM64, но не может найти требуемый символ _main. Как объясняется в Ruby on Mac, “компьютеры Mac с Apple Silicon используют архитектуру arm64, которая несовместима с архитектурой x86_64”. Это создает несоответствие, когда ваша система сборки случайно нацелена на неправильную архитектуру.

Символ _main является точкой входа для программ на C++, и его отсутствие указывает на то, что либо:

  • исходный файл, содержащий main(), не компилируется
  • скомпилированный объектный файл не линкуется в конечный исполняемый файл
  • существует несоответствие архитектуры между скомпилированными объектами и целевой архитектурой линковщика

Диагностика процесса сборки

Ваш текущий процесс сборки имеет несколько проблем, которые необходимо решить:

  1. Несоответствие компилятора: Вы используете g++, который может быть неправильно настроен для ARM64 в macOS. Apple рекомендует использовать clang++ или clang для нативных сборок ARM64.

  2. Отсутствие флагов архитектуры: Ни одна из ваших команд сборки явно не указывает целевую архитектуру, что может привести к тому, что линковщик по умолчанию будет использовать x86_64, когда доступен Rosetta.

  3. Проблема со структурой библиотеки: Вы собираете Google Test как статическую библиотеку, но функция main обычно должна находиться в вашем исполняемом файле теста, а не в библиотеке фреймворка тестирования.

  4. Порядок линковки: Ваша команда линковки помещает объектные файлы основного исполняемого файла (BasicUpTest.o, FixTest.o и т.д.) перед библиотеками, что может повлиять на разрешение символов.

Исправление проблем с целевой архитектурой

Чтобы убедиться, что все файлы собраны для архитектуры ARM64, добавьте эти флаги в команды сборки:

bash
# Явно установить целевую архитектуру
-arch arm64
-target arm64-apple-macos

Измените команды сборки, чтобы включить эти флаги архитектуры:

bash
# Для сборки 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:

bash
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 в вашем тестовом коде и все правильно слинковано:

bash
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, используйте эти команды:

bash
# Проверка архитектуры объектных файлов
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, вам нужно пересобрать их с правильными флагами архитектуры.


Полный пример решения

Вот полный рабочий пример:

  1. Сборка Google Test для ARM64:
bash
cd ${GTEST_ROOT}
mkdir -p build && cd build

cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_CXX_COMPILER=clang++ ..
make
  1. Или ручная сборка с правильными флагами:
bash
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
  1. Сборка и линковка ваших тестов:
bash
# Компиляция ваших тестов с функцией 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”:

  1. Используйте компилятор clang++ от Apple вместо g++ для лучшей совместимости с ARM64
  2. Добавляйте явные флаги архитектуры (-arch arm64 -target arm64-apple-macos) во все команды сборки
  3. Обеспечьте правильный порядок линковки с объектными файлами перед библиотеками
  4. Проверяйте совместимость архитектур с помощью команд file и nm -arch arm64
  5. Рассмотрите возможность использования CMake с CMAKE_OSX_ARCHITECTURES="arm64" для более надежной сборки

Ключевым моментом является явное указание целевой архитектуры ARM64 на протяжении всего процесса сборки, от отдельных исходных файлов до финального шага линковки исполняемого файла.

Источники

  1. Ruby on Mac - ld: symbol(s) not found for architecture x86_64
  2. Документация для разработчиков Apple - Сборка для Apple Silicon
  3. Официальная документация Google Test - Сборка Google Test