NeuroAgent

Fix 'Undefined symbols for architecture arm64' Error on Mac

Learn how to fix 'Undefined symbols for architecture arm64' error when building Google Test on Apple Silicon Macs. Complete guide with architecture verification, build fixes, and prevention strategies for C++ developers.

Question

How to Fix “Undefined symbols for architecture arm64” When Building Google Test on Mac ARM64

I’m encountering a linker error when building Google Test (gtest) on a Mac with ARM64 architecture. The error message is:

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)

My 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

Build Process

The build system first creates the Google Test libraries with these commands:

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

I’ve verified that main() is in the static library:

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

Then my build file executes:

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

Question

Is there a way to verify that all my files are being built for the “arm64” processor architecture, and not accidentally created in a backward-compatible mode?

NeuroAgent

The “Undefined symbols for architecture arm64” error when building Google Test on Apple Silicon Macs typically occurs due to architecture mismatches between your build files and the target architecture. This happens when libraries or object files are compiled for x86_64 but the linker expects arm64 code, or when the Google Test libraries themselves aren’t properly built for ARM64.

Contents


Verifying Build Architecture

To verify that your files are being built for the correct arm64 architecture, use these commands:

Check Object File Architecture

Use the file command to verify the architecture of your object files:

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

You should see output indicating arm64 architecture:

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

Check Static Library Architecture

Use lipo to inspect the architecture slices in your static library:

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

If it only shows x86_64 or no architecture information, you need to rebuild it properly for arm64.

Check Dynamic Libraries

Verify that any system libraries you’re linking against are compatible:

bash
file /opt/homebrew/lib/libgtest*.dylib 2>/dev/null || echo "No dynamic gtest libraries found"
lipo -info /opt/homebrew/lib/lib*.a 2>/dev/null | grep gtest || echo "No architecture info for gtest"

Fixing Google Test Build for ARM64

Based on the research findings, here are the specific fixes for Google Test on ARM64:

Method 1: Rebuild Google Test with ARM64 Flags

Modify your build commands to explicitly specify the architecture:

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

Method 2: Use Homebrew Google Test

According to the Stack Overflow discussion, you might need to use the Homebrew version:

bash
brew install googletest

Then use the Homebrew libraries in your build:

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

Method 3: Build from Source Properly

The GitHub issue #3802 indicates that the pre-built libgtest.a may not contain arm64 architecture. Build from source:

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

This will create properly ARM64-compatible libraries.


Common Solutions

Architecture-Specific Compilation

Ensure all your compilation commands include the -arch arm64 flag:

bash
# For your test files
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

Linker Architecture Specification

Add architecture flags to your final link command:

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

Use of Dynamic Libraries

As mentioned in the research, some users found success using .dylib instead of .a files:

bash
# Convert static library to dynamic if needed
g++ -shared -o libgtest.so ${GTEST_ROOT}/gtest-all.o ${GTEST_ROOT}/gtest_main.o

Then link with the dynamic library:

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

Prevention Strategies

Build Configuration

Set up your build system to always target the correct architecture:

bash
# Create a build script with architecture detection
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
    CXX_ARCH_FLAGS="-arch arm64"
else
    CXX_ARCH_FLAGS=""
fi

echo "Building for architecture: $ARCH"

Xcode Project Settings (if applicable)

If using Xcode, ensure:

  1. Build Active Architecture Only = NO
  2. Valid Architectures includes arm64
  3. Architectures in Build Settings set to $(ARCHS_STANDARD_64_BIT)

Continuous Integration

Add architecture checks to your CI pipeline:

bash
# Verify all libraries are for correct architecture
check_architecture() {
    local lib_path=$1
    if lipo -info "$lib_path" | grep -q "arm64"; then
        echo "✓ $lib_path contains arm64 architecture"
        return 0
    else
        echo "✗ $lib_path missing arm64 architecture"
        return 1
    fi
}

Troubleshooting Checklist

Use this systematic approach to diagnose and fix the issue:

  1. Verify System Architecture

    bash
    uname -m  # Should show arm64
    
  2. Check All Object Files

    bash
    find . -name "*.o" -exec file {} \; | grep -v arm64
    
  3. Inspect Library Architectures

    bash
    lipo -info libgtest.a
    lipo -info /opt/homebrew/lib/libgtest*.a 2>/dev/null
    
  4. Clean and Rebuild

    bash
    rm -f *.o *.a
    # Rebuild with proper flags
    
  5. Test Linking Step by Step

    bash
    # Link just the GTest library first
    g++ -o test_gtest -L${GTEST_ROOT} -lgtest -arch arm64
    
  6. Check for Missing Symbols

    bash
    nm -U libgtest.a | grep "testing::"
    
  7. Verify Compiler Compatibility

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

The key is ensuring that every component in your build chain - from individual object files to final libraries - is compiled explicitly for the arm64 architecture. As noted in the Stack Overflow discussion, this architecture mismatch is particularly common with static libraries on Apple Silicon Macs.

Sources

  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

Conclusion

The “Undefined symbols for architecture arm64” error when building Google Test on Apple Silicon Macs is typically caused by architecture mismatches in your build chain. To resolve this:

  • Always verify that all object files and libraries are built specifically for arm64 using file and lipo commands
  • Rebuild Google Test with explicit -arch arm64 flags or use the Homebrew version
  • Ensure consistent architecture across all compilation and linking steps
  • Consider using dynamic libraries (.dylib) if static libraries continue to cause issues
  • Implement architecture checks in your build process to prevent future problems

By systematically checking each component in your build chain and ensuring they all target the correct arm64 architecture, you can resolve this linker error and successfully build Google Test on your Apple Silicon Mac.