NeuroAgent

Fix Google Test ARM64 Linker Error: Complete Guide

Solve 'Undefined symbols for architecture arm64: _main' error when building Google Test on Apple Silicon Mac. Complete guide with architecture flags and linking solutions.

Question

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
NeuroAgent

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

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:

  1. Compiler Mismatch: You’re using g++ which may not be properly configured for ARM64 on macOS. Apple recommends using clang++ or clang for native ARM64 builds.

  2. 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.

  3. 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.

  4. 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:

bash
# Set target architecture explicitly
-arch arm64
-target arm64-apple-macos

Modify your build commands to include these architecture flags:

bash
# 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:

bash
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:

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

Verifying Architecture Compatibility

To verify that all files are built for ARM64, use these commands:

bash
# 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:

  1. Build Google Test for ARM64:
bash
cd ${GTEST_ROOT}
mkdir -p build && cd build

cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_CXX_COMPILER=clang++ ..
make
  1. Or manual build with proper flags:
bash
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
  1. Build and link your tests:
bash
# 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:

  1. Use Apple’s clang++ compiler instead of g++ for better ARM64 compatibility
  2. Add explicit architecture flags (-arch arm64 -target arm64-apple-macos) to all build commands
  3. Ensure proper linking order with object files before libraries
  4. Verify architecture compatibility using file and nm -arch arm64 commands
  5. 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.

Sources

  1. Ruby on Mac - ld: symbol(s) not found for architecture x86_64
  2. Apple Developer Documentation - Building for Apple Silicon
  3. Google Test Official Documentation - Building Google Test