ソースを参照

macOS: Offer control over host architecture on Apple Silicon hosts

Since commit b6c60f14b6 (macOS: Default to arm64 architecture on Apple
Silicon hosts, 2020-09-28, v3.19.0-rc1~63^2) we use `sysctl` to detect
that we are running on Apple Silicon in a way that pierces Rosetta.
This always sets `CMAKE_HOST_SYSTEM_PROCESSOR` to be `arm64` on such
hosts.  However, macOS offers strong support for running processes under
an emulated `x86_64` architecture.

Teach CMake to select either `arm64` or `x86_64` as the host
architecture on Apple Silicon based on the architecture of its own
process.  When CMake is built as a universal binary, macOS will select
whichever slice (architecture) is appropriate under the user's shell,
and `CMAKE_HOST_SYSTEM_PROCESSOR` will match.

Also offer a `CMAKE_APPLE_SILICON_PROCESSOR` variable and environment
variable to provide users with explicit control over the host
architecture selection regardless of CMake's own architecture.

Finally, if `CMAKE_OSX_ARCHITECTURES` is not set, pass explicit flags to
the toolchain to use selected host architecture instead of letting the
toolchain pick.

Fixes: #21554
Brad King 5 年 前
コミット
5f882f6ce5

+ 13 - 0
Help/envvar/CMAKE_APPLE_SILICON_PROCESSOR.rst

@@ -0,0 +1,13 @@
+CMAKE_APPLE_SILICON_PROCESSOR
+-----------------------------
+
+.. versionadded:: 3.19.2
+
+.. include:: ENV_VAR.txt
+
+On Apple Silicon hosts running macOS, set this environment variable to tell
+CMake what architecture to use for :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`.
+The value must be either ``arm64`` or ``x86_64``.
+
+The :variable:`CMAKE_APPLE_SILICON_PROCESSOR` normal variable, if set,
+overrides this environment variable.

+ 1 - 0
Help/manual/cmake-env-variables.7.rst

@@ -28,6 +28,7 @@ Environment Variables that Control the Build
 .. toctree::
    :maxdepth: 1
 
+   /envvar/CMAKE_APPLE_SILICON_PROCESSOR
    /envvar/CMAKE_BUILD_PARALLEL_LEVEL
    /envvar/CMAKE_CONFIG_TYPE
    /envvar/CMAKE_EXPORT_COMPILE_COMMANDS

+ 1 - 0
Help/manual/cmake-variables.7.rst

@@ -353,6 +353,7 @@ Variables that Control the Build
    /variable/CMAKE_ANDROID_SKIP_ANT_STEP
    /variable/CMAKE_ANDROID_STANDALONE_TOOLCHAIN
    /variable/CMAKE_ANDROID_STL_TYPE
+   /variable/CMAKE_APPLE_SILICON_PROCESSOR
    /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY
    /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG
    /variable/CMAKE_AUTOGEN_ORIGIN_DEPENDS

+ 24 - 0
Help/release/3.19.rst

@@ -53,6 +53,22 @@ Languages
 
 * ``CUDA`` language support now works on QNX.
 
+Platforms
+---------
+
+* Apple Silicon is now supported (since CMake 3.19.2):
+
+  * The :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` is selected using ``uname -m``.
+    Since this may vary based on CMake's own architecture and that of
+    the invoking process tree, the :variable:`CMAKE_APPLE_SILICON_PROCESSOR`
+    variable or :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment
+    variable may be set to specify a host architecture explicitly.
+
+  * If :variable:`CMAKE_OSX_ARCHITECTURES` is not set, CMake adds explicit
+    flags to tell the compiler to build for the
+    :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` so the toolchain does not
+    have to guess based on the process tree's architecture.
+
 File-Based API
 --------------
 
@@ -357,3 +373,11 @@ Changes made since CMake 3.19.0 include the following.
   It requires macOS 10.10 or newer.
   The package file naming pattern has been changed from
   ``cmake-$ver-Darwin-x86_64`` to ``cmake-$ver-macos-universal``.
+
+* Apple Silicon host architecture selection support was updated.
+  CMake 3.19.0 and 3.19.1 always chose ``arm64`` as the host architecture.
+  CMake 3.19.2 returns to using ``uname -m`` as CMake 3.18 and below did.
+  Since this may vary based on CMake's own architecture and that of
+  the invoking process tree, the :variable:`CMAKE_APPLE_SILICON_PROCESSOR`
+  variable or :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment
+  variable may be set to specify a host architecture explicitly.

+ 15 - 0
Help/variable/CMAKE_APPLE_SILICON_PROCESSOR.rst

@@ -0,0 +1,15 @@
+CMAKE_APPLE_SILICON_PROCESSOR
+-----------------------------
+
+.. versionadded:: 3.19.2
+
+On Apple Silicon hosts running macOS, set this variable to tell
+CMake what architecture to use for :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`.
+The value must be either ``arm64`` or ``x86_64``.
+
+The value of this variable should never be modified by project code.
+It is meant to be set by a toolchain file specified by the
+:variable:`CMAKE_TOOLCHAIN_FILE` variable, or as a cache entry
+provided by the user, e.g. via ``-DCMAKE_APPLE_SILICON_PROCESSOR=...``.
+
+See also the :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment variable.

+ 30 - 3
Help/variable/CMAKE_HOST_SYSTEM_PROCESSOR.rst

@@ -3,13 +3,40 @@ CMAKE_HOST_SYSTEM_PROCESSOR
 
 The name of the CPU CMake is running on.
 
+Windows Platforms
+^^^^^^^^^^^^^^^^^
+
 On Windows, this variable is set to the value of the environment variable
-``PROCESSOR_ARCHITECTURE``. On systems that support ``uname``, this variable is
-set to the output of:
+``PROCESSOR_ARCHITECTURE``.
+
+Unix Platforms
+^^^^^^^^^^^^^^
+
+On systems that support ``uname``, this variable is set to the output of:
 
-- ``uname -m`` on GNU, Linux, Cygwin, Darwin, Android, or
+- ``uname -m`` on GNU, Linux, Cygwin, Android, or
 - ``arch`` on OpenBSD, or
 - on other systems,
 
   * ``uname -p`` if its exit code is nonzero, or
   * ``uname -m`` otherwise.
+
+macOS Platforms
+^^^^^^^^^^^^^^^
+
+The value of ``uname -m`` is used by default.
+
+On Apple Silicon hosts, the architecture printed by ``uname -m`` may vary
+based on CMake's own architecture and that of the invoking process tree.
+
+.. versionadded:: 3.19.2
+
+  On Apple Silicon hosts:
+
+  * The :variable:`CMAKE_APPLE_SILICON_PROCESSOR` variable or
+    the :envvar:`CMAKE_APPLE_SILICON_PROCESSOR` environment variable
+    may be set to specify the host architecture explicitly.
+
+  * If :variable:`CMAKE_OSX_ARCHITECTURES` is not set, CMake adds explicit
+    flags to tell the compiler to build for the host architecture so the
+    toolchain does not have to guess based on the process tree's architecture.

+ 28 - 9
Modules/CMakeDetermineSystem.cmake

@@ -43,25 +43,44 @@ if(CMAKE_HOST_UNIX)
     else()
       exec_program(${CMAKE_UNAME} ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
     endif()
-    if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|Darwin|^GNU$|Android")
+    if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|CYGWIN.*|^GNU$|Android")
       exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
         RETURN_VALUE val)
-      if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
-        if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
-          # Check whether we are running under Rosetta on arm64 hardware.
+    elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin")
+      # If we are running on Apple Silicon, honor CMAKE_APPLE_SILICON_PROCESSOR.
+      if(DEFINED CMAKE_APPLE_SILICON_PROCESSOR)
+        set(_CMAKE_APPLE_SILICON_PROCESSOR "${CMAKE_APPLE_SILICON_PROCESSOR}")
+      elseif(DEFINED ENV{CMAKE_APPLE_SILICON_PROCESSOR})
+        set(_CMAKE_APPLE_SILICON_PROCESSOR "$ENV{CMAKE_APPLE_SILICON_PROCESSOR}")
+      else()
+        set(_CMAKE_APPLE_SILICON_PROCESSOR "")
+      endif()
+      if(_CMAKE_APPLE_SILICON_PROCESSOR)
+        if(";${_CMAKE_APPLE_SILICON_PROCESSOR};" MATCHES "^;(arm64|x86_64);$")
           execute_process(COMMAND sysctl -q hw.optional.arm64
             OUTPUT_VARIABLE _sysctl_stdout
             ERROR_VARIABLE _sysctl_stderr
             RESULT_VARIABLE _sysctl_result
             )
-          if(_sysctl_result EQUAL 0 AND _sysctl_stdout MATCHES "hw.optional.arm64: 1")
-            set(CMAKE_HOST_SYSTEM_PROCESSOR "arm64")
+          if(NOT _sysctl_result EQUAL 0 OR NOT _sysctl_stdout MATCHES "hw.optional.arm64: 1")
+            set(_CMAKE_APPLE_SILICON_PROCESSOR "")
           endif()
-        elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
-          # OS X ppc 'uname -m' may report 'Power Macintosh' instead of 'powerpc'
-          set(CMAKE_HOST_SYSTEM_PROCESSOR "powerpc")
+          unset(_sysctl_result)
+          unset(_sysctl_stderr)
+          unset(_sysctl_stdout)
         endif()
       endif()
+      if(_CMAKE_APPLE_SILICON_PROCESSOR)
+        set(CMAKE_HOST_SYSTEM_PROCESSOR "${_CMAKE_APPLE_SILICON_PROCESSOR}")
+      else()
+        exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
+          RETURN_VALUE val)
+      endif()
+      unset(_CMAKE_APPLE_SILICON_PROCESSOR)
+      if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "Power Macintosh")
+        # OS X ppc 'uname -m' may report 'Power Macintosh' instead of 'powerpc'
+        set(CMAKE_HOST_SYSTEM_PROCESSOR "powerpc")
+      endif()
     elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "OpenBSD")
       exec_program(arch ARGS -s OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_PROCESSOR
         RETURN_VALUE val)

+ 13 - 4
Modules/Platform/Darwin-Initialize.cmake

@@ -22,13 +22,22 @@ set(CMAKE_OSX_ARCHITECTURES "$ENV{CMAKE_OSX_ARCHITECTURES}" CACHE STRING
 
 if(NOT CMAKE_CROSSCOMPILING AND
    CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND
-   CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64" AND
-   CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
-  # When building on Apple Silicon (arm64), we need to explicitly specify
+   CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "^(arm64|x86_64)$")
+  execute_process(COMMAND sysctl -q hw.optional.arm64
+    OUTPUT_VARIABLE _sysctl_stdout
+    ERROR_VARIABLE _sysctl_stderr
+    RESULT_VARIABLE _sysctl_result
+    )
+  # When building on an Apple Silicon host, we need to explicitly specify
   # the architecture to the toolchain since it will otherwise guess the
   # architecture based on that of the build system tool.
   # Set an *internal variable* to tell the generators to do this.
-  set(_CMAKE_APPLE_ARCHS_DEFAULT "arm64")
+  if(_sysctl_result EQUAL 0 AND _sysctl_stdout MATCHES "hw.optional.arm64: 1")
+    set(_CMAKE_APPLE_ARCHS_DEFAULT "${CMAKE_HOST_SYSTEM_PROCESSOR}")
+  endif()
+  unset(_sysctl_result)
+  unset(_sysctl_stderr)
+  unset(_sysctl_stdout)
 endif()
 
 # macOS, iOS, tvOS, and watchOS should lookup compilers from