Просмотр исходного кода

MSVC: Move link -machine flag out of CMAKE_*_LINKER_FLAGS

The `CMAKE_{EXE,SHARED,MODULE,STATIC}_LINKER_FLAGS` variables are
not language-specific, so multiple languages' toolchains may disagree
about if/how to pass the flag through a compiler driver to the linker.
Furthermore, carrying the flag in public-facing variables allows projects
or users to change it even though it is required.  Add policy CMP0197
to remove the flag from the public-facing variables and generate it
automatically instead:

* For command-line generators, add the `-machine:` flag to the
  linker and archiver rule variables.

* For Visual Studio generators, we do not need to explicitly add the
  link `-machine:` flag.  MSBuild automatically adds it, and the new
  behavior actually removes a duplicate we generated previously.

Issue: #21934
Brad King 6 месяцев назад
Родитель
Сommit
92d6126450

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

@@ -98,6 +98,7 @@ Policies Introduced by CMake 4.1
 .. toctree::
    :maxdepth: 1
 
+   CMP0197: MSVC link -machine: flag is not in CMAKE_*_LINKER_FLAGS. </policy/CMP0197>
    CMP0196: The CMakeDetermineVSServicePack module is removed. </policy/CMP0196>
    CMP0195: Swift modules in build trees use the Swift module directory structure. </policy/CMP0195>
    CMP0194: MSVC is not an assembler for language ASM. </policy/CMP0194>

+ 45 - 0
Help/policy/CMP0197.rst

@@ -0,0 +1,45 @@
+CMP0197
+-------
+
+.. versionadded:: 4.1
+
+MSVC link ``-machine:`` flag is not in ``CMAKE_*_LINKER_FLAGS``.
+
+When using MSVC-like compilers in CMake 4.0 and below, the linker's
+``-machine:`` flag is added via language-agnostic linker flag variables:
+
+* :variable:`CMAKE_EXE_LINKER_FLAGS`
+* :variable:`CMAKE_SHARED_LINKER_FLAGS`
+* :variable:`CMAKE_MODULE_LINKER_FLAGS`
+* :variable:`CMAKE_STATIC_LINKER_FLAGS`
+
+This is problematic when multiple languages' toolchains disagree about
+if/how to pass the flag through a compiler driver to the linker.
+Furthermore, carrying the flag in public-facing variables allows projects
+or users to change it even though it is required.
+
+CMake 4.1 and above prefer to leave the ``-machine:`` flag out of
+``CMAKE_*_LINKER_FLAGS`` variables, and instead generate the link
+flag automatically where needed.
+
+This policy provides compatibility with projects that have not been updated
+to expect the lack of the ``-machine:`` flags.  The policy setting takes
+effect as of the first :command:`project` or :command:`enable_language`
+command that initializes the above-listed ``CMAKE_*_LINKER_FLAGS`` variables.
+
+.. note::
+
+  Once the policy has taken effect at the top of a project for a given
+  language, that choice must be used throughout the tree for that language.
+  In projects that have nested projects in subdirectories, be sure to
+  convert everything together.
+
+The ``OLD`` behavior for this policy is to place the MSVC ``-machine:``
+flag in ``CMAKE_*_LINKER_FLAGS``.  The ``NEW`` behavior for this policy
+is to *not* place the MSVC ``-machine:`` flag in ``CMAKE_*_LINKER_FLAGS``.
+
+.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.1
+.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn
+.. include:: include/STANDARD_ADVICE.rst
+
+.. include:: include/DEPRECATED.rst

+ 5 - 0
Help/release/dev/msvc-link-machine.rst

@@ -0,0 +1,5 @@
+msvc-link-machine
+-----------------
+
+* The MSVC link ``-machine:`` flag is no longer added to the
+  ``CMAKE_*_LINKER_FLAGS`` variables.  See policy :policy:`CMP0197`.

+ 1 - 1
Modules/Platform/Windows-IntelLLVM.cmake

@@ -47,7 +47,7 @@ macro(__windows_compiler_intel lang)
   if (NOT "${lang}" STREQUAL "Fortran" OR CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 2022.1)
     # The Fortran driver does not support -fuse-ld=llvm-lib before compiler version 2022.1
     set(CMAKE_${lang}_CREATE_STATIC_LIBRARY
-      "<CMAKE_${lang}_COMPILER> ${CMAKE_CL_NOLOGO} <CMAKE_${lang}_LINK_FLAGS> <OBJECTS> ${CMAKE_START_TEMP_FILE} -fuse-ld=llvm-lib -o <TARGET> <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
+      "<CMAKE_${lang}_COMPILER> ${CMAKE_CL_NOLOGO}${_PLATFORM_ARCHIVE_FLAGS} <CMAKE_${lang}_LINK_FLAGS> <OBJECTS> ${CMAKE_START_TEMP_FILE} -fuse-ld=llvm-lib -o <TARGET> <LINK_FLAGS> <LINK_LIBRARIES> ${CMAKE_END_TEMP_FILE}")
   endif()
 
   set(CMAKE_DEPFILE_FLAGS_${lang} "-QMD -QMT <DEP_TARGET> -QMF <DEP_FILE>")

+ 19 - 4
Modules/Platform/Windows-MSVC.cmake

@@ -276,7 +276,12 @@ unset(_GR)
 
 set(CMAKE_CXX_STANDARD_LIBRARIES_INIT "${CMAKE_C_STANDARD_LIBRARIES_INIT}")
 
-set(_machine "/machine")
+cmake_policy(GET CMP0197 CMAKE_MSVC_CMP0197)
+if(CMAKE_MSVC_CMP0197 STREQUAL "NEW")
+  set(_machine "-machine")
+else()
+  set(_machine "/machine")
+endif()
 
 # executable linker flags
 set (CMAKE_LINK_DEF_FILE_FLAG "/DEF:")
@@ -321,7 +326,9 @@ if(NOT WINDOWS_PHONE AND NOT WINDOWS_STORE AND NOT CMAKE_SYSTEM_NAME STREQUAL "W
 endif()
 
 foreach(t EXE SHARED MODULE)
-  string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+  if(NOT CMAKE_MSVC_CMP0197 STREQUAL "NEW")
+    string(APPEND CMAKE_${t}_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+  endif()
   if (CMAKE_COMPILER_SUPPORTS_PDBTYPE)
     string(APPEND CMAKE_${t}_LINKER_FLAGS_DEBUG_INIT " ${_Wl}/debug ${_Wl}/pdbtype:sept ${MSVC_INCREMENTAL_YES_FLAG}")
     string(APPEND CMAKE_${t}_LINKER_FLAGS_RELWITHDEBINFO_INIT " ${_Wl}/debug ${_Wl}/pdbtype:sept ${MSVC_INCREMENTAL_YES_FLAG}")
@@ -340,11 +347,19 @@ if(CMAKE_SYSTEM_NAME STREQUAL "WindowsCE")
 elseif(CMAKE_SYSTEM_NAME STREQUAL "WindowsKernelModeDriver")
   string(APPEND _PLATFORM_LINK_FLAGS " -subsystem:native -kernel -MANIFEST:NO")
 endif()
+if(CMAKE_MSVC_CMP0197 STREQUAL "NEW")
+  string(APPEND _PLATFORM_LINK_FLAGS " ${_MACHINE_ARCH_FLAG}")
+endif()
 
+set(_PLATFORM_ARCHIVE_FLAGS "")
 if((_MSVC_C_ARCHITECTURE_FAMILY STREQUAL "ARM64EC") OR (_MSVC_CXX_ARCHITECTURE_FAMILY STREQUAL "ARM64EC"))
   set(_MACHINE_ARCH_FLAG " ${_Wl}${_machine}:ARM64X")
 endif()
-string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+if(CMAKE_MSVC_CMP0197 STREQUAL "NEW")
+  string(APPEND _PLATFORM_ARCHIVE_FLAGS " ${_MACHINE_ARCH_FLAG}")
+else()
+  string(APPEND CMAKE_STATIC_LINKER_FLAGS_INIT " ${_MACHINE_ARCH_FLAG}")
+endif()
 unset(_MACHINE_ARCH_FLAG)
 unset(_machine)
 
@@ -388,7 +403,7 @@ macro(__windows_compiler_msvc lang)
   unset(_DLL_DRIVER)
 
   set(CMAKE_${lang}_CREATE_SHARED_MODULE ${CMAKE_${lang}_CREATE_SHARED_LIBRARY})
-  set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+  set(CMAKE_${lang}_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO}${_PLATFORM_ARCHIVE_FLAGS} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 
   set(CMAKE_${lang}_COMPILE_OBJECT
     "<CMAKE_${lang}_COMPILER> ${CMAKE_START_TEMP_FILE} ${CMAKE_CL_NOLOGO}${_COMPILE_${lang}} <DEFINES> <INCLUDES> <FLAGS> /Fo<OBJECT> /Fd<TARGET_COMPILE_PDB>${_FS_${lang}} -c <SOURCE>${CMAKE_END_TEMP_FILE}")

+ 1 - 1
Modules/Platform/Windows-NVIDIA-CUDA.cmake

@@ -17,7 +17,7 @@ set(CMAKE_CUDA_CREATE_SHARED_LIBRARY
   "${_CMAKE_VS_LINK_DLL}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /dll /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")
 
 set(CMAKE_CUDA_CREATE_SHARED_MODULE ${CMAKE_CUDA_CREATE_SHARED_LIBRARY})
-set(CMAKE_CUDA_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
+set(CMAKE_CUDA_CREATE_STATIC_LIBRARY  "<CMAKE_AR> ${CMAKE_CL_NOLOGO}${_PLATFORM_ARCHIVE_FLAGS} <LINK_FLAGS> /out:<TARGET> <OBJECTS> ")
 set(CMAKE_CUDA_LINKER_SUPPORTS_PDB ON)
 set(CMAKE_CUDA_LINK_EXECUTABLE
   "${_CMAKE_VS_LINK_EXE}<CMAKE_LINKER> ${CMAKE_CL_NOLOGO} <OBJECTS> ${CMAKE_START_TEMP_FILE} /out:<TARGET> /implib:<TARGET_IMPLIB> /pdb:<TARGET_PDB> /version:<TARGET_VERSION_MAJOR>.<TARGET_VERSION_MINOR>${_PLATFORM_LINK_FLAGS} <LINK_FLAGS> <LINK_LIBRARIES>${__IMPLICIT_LINKS} ${CMAKE_END_TEMP_FILE}")

+ 7 - 0
Source/cmCoreTryCompile.cxx

@@ -91,6 +91,7 @@ std::string const kCMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT =
   "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT_DEFAULT";
 std::string const kCMAKE_MSVC_RUNTIME_CHECKS_DEFAULT =
   "CMAKE_MSVC_RUNTIME_CHECKS_DEFAULT";
+std::string const kCMAKE_MSVC_CMP0197 = "CMAKE_MSVC_CMP0197";
 
 /* GHS Multi platform variables */
 std::set<std::string> const ghs_platform_vars{
@@ -684,6 +685,12 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode(
       fprintf(fout, "cmake_policy(SET CMP0128 OLD)\n");
     }
 
+    /* Set MSVC link -machine: policy to match outer project.  */
+    if (cmValue cmp0197 = this->Makefile->GetDefinition(kCMAKE_MSVC_CMP0197)) {
+      fprintf(fout, "cmake_policy(SET CMP0197 %s)\n",
+              *cmp0197 == "NEW"_s ? "NEW" : "OLD");
+    }
+
     std::string projectLangs;
     for (std::string const& li : testLangs) {
       projectLangs += cmStrCat(' ', li);

+ 4 - 1
Source/cmPolicies.h

@@ -586,7 +586,10 @@ class cmMakefile;
     "Swift modules in build trees use the Swift module directory structure.", \
     4, 1, 0, WARN)                                                            \
   SELECT(POLICY, CMP0196,                                                     \
-         "The CMakeDetermineVSServicePack module is removed.", 4, 1, 0, WARN)
+         "The CMakeDetermineVSServicePack module is removed.", 4, 1, 0, WARN) \
+  SELECT(POLICY, CMP0197,                                                     \
+         "MSVC link -machine: flag is not in CMAKE_*_LINKER_FLAGS.", 4, 1, 0, \
+         WARN)
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 2 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-NEW-config.txt

@@ -0,0 +1,2 @@
+[ ,][/-][Mm][Aa][Cc][Hh][Ii][Nn][Ee]:[A-Za-z0-9_]+[ ]|[Vv][Cc](98|7)\\\\[Bb][Ii][Nn]\\\\[Ll][Ii][Nn][Kk]\.[Ee][Xx][Ee] [^
+]*@[^ ]+\\\\nm

+ 2 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-NEW.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0197 NEW)
+include(CMP0197-common.cmake)

+ 1 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-OLD-config.txt

@@ -0,0 +1 @@
+[" ,]/[Mm][Aa][Cc][Hh][Ii][Nn][Ee]:[A-Za-z0-9_]+[ "]

+ 2 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-OLD.cmake

@@ -0,0 +1,2 @@
+cmake_policy(SET CMP0197 OLD)
+include(CMP0197-common.cmake)

+ 1 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-WARN-config.txt

@@ -0,0 +1 @@
+[" ,]/[Mm][Aa][Cc][Hh][Ii][Nn][Ee]:[A-Za-z0-9_]+[ "]

+ 2 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-WARN.cmake

@@ -0,0 +1,2 @@
+
+include(CMP0197-common.cmake)

+ 1 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-build-stdout.txt

@@ -0,0 +1 @@
+[ ,][/-][Mm][Aa][Cc][Hh][Ii][Nn][Ee]:[A-Za-z0-9_]+[ ]

+ 20 - 0
Tests/RunCMake/MSVCDefaultFlags/CMP0197-common.cmake

@@ -0,0 +1,20 @@
+enable_language(C)
+
+# Make sure the compile command is not hidden.
+string(REPLACE "${CMAKE_START_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+string(REPLACE "${CMAKE_END_TEMP_FILE}" "" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}")
+
+cmake_policy(GET CMP0197 cmp0197)
+foreach(t EXE SHARED MODULE STATIC)
+  if(cmp0197 STREQUAL "NEW")
+    if("${CMAKE_${t}_LINKER_FLAGS}" MATCHES "([/-][Mm][Aa][Cc][Hh][Ii][Nn][Ee]:)")
+      message(SEND_ERROR "CMAKE_${t}_LINKER_FLAGS has '${CMAKE_MATCH_1}' under NEW behavior")
+    endif()
+  else()
+    if(NOT " ${CMAKE_${t}_LINKER_FLAGS} " MATCHES "[ ,]/machine:[A-Za-z0-9_]+ ")
+      message(SEND_ERROR "CMAKE_${t}_LINKER_FLAGS does not have '/machine:' under OLD behavior")
+    endif()
+  endif()
+endforeach()
+
+add_executable(main main.c)

+ 13 - 0
Tests/RunCMake/MSVCDefaultFlags/RunCMakeTest.cmake

@@ -3,3 +3,16 @@ include(RunCMake)
 run_cmake(CMP0092-WARN)
 run_cmake(CMP0092-OLD)
 run_cmake(CMP0092-NEW)
+
+function(run_CMP0197 pol)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0197-${pol})
+  run_cmake(CMP0197-${pol})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  set(RunCMake_TEST_OUTPUT_MERGE 1)
+  set(RunCMake-stdout-file "CMP0197-build-stdout.txt")
+  run_cmake_command(CMP0197-${pol}-build ${CMAKE_COMMAND} --build . --config Debug --verbose)
+endfunction()
+
+run_CMP0197(WARN)
+run_CMP0197(OLD)
+run_CMP0197(NEW)

+ 4 - 0
Tests/RunCMake/MSVCDefaultFlags/main.c

@@ -0,0 +1,4 @@
+int main(void)
+{
+  return 0;
+}