Как исправить ошибку “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 с помощью этих команд:
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
Вопрос
Есть ли способ проверить, что все мои файлы собираются для архитектуры процессора “arm64”, а не случайно создаются в режиме обратной совместимости?
Неопределенные символы для архитектуры arm64 при сборке Google Test на Mac с Apple Silicon
Ошибка “Неопределенные символы для архитектуры arm64” при сборке Google Test на Mac с Apple Silicon обычно возникает из-за несоответствия архитектуры между файлами сборки и целевой архитектурой. Это происходит, когда библиотеки или объектные файлы скомпилированы для x86_64, а линкер ожидает код для arm64, или когда библиотеки Google Test сами по себе не должным образом скомпилированы для ARM64.
Содержание
- Проверка архитектуры сборки
- Исправление сборки Google Test для ARM64
- Распространенные решения
- Стратегии предотвращения
- Чек-лист для устранения неполадок
Проверка архитектуры сборки
Чтобы убедиться, что ваши файлы собираются для правильной архитектуры arm64, используйте следующие команды:
Проверка архитектуры объектных файлов
Используйте команду file для проверки архитектуры ваших объектных файлов:
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 для проверки срезов архитектуры в вашей статической библиотеке:
lipo -info ${GTEST_ROOT}/libgtest.a
Если она показывает только x86_64 или не содержит информации об архитектуре, вам нужно перекомпилировать ее должным образом для arm64.
Проверка динамических библиотек
Убедитесь, что все системные библиотеки, с которыми вы связываетесь, совместимы:
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
Измените команды сборки, чтобы явно указать архитектуру:
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:
brew install googletest
Затем используйте библиотеки Homebrew в вашей сборке:
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. Соберите из исходного кода:
cd ${GTEST_ROOT}
mkdir build && cd build
cmake .. -DCMAKE_OSX_ARCHITECTURES="arm64"
make
Это создаст библиотеки, совместимые с ARM64.
Распространенные решения
Компиляция для конкретной архитектуры
Убедитесь, что все команды компиляции включают флаг -arch arm64:
# Для ваших тестовых файлов
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
Указание архитектуры в линкере
Добавьте флаги архитектуры в конечную команду линковки:
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 файлов:
# При необходимости преобразуйте статическую библиотеку в динамическую
g++ -shared -o libgtest.so ${GTEST_ROOT}/gtest-all.o ${GTEST_ROOT}/gtest_main.o
Затем свяжитесь с динамической библиотекой:
g++ -o coverage/unittest.prog \
coverage/*.o -L${GTEST_ROOT} -lgtest \
-std=c++20 -arch arm64
Стратегии предотвращения
Конфигурация сборки
Настройте вашу систему сборки так, чтобы она всегда нацеливалась на правильную архитектуру:
# Создайте скрипт сборки с определением архитектуры
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
CXX_ARCH_FLAGS="-arch arm64"
else
CXX_ARCH_FLAGS=""
fi
echo "Сборка для архитектуры: $ARCH"
Настройки проекта Xcode (если применимо)
При использовании Xcode убедитесь, что:
- Build Active Architecture Only = NO
- Valid Architectures включает arm64
- Архитектуры в Build Settings установлены в $(ARCHS_STANDARD_64_BIT)
Непрерывная интеграция
Добавьте проверки архитектуры в ваш CI-конвейер:
# Проверяем, что все библиотеки имеют правильную архитектуру
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
}
Чек-лист для устранения неполадок
Используйте этот систематический подход для диагностики и исправления проблемы:
-
Проверка системной архитектуры
bashuname -m # Должно показать arm64 -
Проверка всех объектных файлов
bashfind . -name "*.o" -exec file {} \; | grep -v arm64 -
Проверка архитектур библиотек
bashlipo -info libgtest.a lipo -info /opt/homebrew/lib/libgtest*.a 2>/dev/null
-
Очистка и пересборка
bashrm -f *.o *.a # Пересоберите с правильными флагами -
Пошаговая проверка этапа линковки
bash# Сначала свяжите только библиотеку GTest g++ -o test_gtest -L${GTEST_ROOT} -lgtest -arch arm64 -
Проверка отсутствующих символов
bashnm -U libgtest.a | grep "testing::" -
Проверка совместимости компилятора
bashg++ -v | grep -E "Target|Architecture"
Ключевым является обеспечение того, чтобы каждый компонент в вашей цепочке сборки - от отдельных объектных файлов до конечных библиотек - был явно скомпилирован для архитектуры arm64. Как отмечено в обсуждении на Stack Overflow, это несоответствие архитектуры особенно часто встречается со статическими библиотеками на Mac с Apple Silicon.
Источники
- Stack Overflow: symbol(s) not found for architecture arm64 while writing unit tests through Google Test library on M1 Chip
- GitHub Issue: apple M1 chip Mac build failed because of */libgtest.a does not contain the arm64 architecture
- Stack Overflow: Undefined symbols for architecture arm64
- Exercism Issue: x86_64 on Apple Silicon: ld: symbol(s) not found for architecture arm64
- 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.