How to fix ‘Undefined symbols for architecture arm64: _main’ linker error when building Google Test on Apple Silicon Mac?
I’m encountering a linker error when building Google Test on my Mac with ARM64 processor:
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)
System information:
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
How can I verify that all files are being built for the ARM64 architecture and not accidentally created in backward-compatible mode?
My build process for 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
I’ve confirmed that main() is in the static lib:
nm ${GTEST_ROOT}/libgtest.a | grep main
gtest_main.o:
0000000000000000 T _main
My final link command:
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
The “Undefined symbols for architecture arm64: _main” error occurs because your build process isn’t properly targeting the ARM64 architecture or the main function symbol isn’t being included in the final executable. On Apple Silicon Macs, you need to explicitly specify architecture flags and ensure your build commands are compatible with arm64 rather than x86_64.
Contents
- Understanding the ARM64 Linker Error
- Diagnosing the Build Process
- Fixing the Architecture Targeting Issues
- Correcting the Google Test Build Process
- Verifying Architecture Compatibility
- Complete Solution Example
Understanding the ARM64 Linker Error
The error message “Undefined symbols for architecture arm64: _main” indicates that the linker is trying to build your executable for ARM64 architecture but cannot find the required _main symbol. As Ruby on Mac explains, “Apple Silicon Macs use the arm64 architecture, which is not compatible with the x86_64 architecture.” This creates a mismatch when your build system accidentally targets the wrong architecture.
The _main symbol is the entry point for C++ programs, and its absence suggests either:
- The source file containing
main()isn’t being compiled - The compiled object file isn’t being linked into the final executable
- There’s an architecture mismatch between compiled objects and the linker target
Diagnosing the Build Process
Your current build process has several issues that need to be addressed:
-
Compiler Mismatch: You’re using
g++which may not be properly configured for ARM64 on macOS. Apple recommends usingclang++orclangfor native ARM64 builds. -
Missing Architecture Flags: None of your build commands explicitly specify the target architecture, which can cause the linker to default to x86_64 when Rosetta is available.
-
Library Structure Issue: You’re building Google Test as a static library but the main function should typically be in your test executable, not in the testing framework library.
-
Link Order: Your link command places the main executable object files (
BasicUpTest.o,FixTest.o, etc.) before libraries, which can affect symbol resolution.
Fixing the Architecture Targeting Issues
To ensure all files are built for ARM64 architecture, add these flags to your build commands:
# Set target architecture explicitly
-arch arm64
-target arm64-apple-macos
Modify your build commands to include these architecture flags:
# For building 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
# For your test compilation
clang++ -arch arm64 -target arm64-apple-macos -std=c++20 \
-I${GTEST_ROOT}/googletest/include \
-c your_test_file.cpp
Correcting the Google Test Build Process
Here’s the corrected build process for Google Test on ARM64:
cd ${GTEST_ROOT}
# Build Google Test library with ARM64 flags
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
# Create static library
ar -rv libgtest.a gtest-all.o gtest_main.o
For your final linking, ensure you have a main function in your test code and link everything properly:
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
Verifying Architecture Compatibility
To verify that all files are built for ARM64, use these commands:
# Check architecture of object files
file coverage/*.o
file gtest-all.o gtest_main.o
# Check architecture of static library
file libgtest.a
# Verify main function presence in correct architecture
nm -arch arm64 coverage/unittest.o | grep main
nm -arch arm64 gtest_main.o | grep main
All output should show arm64 architecture. If any files show x86_64, you need to rebuild them with the proper architecture flags.
Complete Solution Example
Here’s a complete working example:
- Build Google Test for ARM64:
cd ${GTEST_ROOT}
mkdir -p build && cd build
cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_CXX_COMPILER=clang++ ..
make
- Or manual build with proper flags:
cd ${GTEST_ROOT}
# Build with explicit ARM64 targeting
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
- Build and link your tests:
# Compile your test with main function
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
# Link everything
clang++ -arch arm64 -target arm64-apple-macos \
-o your_tests \
your_tests.o \
-L${GTEST_ROOT} \
-lgtest -lpthread
Conclusion
To resolve the “Undefined symbols for architecture arm64: _main” error:
- Use Apple’s clang++ compiler instead of g++ for better ARM64 compatibility
- Add explicit architecture flags (
-arch arm64 -target arm64-apple-macos) to all build commands - Ensure proper linking order with object files before libraries
- Verify architecture compatibility using
fileandnm -arch arm64commands - Consider using CMake with
CMAKE_OSX_ARCHITECTURES="arm64"for more reliable builds
The key is to be explicit about targeting ARM64 architecture throughout your entire build process, from individual source files to the final executable link step.