浏览代码

ARMClang: Do not automatically add cpu/arch compile or link options

The compile options `--march=<arch>` and `--mcpu=<cpu>` and the
link option `--cpu=<cpu>` are automatically added by CMake based
on `CMAKE_SYSTEM_PROCESSOR` or `CMAKE_SYSTEM_ARCH`. But this is not
sufficient, because armclang also supports enabling or disabling
features using `+<feature>`:

    -mcpu=<name>[+[no]<feature>+...]

For example:

    -mcpu=cortex-a57+nocrypto+nofp+nosimd+crc

(Reference: https://developer.arm.com/documentation/dui0774/k/Compiler-Command-line-Options/-mcpu?lang=en)

The problem is, even if a project adds a flag with features it needs,
CMake still adds flags, resulting in code that is compiled with wrong
CPU features and unable to run.

Add policy `CMP0123` to not automatically add compile or link options,
and let projects set them instead.

Co-Author: Brad King <[email protected]>
Fixes: #21173
Lingkai Dong 4 年之前
父节点
当前提交
c4941b7e66

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

@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.21
 .. toctree::
    :maxdepth: 1
 
+   CMP0123: ARMClang cpu/arch compile and link flags must be set explicitly. </policy/CMP0123>
    CMP0122: UseSWIG use standard library name conventions for csharp language. </policy/CMP0122>
    CMP0121: The list command detects invalid indicies. </policy/CMP0121>
 

+ 32 - 0
Help/policy/CMP0123.rst

@@ -0,0 +1,32 @@
+CMP0123
+-------
+
+.. versionadded:: 3.21
+
+``ARMClang`` cpu/arch compile and link flags must be set explicitly.
+
+CMake 3.20 and lower automatically maps the :variable:`CMAKE_SYSTEM_PROCESSOR`
+variable and an undocumented ``CMAKE_SYSTEM_ARCH`` to compile and link options
+for ``ARMClang``.  For example, the ``-mcpu=cortex-m33`` flag is added when
+:variable:`CMAKE_SYSTEM_PROCESSOR` equals ``cortex-m33``.  CMake requires
+projects to set either variable or it raises a fatal error.  However, the
+project may need to additionally specify CPU features using e.g.
+``-mcpu=cortex-m33+nodsp``, conflicting with the ``-mcpu=cortex-m33`` added
+by CMake.  This results in either link errors or unusable binaries.
+
+CMake 3.21 and above prefer instead to not add any cpu/arch compile and link
+flags automatically.  Instead, projects must specify them explicitly.
+This policy provides compatibility for projects that have not been updated.
+
+The ``OLD`` behavior of this policy requires projects that use ``ARMClang``
+to set either :variable:`CMAKE_SYSTEM_PROCESSOR` or ``CMAKE_SYSTEM_ARCH``
+and it automatically adds a compile option ``-mcpu=`` or ``-march=`` and
+a link option ``--cpu=`` based on those variables.  The ``NEW`` behavior
+does not add compile or link options, and projects are responsible for
+setting correct options.
+
+This policy was introduced in CMake version 3.21.  CMake version |release|
+warns when the policy is not set and uses ``OLD`` behavior.  Use the
+:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt

+ 7 - 0
Help/release/dev/ARMClang-cpu-arch-flags.rst

@@ -0,0 +1,7 @@
+ARMClang-cpu-arch-flags
+-----------------------
+
+* ``ARMClang`` cpu/arch compile and link flags are no longer added
+  automatically based on the :variable:`CMAKE_SYSTEM_PROCESSOR`
+  variable or the undocumented ``CMAKE_SYSTEM_ARCH`` variable.
+  They must be specified explicitly.  See policy :policy:`CMP0123`.

+ 46 - 26
Modules/Compiler/ARMClang.cmake

@@ -3,6 +3,9 @@ if(_ARMClang_CMAKE_LOADED)
 endif()
 set(_ARMClang_CMAKE_LOADED TRUE)
 
+# Save the CMP0123 setting in a variable used both below and by try_compile.
+cmake_policy(GET CMP0123 CMAKE_ARMClang_CMP0123)
+
 cmake_policy(PUSH)
 cmake_policy(SET CMP0057 NEW) # if IN_LIST
 
@@ -82,36 +85,53 @@ macro(__compiler_armclang lang)
   if(NOT CMAKE_${lang}_COMPILER_ARCH_LIST)
     __armclang_set_arch_list(${lang} CMAKE_${lang}_COMPILER_ARCH_LIST)
   endif()
-  if(NOT CMAKE_SYSTEM_PROCESSOR AND NOT CMAKE_SYSTEM_ARCH)
-    message(FATAL_ERROR "  CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
-      "  Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
-      "  Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
-  else()
-    __armclang_check_processor("${CMAKE_SYSTEM_ARCH}" "${CMAKE_${lang}_COMPILER_ARCH_LIST}" _CMAKE_${lang}_CHECK_ARCH_RESULT)
-    if( _CMAKE_${lang}_CHECK_ARCH_RESULT)
-      string(APPEND CMAKE_${lang}_FLAGS_INIT " -march=${CMAKE_SYSTEM_ARCH}")
-      set(__march_flag_set TRUE)
+
+  # CMAKE_SYSTEM_PROCESSOR and CMAKE_SYSTEM_ARCH are not sufficient because they provide no
+  # information of additional CPU features needed in `-mcpu=<name>[+[no]<feature>+...]`.
+  # The automatic setting of compile and link options is deprecated and projects should specify their own.
+  cmake_policy(GET CMP0123 policy_CMP0123)
+  if(NOT "x${CMAKE_ARMClang_CMP0123}x" STREQUAL "xNEWx")
+    if(NOT "x${CMAKE_ARMClang_CMP0123}x" STREQUAL "xOLDx")
+      cmake_policy(GET_WARNING CMP0123 _cmp0123_warning)
+      message(AUTHOR_WARNING
+        "${_cmp0123_warning}\n"
+        "For compatibility, CMake will automatically add cpu/arch flags based "
+        "on the CMAKE_SYSTEM_PROCESSOR and/or CMAKE_SYSTEM_ARCH variables."
+        )
     endif()
-    __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}" _CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
-    if(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
-      string(APPEND CMAKE_${lang}_FLAGS_INIT " -mcpu=${CMAKE_SYSTEM_PROCESSOR}")
-      set(__mcpu_flag_set TRUE)
+
+    if(NOT CMAKE_SYSTEM_PROCESSOR AND NOT CMAKE_SYSTEM_ARCH)
+      message(FATAL_ERROR "  CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
+        "  Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
+        "  Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
+    else()
+      __armclang_check_processor("${CMAKE_SYSTEM_ARCH}" "${CMAKE_${lang}_COMPILER_ARCH_LIST}" _CMAKE_${lang}_CHECK_ARCH_RESULT)
+      if( _CMAKE_${lang}_CHECK_ARCH_RESULT)
+        string(APPEND CMAKE_${lang}_FLAGS_INIT " -march=${CMAKE_SYSTEM_ARCH}")
+        set(__march_flag_set TRUE)
+      endif()
+      __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}" _CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+      if(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+        string(APPEND CMAKE_${lang}_FLAGS_INIT " -mcpu=${CMAKE_SYSTEM_PROCESSOR}")
+        set(__mcpu_flag_set TRUE)
+      endif()
+      if(NOT __march_flag_set AND NOT __mcpu_flag_set)
+        message(FATAL_ERROR "At least one of the variables CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
+                            "Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
+                            "  Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
+      endif()
+      unset(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
+      unset(_CMAKE_${lang}_CHECK_ARCH_RESULT)
     endif()
-    if(NOT __march_flag_set AND NOT __mcpu_flag_set)
-      message(FATAL_ERROR "At least one of the variables CMAKE_SYSTEM_PROCESSOR or CMAKE_SYSTEM_ARCH must be set for ARMClang\n"
-                          "Supported processor: ${CMAKE_${lang}_COMPILER_PROCESSOR_LIST}\n"
-                          "  Supported Architecture: ${CMAKE_${lang}_COMPILER_ARCH_LIST}")
+
+    #check if CMAKE_SYSTEM_PROCESSOR belongs to supported cpu list for armlink
+    __armlink_set_cpu_list( ${lang} CMAKE_LINKER_CPU_LIST)
+    list(TRANSFORM CMAKE_LINKER_CPU_LIST TOLOWER)
+    __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_LINKER_CPU_LIST}" _CMAKE_CHECK_LINK_CPU_RESULT)
+    if(_CMAKE_CHECK_LINK_CPU_RESULT)
+      string(APPEND CMAKE_${lang}_LINK_FLAGS " --cpu=${CMAKE_SYSTEM_PROCESSOR}")
     endif()
-    unset(_CMAKE_${lang}_CHECK_PROCESSOR_RESULT)
-    unset(_CMAKE_${lang}_CHECK_ARCH_RESULT)
-  endif()
 
-  #check if CMAKE_SYSTEM_PROCESSOR belongs to supported cpu list for armlink
-  __armlink_set_cpu_list( ${lang} CMAKE_LINKER_CPU_LIST)
-  list(TRANSFORM CMAKE_LINKER_CPU_LIST TOLOWER)
-  __armclang_check_processor("${CMAKE_SYSTEM_PROCESSOR}" "${CMAKE_LINKER_CPU_LIST}" _CMAKE_CHECK_LINK_CPU_RESULT)
-  if(_CMAKE_CHECK_LINK_CPU_RESULT)
-    string(APPEND CMAKE_${lang}_LINK_FLAGS " --cpu=${CMAKE_SYSTEM_PROCESSOR}")
   endif()
 
   if(__CMAKE_ARMClang_USING_armlink)

+ 9 - 0
Source/cmCoreTryCompile.cxx

@@ -8,6 +8,7 @@
 #include <sstream>
 #include <utility>
 
+#include <cm/string_view>
 #include <cmext/string_view>
 
 #include "cmsys/Directory.hxx"
@@ -217,6 +218,7 @@ std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
 std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
 std::string const kCMAKE_SYSROOT_COMPILE = "CMAKE_SYSROOT_COMPILE";
 std::string const kCMAKE_SYSROOT_LINK = "CMAKE_SYSROOT_LINK";
+std::string const kCMAKE_ARMClang_CMP0123 = "CMAKE_ARMClang_CMP0123";
 std::string const kCMAKE_TRY_COMPILE_OSX_ARCHITECTURES =
   "CMAKE_TRY_COMPILE_OSX_ARCHITECTURES";
 std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
@@ -552,6 +554,13 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       fprintf(fout, "cmake_policy(SET CMP0104 OLD)\n");
     }
 
+    /* Set ARMClang cpu/arch policy to match outer project.  */
+    if (cmProp cmp0123 =
+          this->Makefile->GetDefinition(kCMAKE_ARMClang_CMP0123)) {
+      fprintf(fout, "cmake_policy(SET CMP0123 %s)\n",
+              *cmp0123 == "NEW"_s ? "NEW" : "OLD");
+    }
+
     std::string projectLangs;
     for (std::string const& li : testLangs) {
       projectLangs += " " + li;

+ 4 - 1
Source/cmPolicies.h

@@ -366,7 +366,10 @@ class cmMakefile;
   SELECT(                                                                     \
     POLICY, CMP0122,                                                          \
     "UseSWIG use standard library name conventions for csharp language.", 3,  \
-    21, 0, cmPolicies::WARN)
+    21, 0, cmPolicies::WARN)                                                  \
+  SELECT(POLICY, CMP0123,                                                     \
+         "ARMClang cpu/arch compile and link flags must be set explicitly.",  \
+         3, 21, 0, cmPolicies::WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \