1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-05-08 22:37:04 +08:00

ASM: Guard exclusion of MSVC C/CXX compiler with a policy

Since commit 6baf65ec46 (ASM: Do not consider MSVC C/CXX compiler for
generic ASM, 2025-04-08) we no longer mistake `cl` for an assembler.
However, some projects unconditionally enable ``ASM``, which worked
on Windows only due to that bug.  Restore compatibility with such
projects by guarding the change behind a new policy ``CMP0194``.

Fixes: #26907
Issue: #26617
This commit is contained in:
Brad King 2025-05-02 14:04:48 -04:00
parent 3c992e336b
commit 14212494bb
19 changed files with 120 additions and 7 deletions

View File

@ -98,6 +98,7 @@ Policies Introduced by CMake 4.1
.. toctree::
:maxdepth: 1
CMP0194: MSVC is not an assembler for language ASM. </policy/CMP0194>
CMP0193: GNUInstallDirs caches CMAKE_INSTALL_* with leading 'usr/' for install prefix '/'. </policy/CMP0193>
CMP0192: GNUInstallDirs uses absolute SYSCONFDIR, LOCALSTATEDIR, and RUNSTATEDIR in special prefixes. </policy/CMP0192>
CMP0191: The FindCABLE module is removed. </policy/CMP0191>

27
Help/policy/CMP0194.rst Normal file
View File

@ -0,0 +1,27 @@
CMP0194
-------
.. versionadded:: 4.1
MSVC is not an assembler for language ASM.
When enabling the ``ASM`` language, CMake considers C compiler drivers
as assembler candidates. CMake 4.0 and below accidentally selected
MSVC's ``cl`` compiler as the ``CMAKE_ASM_COMPILER``, allowing the ``ASM``
language to be enabled on Windows even though ``cl`` does not support
assembler sources. CMake 4.1 and above prefer to reject ``cl`` as an
assembler candidate, but some existing projects unconditionally enable
``ASM`` on Windows even though they add no assembler sources. This
policy provides compatibility for such projects to allow them to
configure as before.
The ``OLD`` behavior for this policy is to successfully enable ``ASM``
even if ``cl`` is the only available candidate. The ``NEW`` behavior
for this policy is to not consider ``cl`` as a candidate assembler
for the ``ASM`` language.
.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.1
.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
.. include:: include/STANDARD_ADVICE.rst
.. include:: include/DEPRECATED.rst

View File

@ -0,0 +1,5 @@
asm-no-msvc
-----------
* Enabling ``ASM`` no longer accidentally succeeds using ``MSVC``'s ``cl``
C compiler as an assembler. See policy :policy:`CMP0194`.

View File

@ -22,7 +22,7 @@ if(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
include(Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE)
endif()
if(NOT _INCLUDED_FILE)
if("ASM${ASM_DIALECT}" STREQUAL "ASM")
if("ASM${ASM_DIALECT}" STREQUAL "ASM" AND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
message(STATUS "Warning: Did not find file Compiler/${CMAKE_ASM${ASM_DIALECT}_COMPILER_ID}-ASM${ASM_DIALECT}")
endif()
include(Platform/${CMAKE_BASE_NAME} OPTIONAL)

View File

@ -6,6 +6,8 @@
include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake)
cmake_policy(GET CMP0194 _CMAKE_ASM_CMP0194)
if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER)
# prefer the environment variable ASM
if(NOT $ENV{ASM${ASM_DIALECT}} STREQUAL "")
@ -21,19 +23,32 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER)
# finally list compilers to try
if("ASM${ASM_DIALECT}" STREQUAL "ASM") # the generic assembler support
if(NOT CMAKE_ASM_COMPILER_INIT)
if(CMAKE_C_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_ID MATCHES "^(MSVC)$")
if(_CMAKE_ASM_CMP0194 STREQUAL "NEW")
set(_CMAKE_ASM_REGEX_MSVC "^(MSVC)$")
set(_CMAKE_ASM_REGEX_CL "(^|/)[Cc][Ll](\\.|$)")
set(_CMAKE_ASM_MAYBE_CL "")
else()
set(_CMAKE_ASM_REGEX_MSVC "CMP0194_OLD_MSVC_NOT_EXCLUDED")
set(_CMAKE_ASM_REGEX_CL "CMP0194_OLD_MSVC_NOT_EXCLUDED")
set(_CMAKE_ASM_MAYBE_CL "cl")
endif()
if(CMAKE_C_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_ID MATCHES "${_CMAKE_ASM_REGEX_MSVC}")
set(CMAKE_ASM_COMPILER_LIST ${CMAKE_C_COMPILER})
elseif(NOT CMAKE_C_COMPILER_LOADED AND CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER MATCHES "(^|/)[Cc][Ll](\\.|$)")
elseif(NOT CMAKE_C_COMPILER_LOADED AND CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER MATCHES "${_CMAKE_ASM_REGEX_CL}")
set(CMAKE_ASM_COMPILER_LIST ${CMAKE_C_COMPILER})
elseif(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_CXX_COMPILER_ID MATCHES "^(MSVC)$")
elseif(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_CXX_COMPILER_ID MATCHES "${_CMAKE_ASM_REGEX_MSVC}")
set(CMAKE_ASM_COMPILER_LIST ${CMAKE_CXX_COMPILER})
elseif(NOT CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER AND NOT CMAKE_CXX_COMPILER MATCHES "(^|/)[Cc][Ll](\\.|$)")
elseif(NOT CMAKE_CXX_COMPILER_LOADED AND CMAKE_CXX_COMPILER AND NOT CMAKE_CXX_COMPILER MATCHES "${_CMAKE_ASM_REGEX_CL}")
set(CMAKE_ASM_COMPILER_LIST ${CMAKE_CXX_COMPILER})
else()
# List all default C and CXX compilers
set(CMAKE_ASM_COMPILER_LIST
${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc xlc
${_CMAKE_ASM_MAYBE_CL}
CC ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ xlC)
unset(_CMAKE_ASM_MAYBE_CL)
unset(_CMAKE_ASM_REGEX_CL)
unset(_CMAKE_ASM_REGEX_MSVC)
endif()
endif()
else() # some specific assembler "dialect"
@ -100,7 +115,11 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER_ID)
list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS MSVC )
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_MSVC "-?")
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_MSVC "Microsoft.*Macro Assembler")
if(_CMAKE_ASM_CMP0194 STREQUAL "NEW")
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_MSVC "Microsoft.*Macro Assembler")
else()
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_REGEX_MSVC "Microsoft")
endif()
list(APPEND CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDORS TI )
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_ID_VENDOR_FLAGS_TI "-h")
@ -200,6 +219,11 @@ else()
message(STATUS "The ASM${ASM_DIALECT} compiler identification is unknown")
endif()
if("ASM${ASM_DIALECT}" STREQUAL "ASM" AND CMAKE_ASM_COMPILER_ID STREQUAL "MSVC" AND _CMAKE_ASM_CMP0194 STREQUAL "")
cmake_policy(GET_WARNING CMP0194 _CMAKE_ASM_CMP0194_WARNING)
message(AUTHOR_WARNING "${_CMAKE_ASM_CMP0194_WARNING}")
endif()
# If we have a gas/as cross compiler, they have usually some prefix, like
# e.g. powerpc-linux-gas, arm-elf-gas or i586-mingw32msvc-gas , optionally
# with a 3-component version number at the end

View File

@ -578,7 +578,9 @@ class cmMakefile;
SELECT(POLICY, CMP0193, \
"GNUInstallDirs caches CMAKE_INSTALL_* with leading 'usr/' for " \
"install prefix '/'.", \
4, 1, 0, WARN)
4, 1, 0, WARN) \
SELECT(POLICY, CMP194, "MSVC is not an assembler for language ASM.", 4, 1, \
0, WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,9 @@
^CMake Error at CMP0194-common\.cmake:[0-9]+ \(enable_language\):
No CMAKE_ASM_COMPILER could be found\.
(
Tell CMake where to find the compiler by setting either the environment
variable "ASM" or the CMake cache entry CMAKE_ASM_COMPILER to the full path
to the compiler, or to the compiler name if it is in the PATH\.)?
Call Stack \(most recent call first\):
CMP0194-NEW\.cmake:[0-9]+ \(include\)
CMakeLists\.txt:[0-9]+ \(include\)$

View File

@ -0,0 +1,2 @@
-- The ASM compiler identification is unknown
-- Didn't find assembler

View File

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

View File

@ -0,0 +1,3 @@
-- The ASM compiler identification is MSVC
-- Found assembler: [^
]*/cl\.exe

View File

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

View File

@ -0,0 +1,10 @@
^CMake Warning \(dev\) at [^
]*/Modules/CMakeDetermineASMCompiler.cmake:[0-9]+ \(message\):
Policy CMP194 is not set: MSVC is not an assembler for language ASM\. Run
"cmake --help-policy CMP194" for policy details\. Use the cmake_policy
command to set the policy and suppress this warning\.
Call Stack \(most recent call first\):
CMP0194-common\.cmake:[0-9]+ \(enable_language\)
CMP0194-WARN\.cmake:[0-9]+ \(include\)
CMakeLists.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.$

View File

@ -0,0 +1,3 @@
-- The ASM compiler identification is MSVC
-- Found assembler: [^
]*/cl\.exe

View File

@ -0,0 +1,2 @@
# CMP0194 is unset
include(CMP0194-common.cmake)

View File

@ -0,0 +1,3 @@
enable_language(C)
set(ENV{PATH} "")
enable_language(ASM)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 4.0)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1,10 @@
include(RunCMake)
# The test cases empty the PATH before enabling ASM to avoid finding
# another assembler in the caller's environment. However, old
# versions of MSVC do not support running `cl` without the PATH set.
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16)
run_cmake(CMP0194-WARN)
run_cmake(CMP0194-OLD)
endif()
run_cmake(CMP0194-NEW)

View File

@ -181,6 +181,10 @@ add_RunCMake_test(CMP0171)
add_RunCMake_test(CMP0173)
add_RunCMake_test(CMP0187)
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
add_RunCMake_test(CMP0194 -DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
endif()
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
# generators ignore. The policy will have no effect on those generators.