НейроАгент

Как исправить ошибку 'Undefined symbols for architecture arm64' на Mac

Узнайте, как исправить ошибку 'Undefined symbols for architecture arm64' при сборке Google Test на Mac с процессорами Apple Silicon. Полное руководство с проверкой архитектуры, исправлением сборки и стратегиями предотвращения для разработчиков C++.

Вопрос

Как исправить ошибку “Undefined symbols for architecture arm64” при сборке Google Test на Mac ARM64

Я столкнулся с ошибкой компоновщика при сборке Google Test (gtest) на 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

Процесс сборки

Система сборки сначала создает библиотеки Google Test с помощью этих команд:

bash
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() находится в статической библиотеке:

bash
> nm ${GTEST_ROOT}/libgtest.a | grep main
gtest_main.o:
0000000000000000 T _main

Затем мой файл сборки выполняет:

bash
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

Вопрос

Есть ли способ проверить, что все мои файлы собираются для архитектуры процессора “arm64”, а не случайно создаются в режиме обратной совместимости?

НейроАгент

Неопределенные символы для архитектуры arm64 при сборке Google Test на Mac с Apple Silicon

Ошибка “Неопределенные символы для архитектуры arm64” при сборке Google Test на Mac с Apple Silicon обычно возникает из-за несоответствия архитектуры между файлами сборки и целевой архитектурой. Это происходит, когда библиотеки или объектные файлы скомпилированы для x86_64, а линкер ожидает код для arm64, или когда библиотеки Google Test сами по себе не должным образом скомпилированы для ARM64.

Содержание


Проверка архитектуры сборки

Чтобы убедиться, что ваши файлы собираются для правильной архитектуры arm64, используйте следующие команды:

Проверка архитектуры объектных файлов

Используйте команду file для проверки архитектуры ваших объектных файлов:

bash
file ${GTEST_ROOT}/gtest-all.o
file ${GTEST_ROOT}/gtest_main.o
file coverage/BasicUpTest.o
file coverage/FixTest.o
file coverage/FrameTest.o

Вы должны увидеть вывод, указывающий на архитектуру arm64:

${GTEST_ROOT}/gtest-all.o: Mach-O 64-bit object arm64
${GTEST_ROOT}/gtest_main.o: Mach-O 64-bit object arm64

Проверка архитектуры статической библиотеки

Используйте lipo для проверки срезов архитектуры в вашей статической библиотеке:

bash
lipo -info ${GTEST_ROOT}/libgtest.a

Если она показывает только x86_64 или не содержит информации об архитектуре, вам нужно перекомпилировать ее должным образом для arm64.

Проверка динамических библиотек

Убедитесь, что все системные библиотеки, с которыми вы связываетесь, совместимы:

bash
file /opt/homebrew/lib/libgtest*.dylib 2>/dev/null || echo "Динамические библиотеки gtest не найдены"
lipo -info /opt/homebrew/lib/lib*.a 2>/dev/null | grep gtest || echo "Нет информации об архитектуре для gtest"

Исправление сборки Google Test для ARM64

На основе результатов исследования, вот конкретные исправления для Google Test на ARM64:

Метод 1: Пересборка Google Test с флагами ARM64

Измените команды сборки, чтобы явно указать архитектуру:

bash
cd ${GTEST_ROOT}
g++ -std=c++20 -I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
    -c ${GTEST_ROOT}/googletest/src/gtest-all.cc -arch arm64
g++ -std=c++20 -I${GTEST_ROOT}/googletest/include -I${GTEST_ROOT}/googletest \
    -c ${GTEST_ROOT}/googletest/src/gtest_main.cc -arch arm64
ar -rv libgtest.a gtest-all.o gtest_main.o

Метод 2: Использование Google Test из Homebrew

Согласно обсуждению на Stack Overflow, вам может потребоваться версия Google Test из Homebrew:

bash
brew install googletest

Затем используйте библиотеки Homebrew в вашей сборке:

bash
g++ -o coverage/unittest.prog \
    coverage/BasicUpTest.o coverage/FixTest.o coverage/FrameTest.o coverage/unittest.o \
    -L/opt/homebrew/lib -lgtest -lgtest_main -lpthread \
    -std=c++20 -arch arm64

Метод 3: Правильная сборка из исходного кода

Проблема на GitHub #3802 указывает на то, что предварительно скомпилированный libgtest.a может не содержать архитектуру arm64. Соберите из исходного кода:

bash
cd ${GTEST_ROOT}
mkdir build && cd build
cmake .. -DCMAKE_OSX_ARCHITECTURES="arm64"
make

Это создаст библиотеки, совместимые с ARM64.


Распространенные решения

Компиляция для конкретной архитектуры

Убедитесь, что все команды компиляции включают флаг -arch arm64:

bash
# Для ваших тестовых файлов
g++ -c coverage/BasicUpTest.cpp -o coverage/BasicUpTest.o -std=c++20 -arch arm64
g++ -c coverage/FixTest.cpp -o coverage/FixTest.o -std=c++20 -arch arm64
g++ -c coverage/FrameTest.cpp -o coverage/FrameTest.o -std=c++20 -arch arm64
g++ -c coverage/unittest.cpp -o coverage/unittest.o -std=c++20 -arch arm64

Указание архитектуры в линкере

Добавьте флаги архитектуры в конечную команду линковки:

bash
g++ -o coverage/unittest.prog \
    coverage/BasicUpTest.o coverage/FixTest.o coverage/FrameTest.o coverage/unittest.o \
    -L./coverage -L../coverage -L${GTEST_ROOT} -lgtest \
    -fPIC -g -std=c++20 -fprofile-arcs -ftest-coverage -lpthread \
    -arch arm64

Использование динамических библиотек

Как упоминалось в исследованиях, некоторые пользователи добились успеха, используя .dylib вместо .a файлов:

bash
# При необходимости преобразуйте статическую библиотеку в динамическую
g++ -shared -o libgtest.so ${GTEST_ROOT}/gtest-all.o ${GTEST_ROOT}/gtest_main.o

Затем свяжитесь с динамической библиотекой:

bash
g++ -o coverage/unittest.prog \
    coverage/*.o -L${GTEST_ROOT} -lgtest \
    -std=c++20 -arch arm64

Стратегии предотвращения

Конфигурация сборки

Настройте вашу систему сборки так, чтобы она всегда нацеливалась на правильную архитектуру:

bash
# Создайте скрипт сборки с определением архитектуры
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
    CXX_ARCH_FLAGS="-arch arm64"
else
    CXX_ARCH_FLAGS=""
fi

echo "Сборка для архитектуры: $ARCH"

Настройки проекта Xcode (если применимо)

При использовании Xcode убедитесь, что:

  1. Build Active Architecture Only = NO
  2. Valid Architectures включает arm64
  3. Архитектуры в Build Settings установлены в $(ARCHS_STANDARD_64_BIT)

Непрерывная интеграция

Добавьте проверки архитектуры в ваш CI-конвейер:

bash
# Проверяем, что все библиотеки имеют правильную архитектуру
check_architecture() {
    local lib_path=$1
    if lipo -info "$lib_path" | grep -q "arm64"; then
        echo "✓ $lib_path содержит архитектуру arm64"
        return 0
    else
        echo "✗ $lib_path отсутствует архитектура arm64"
        return 1
    fi
}

Чек-лист для устранения неполадок

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

  1. Проверка системной архитектуры

    bash
    uname -m  # Должно показать arm64
    
  2. Проверка всех объектных файлов

    bash
    find . -name "*.o" -exec file {} \; | grep -v arm64
    
  3. Проверка архитектур библиотек

    bash
    lipo -info libgtest.a
    lipo -info /opt/homebrew/lib/libgtest*.a 2>/dev/null
    
  4. Очистка и пересборка

    bash
    rm -f *.o *.a
    # Пересоберите с правильными флагами
    
  5. Пошаговая проверка этапа линковки

    bash
    # Сначала свяжите только библиотеку GTest
    g++ -o test_gtest -L${GTEST_ROOT} -lgtest -arch arm64
    
  6. Проверка отсутствующих символов

    bash
    nm -U libgtest.a | grep "testing::"
    
  7. Проверка совместимости компилятора

    bash
    g++ -v | grep -E "Target|Architecture"
    

Ключевым является обеспечение того, чтобы каждый компонент в вашей цепочке сборки - от отдельных объектных файлов до конечных библиотек - был явно скомпилирован для архитектуры arm64. Как отмечено в обсуждении на Stack Overflow, это несоответствие архитектуры особенно часто встречается со статическими библиотеками на Mac с Apple Silicon.

Источники

  1. Stack Overflow: symbol(s) not found for architecture arm64 while writing unit tests through Google Test library on M1 Chip
  2. GitHub Issue: apple M1 chip Mac build failed because of */libgtest.a does not contain the arm64 architecture
  3. Stack Overflow: Undefined symbols for architecture arm64
  4. Exercism Issue: x86_64 on Apple Silicon: ld: symbol(s) not found for architecture arm64
  5. Apple Developer Forums: ld: symbol(s) not found for architecture arm64

Заключение

Ошибка “Неопределенные символы для архитектуры arm64” при сборке Google Test на Mac с Apple Silicon обычно вызвана несоответствием архитектуры в вашей цепочке сборки. Чтобы решить эту проблему:

  • Всегда проверяйте, что все объектные файлы и библиотеки скомпилированы специально для arm64 с помощью команд file и lipo
  • Пересоберите Google Test с явными флагами -arch arm64 или используйте версию из Homebrew
  • Обеспечьте согласованность архитектуры на всех этапах компиляции и линковки
  • Рассмотрите возможность использования динамических библиотек (.dylib), если статические библиотеки продолжают вызывать проблемы
  • Реализуйте проверки архитектуры в процессе сборки для предотвращения будущих проблем

Систематически проверяя каждый компонент в вашей цепочке сборки и убедившись, что они все нацелены на правильную архитектуру arm64, вы можете решить эту ошибку линкера и успешно собрать Google Test на вашем Mac с Apple Silicon.