Building application using ExternalProject_Add on M1 CPU

Hey there,

I finally got around to looking into this. I’ve been able to resolve the problem but there definitely seems to be something a little strange going on with ExternalProject_Add I don’t fully understand…

The crux of the problem seemed to be when I configured and built using the Ninja generator with ExternalProject_Add, the libraries built from this wound up being x86_64. I used lipo -info on Ninja and found it was x86_64.

❯ lipo -info /usr/local/bin/ninja
Non-fat file: /usr/local/bin/ninja is architecture: x86_64

The odd thing is when using Ninja to build a simple application (not using ExternalProject_Add) the build artefacts would be arm64. This is where the strange mismatch was coming from for me.

# using Ninja generator

❯ lipo -info test # simple app
Non-fat file: test is architecture: arm64

❯ lipo -info lib/libimgui.cmake.a # lib built with ExternalProject_Add at the same time
Non-fat file: lib/libimgui.cmake.a is architecture: x86_64

The solution I found was to download the latest version of Ninja which is now a fat binary including both x86_64 and arm64 architectures. Now when I run configure and build using ExternalProject_Add the build artefacts are arm64, not x86_64 as they were before.

This subtle difference is still a bit of a puzzle to me, but it’s likely something that’s not going to impact too many people in future.

I also took your advice and made a little test program that used sysctl.proc_translated. This page was very helpful - about-the-rosetta-translation-environment.

I could then build and run the program like so…

❯ cmake -B build -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -G Ninja
...
❯ cmake --build build
...

❯ arch -x86_64 build/test
translated

❯ arch -arm64 build/test
native

Where the code looked something like this…

int process_is_translated()
{
  int ret = 0;
  size_t size = sizeof(ret);
  if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
    if (errno == ENOENT) {
      return 0;
    }
    return -1;
  }
  return ret;
}

int main(int argc, char** argv)
{
  if (auto result = process_is_translated(); result == 0) {
    std::cout << "native\n";
  } else if (result == 1) {
    std::cout << "translated\n";
  } else {
    std::cout << "error\n";
  }
}

Thanks again for your help and I can now remove the hardcoded CMAKE_OSX_ARCHITECTURES option from my CMakeLists.txt file