# Building application using ExternalProject\_Add on M1 CPU

**URL:** <https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931>\
**Category:** Code\
**Created:** [January 29, 2022, 5:41pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931 "2022-01-29T17:41:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [January 29, 2022, 5:41pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/1 "2022-01-29T17:41:54Z")

</div>

Hello there,

I encountered a problem recently where I get a series of link errors while attempting to build an application on an M1 (ARM) CPU (this is on a 2021 MacBook) when linking against libraries built using `ExternalProject_Add`. I have a ‘fix’, but I’d like to check if it’s sufficient or if there’s a better, more idiomatic way of handling it.

This is the application in question - [sdl-bgfx-imgui-starter](https://github.com/pr0g/sdl-bgfx-imgui-starter)

It’s a little graphics demo starter that relies on three separate dependencies (SDL2, bgfx and Dear ImGui). I have third-party folder that contains a single `CMakeLists.txt` file that uses `ExternalProject_Add` to download, build and install all the libraries.

The main application then uses `DCMAKE_PREFIX_PATH` from the cli and `find_package` from the `CMakeLists.txt` file to find and link the libraries.

This all seems to work fine for the most part, but when building on M1 hardware, when the main application tries to link against the built libraries, I get an avalanche of link errors for the calls in the libraries I’m consuming.

```auto
... building for macOS-arm64 but attempting to link with file built for macOS-x86_64

"_SDL_Init", referenced from:
    _main in main.cpp.o
"bgfx::shutdown()", referenced from:
    _main in main.cpp.o
"ImGui::GetDrawData()", referenced from:
    main_loop(void*) in main.cpp.o

etc...

```

To ‘fix’ this, I found I can simply add this line at the top of the application `CMakeLists.txt` file ([source](https://stackoverflow.com/questions/69803659/what-is-the-proper-way-to-build-for-macos-x86-64-using-cmake-on-apple-m1-arm)).

```auto
if (APPLE)
  set(CMAKE_OSX_ARCHITECTURES "x86_64")
endif ()

```

And then if I reconfigure and build, everything works fine. My concern is, is this the _right_ thing to do?

It’s not clear to me why the libraries fetched using `ExternalProject_Add` are built for “x86\_64” as opposed to “ARM” (there does not seem to be any mention of `CMAKE_OSX_ARCHITECTURES` in any of the dependencies `CMakeLists.txt` files). When building the application the default appears to be ARM which mismatches and causes all the link errors.

It would be nice to be able to specify which architecture the user of the application would like to build for as opposed to hardcoding it in the `CMakeLists.txt` file. I could then ensure the user chooses explicitly (at least on Apple/macOS).

I’d be very grateful if anyone could offer any advice/suggestions on how to cleanly handle this in a future proof and idiomatic way.

Thank you very much for your time!

Tom

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [January 30, 2022, 6:01pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/2 "2022-01-30T18:01:49Z")

</div>

Is there anything using Rosetta in the process tree? Usual suspects would be CMake itself and Ninja. Any process using Rosetta will launch the `x86_64` variant of the binaries it invokes, so anything detecting “native” architectures will be flipped to x86\_64 if the build tools don’t support arm64 natively.

---

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [January 30, 2022, 6:46pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/3 "2022-01-30T18:46:58Z")

</div>

Thanks for getting back to me @ben.boeckel,

Hmm that’s a good question… so actually thinking about it now, one difference I have between building the third-party folder and the main application, is I have a little `.sh` script to configure the main application so I don’t have to type out all the CMake commands every time. I wonder if this is causing the mismatch…

I’ll try the longhand way and see if that stops the error from happening and report back.

Thanks for the suggestion!

---

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [January 30, 2022, 6:54pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/4 "2022-01-30T18:54:24Z")

</div>

Unfortunately that hasn’t helped, but it could still be something along the lines of what you’re suggesting. If `ExternalProject_Add` under the hood is using Rosetta this could potentially be causing it?

What would be your suggestion for confirming this? Would using Activity Monitor reveal this kind of information?

Thanks!

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [January 31, 2022, 1:17pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/5 "2022-01-31T13:17:10Z")

</div>

I would write a tiny utility that is a fat binary with arm64 and x86\_64 implementations that dumps out `sysctlbyname("sysctl.proc_translated")` (see its manpage for docs on usage) to tell whether it is running as x86\_64 or arm64 (though the preprocessor may be simpler; that’s up you). Run this utility at various places to inspect the state at different points to try and probe where you’re missing an arm64 binary.

Activity Monitor might have this information, but I have no idea where to look.

---

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [January 31, 2022, 10:01pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/6 "2022-01-31T22:01:33Z")

</div>

Okay sounds like a plan, I’ll give that a try at some point later this week or next and report back when I have any more info.

I suspect there potentially might be something up with `ExternalProject_Add` that’s causing this but I don’t have enough information right now to be sure. I’ll see if I can zero in on something.

Thanks for the suggestions, much appreciated.

---

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [February 20, 2022, 4:24pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/7 "2022-02-20T16:24:18Z")

</div>

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

```auto
❯ 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.

```auto
# 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](https://github.com/ninja-build/ninja/releases) 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](https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment).

I could then build and run the program like so…

```auto
❯ 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…

```auto
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

---

<div class="post-metadata">

**Author:** ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)\
**Post date:** [February 21, 2022, 6:13pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/8 "2022-02-21T18:13:15Z")

</div>

> [@tomhh](#):
>
> ```auto
> ❯ 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
> 
> ```

This is because the direct one is made from a CMake using `arm64`, so the “native” detection is working before `ninja` ruins things. In the second case, `ninja` is running `cmake`, so it runs as `x86_64`, autodetects that arch and compiles for the “native” host.

---

<div class="post-metadata">

**Author:** ![tomhh](https://discourse.cmake.org/user_avatar/discourse.cmake.org/tomhh/32/493_2.png) [@tomhh](https://discourse.cmake.org/u/tomhh)\
**Post date:** [February 22, 2022, 8:18pm UTC](https://discourse.cmake.org/t/building-application-using-externalproject-add-on-m1-cpu/4931/9 "2022-02-22T20:18:54Z")

</div>

Ah I see! Interesting 😅 Thanks for following up, it all makes a lot more sense now, much appreciated 👍
