Compile with explicit language flag when source LANGUAGE property is set

This change was originally made by commit 74b1c9fc8e (Explicitly specify
language flag when source LANGUAGE property is set, 2020-06-01,
v3.19.0-rc1~722^2), but it was reverted by commit 30aa715fac (Revert
"specify language flag when source LANGUAGE property is set",
2020-11-19) to restore compatibility with pre-3.19 behavior.

Implement the change again, but add policy CMP0119 to make this change
while preserving compatibility with existing projects.

Note that the `Compiler/{Clang,Intel,MSVC}-CXX` modules do not need to
specify `-TP` for their MSVC-like variants because we already use the
flag in `CMAKE_CXX_COMPILE_OBJECT`.  Similarly for `Compiler/XL-CXX`
and `Platform/Windows-Embarcadero`.

Note also that this does not seem possible to implement for XL C.
Even with `-qsourcetype=c`, `xlc` complains about an unknown suffix:
`1501-218 (W) file /.../AltExtC.zzz contains an incorrect file suffix`.
It returns non-zero even with `-qsuppress=1501-218`.

Co-Author: Robert Maynard <robert.maynard@kitware.com>
Fixes: #14516, #20716
This commit is contained in:
Brad King 2020-11-19 16:12:01 -05:00
parent 2e67a75acd
commit 48aac247e9
39 changed files with 199 additions and 5 deletions

View File

@ -57,6 +57,7 @@ Policies Introduced by CMake 3.20
.. toctree::
:maxdepth: 1
CMP0119: LANGUAGE source file property explicitly compiles as language. </policy/CMP0119>
CMP0118: The GENERATED source file property is now visible in all directories. </policy/CMP0118>
CMP0117: MSVC RTTI flag /GR is not added to CMAKE_CXX_FLAGS by default. </policy/CMP0117>
CMP0116: Ninja generators transform DEPFILEs from add_custom_command(). </policy/CMP0116>

36
Help/policy/CMP0119.rst Normal file
View File

@ -0,0 +1,36 @@
CMP0119
-------
.. versionadded:: 3.20
:prop_sf:`LANGUAGE` source file property explicitly compiles as specified
language.
The :prop_sf:`LANGUAGE` source file property is documented to mean that the
source file is written in the specified language. In CMake 3.19 and below,
setting this property causes CMake to compile the source file using the
compiler for the specified language. However, it only passes an explicit
flag to tell the compiler to treat the source as the specified language
for MSVC-like, XL, and Embarcadero compilers for the ``CXX`` language.
CMake 3.20 and above prefer to also explicitly tell the compiler to use
the specified language using a flag such as ``-x c`` on all compilers
for which such flags are known.
This policy provides compatibility for projects that have not been updated
to expect this behavior. For example, some projects were setting the
``LANGUAGE`` property to ``C`` on assembly-language ``.S`` source files
in order to compile them using the C compiler. Such projects should be
updated to use ``enable_language(ASM)``, for which CMake will often choose
the C compiler as the assembler on relevant platforms anyway.
The ``OLD`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
property using its undocumented meaning to "use the ``<LANG>`` compiler".
The ``NEW`` behavior for this policy is to interpret the ``LANGUAGE <LANG>``
property using its documented meaning to "compile as a ``<LANG>`` source".
This policy was introduced in CMake version 3.20. Use the
:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
Unlike many policies, CMake version |release| does *not* warn
when this policy is not set and simply uses ``OLD`` behavior.
.. include:: DEPRECATED.txt

View File

@ -1,7 +1,7 @@
LANGUAGE
--------
What programming language is the file.
Specify the programming language in which a source file is written.
A property that can be set to indicate what programming language the
source file is. If it is not set the language is determined based on
@ -9,3 +9,9 @@ the file extension. Typical values are ``CXX`` (i.e. C++), ``C``,
``CSharp``, ``CUDA``, ``Fortran``, ``ISPC``, and ``ASM``. Setting this
property for a file means this file will be compiled. Do not set this
for headers or files that should not be compiled.
.. versionchanged:: 3.20
Setting this property causes the source file to be compiled as the
specified language, using explicit flags if possible. Previously it
only caused the specified language's compiler to be used.
See policy :policy:`CMP0119`.

View File

@ -0,0 +1,5 @@
explicit-LANGUAGE-flag
----------------------
* The :prop_sf:`LANGUAGE` source file property now forces compilation
as the specified language. See policy :policy:`CMP0119`.

View File

@ -12,6 +12,7 @@ if(NOT "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
endif()
endif()
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")

View File

@ -1,6 +1,8 @@
include(Compiler/Clang)
__compiler_clang(CXX)
set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
if(NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
AND CMAKE_GENERATOR MATCHES "Makefiles"

View File

@ -7,6 +7,7 @@ if(APPLE AND NOT appleClangPolicy STREQUAL NEW)
endif()
if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
@ -14,6 +15,7 @@ if("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
endif()
elseif("x${CMAKE_C_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
AND CMAKE_GENERATOR MATCHES "Makefiles|WMake"
AND CMAKE_DEPFILE_FLAGS_C)

View File

@ -11,6 +11,7 @@ if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU")
set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
endif()
set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden")
endif()

View File

@ -10,6 +10,7 @@ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
set(CMAKE_C_DEPENDS_USE_COMPILER TRUE)
endif()
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c90")

View File

@ -10,6 +10,7 @@ if((NOT DEFINED CMAKE_DEPENDS_USE_COMPILER OR CMAKE_DEPENDS_USE_COMPILER)
set(CMAKE_CXX_DEPENDS_USE_COMPILER TRUE)
endif()
set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
if (WIN32)
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)

View File

@ -15,6 +15,7 @@ endif()
if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 16.0.0)
@ -34,6 +35,8 @@ if("x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
else()
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
if (NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 15.0.0)
set(CMAKE_C11_STANDARD_COMPILE_OPTION "-std=c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "-std=gnu11")

View File

@ -48,6 +48,8 @@ if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
else()
set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.0.0)
set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std=c++20")
set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std=gnu++20")

View File

@ -27,6 +27,7 @@ else()
set(CMAKE_C_STANDARD_DEFAULT "")
endif()
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -TC)
set(CMAKE_C_CLANG_TIDY_DRIVER_MODE "cl")
# There are no C compiler modes so we hard-code the known compiler supported

View File

@ -1,6 +1,8 @@
include(Compiler/XLClang)
__compiler_xlclang(C)
set(CMAKE_C_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c)
if (CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
set(CMAKE_C90_STANDARD_COMPILE_OPTION "-std=c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "-std=gnu89")

View File

@ -1,6 +1,8 @@
include(Compiler/XLClang)
__compiler_xlclang(CXX)
set(CMAKE_CXX_COMPILE_OPTIONS_EXPLICIT_LANGUAGE -x c++)
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.1.1)
set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")

View File

@ -349,6 +349,11 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
if (language.empty()) {
language = "C";
}
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
gtgt->AddExplicitLanguageFlags(flags, *source);
std::string const& config =
lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");

View File

@ -3155,6 +3155,30 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config,
}
}
void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const
{
cmProp lang = sf.GetProperty("LANGUAGE");
if (!lang) {
return;
}
switch (this->GetPolicyStatusCMP0119()) {
case cmPolicies::WARN:
case cmPolicies::OLD:
// The OLD behavior is to not add explicit language flags.
return;
case cmPolicies::REQUIRED_ALWAYS:
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::NEW:
// The NEW behavior is to add explicit language flags.
break;
}
this->LocalGenerator->AppendFeatureOptions(flags, *lang,
"EXPLICIT_LANGUAGE");
}
void cmGeneratorTarget::AddCUDAArchitectureFlags(std::string& flags) const
{
const std::string& property = this->GetSafeProperty("CUDA_ARCHITECTURES");

View File

@ -447,6 +447,9 @@ public:
void GetAppleArchs(const std::string& config,
std::vector<std::string>& archVec) const;
void AddExplicitLanguageFlags(std::string& flags,
cmSourceFile const& sf) const;
void AddCUDAArchitectureFlags(std::string& flags) const;
void AddCUDAToolkitFlags(std::string& flags) const;

View File

@ -938,6 +938,11 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile(
default:
break;
}
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
gtgt->AddExplicitLanguageFlags(flags, *sf);
const std::string COMPILE_FLAGS("COMPILE_FLAGS");
if (cmProp cflags = sf->GetProperty(COMPILE_FLAGS)) {
lg->AppendFlags(flags, genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));

View File

@ -622,6 +622,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Build the set of compiler flags.
std::string flags;
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
this->GeneratorTarget->AddExplicitLanguageFlags(flags, source);
// Add language-specific flags.
std::string langFlags = cmStrCat("$(", lang, "_FLAGS", filterArch, ")");
this->LocalGenerator->AppendFlags(flags, langFlags);

View File

@ -183,7 +183,15 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
}
}
std::string flags = this->GetFlags(language, config, filterArch);
std::string flags;
// Explicitly add the explicit language flag before any other flag
// so user flags can override it.
this->GeneratorTarget->AddExplicitLanguageFlags(flags, *source);
if (!flags.empty()) {
flags += " ";
}
flags += this->GetFlags(language, config, filterArch);
// Add Fortran format flags.
if (language == "Fortran") {

View File

@ -352,7 +352,11 @@ class cmMakefile;
SELECT( \
POLICY, CMP0118, \
"The GENERATED source file property is now visible in all directories.", \
3, 20, 0, cmPolicies::WARN)
3, 20, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0119, \
"LANGUAGE source file property explicitly compiles as specified " \
"language.", \
3, 20, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@ -387,7 +391,8 @@ class cmMakefile;
F(CMP0105) \
F(CMP0108) \
F(CMP0112) \
F(CMP0113)
F(CMP0113) \
F(CMP0119)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies

View File

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

View File

@ -0,0 +1,3 @@
int main() {
return static_cast<int>(0);
}

View File

@ -0,0 +1,4 @@
enable_language(C)
add_executable(AltExtC AltExtC.zzz)
set_property(SOURCE AltExtC.zzz PROPERTY LANGUAGE C)

View File

@ -0,0 +1,6 @@
cmake_policy(SET CMP0119 NEW)
include(CMP0119-Common.cmake)
enable_language(CXX)
add_executable(AltExtCXX AltExtCXX.zzz)
set_property(SOURCE AltExtCXX.zzz PROPERTY LANGUAGE CXX)

View File

@ -0,0 +1 @@
[^0]

View File

@ -0,0 +1 @@
.*

View File

@ -0,0 +1,2 @@
cmake_policy(SET CMP0119 OLD)
include(CMP0119-Common.cmake)

View File

@ -0,0 +1 @@
[^0]

View File

@ -0,0 +1 @@
.*

View File

@ -0,0 +1,2 @@
include(CMP0119-Common.cmake)

View File

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

View File

@ -0,0 +1,17 @@
include(RunCMake)
function(run_CMP0119 status)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CMP0119-${status}-build)
run_cmake(CMP0119-${status})
set(RunCMake_TEST_NO_CLEAN 1)
run_cmake_command(CMP0119-${status}-build "${CMAKE_COMMAND}" --build . --config Debug)
endfunction()
if(NOT RunCMake_GENERATOR MATCHES "Visual Studio|Xcode" AND
NOT CMAKE_C_COMPILER_ID MATCHES "(Borland|Embarcadero|Watcom)")
run_CMP0119(WARN)
run_CMP0119(OLD)
endif()
if((CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang|MSVC|Borland|Embarcadero|Intel|TI)"))
run_CMP0119(NEW)
endif()

View File

@ -130,6 +130,7 @@ if(CMAKE_GENERATOR MATCHES "Ninja")
add_RunCMake_test(CMP0116)
endif()
add_RunCMake_test(CMP0118)
add_RunCMake_test(CMP0119 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode

View File

@ -34,6 +34,7 @@
\* CMP0108
\* CMP0112
\* CMP0113
\* CMP0119
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)

View File

@ -15,3 +15,11 @@ if(CMAKE_GENERATOR MATCHES "^Visual Studio" AND "x${CMAKE_C_COMPILER_ID}" STREQU
add_library(stay stay_c.c stay_cxx.cxx)
set_property(TARGET stay PROPERTY COMPILE_OPTIONS "-TP")
endif()
if((CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang|MSVC|Borland|Embarcadero|Intel|TI|XL)"))
cmake_policy(SET CMP0119 NEW)
add_library(zoom zoom.zzz)
set_source_files_properties(zoom.zzz PROPERTIES LANGUAGE CXX)
target_link_libraries(SetLang zoom)
target_compile_definitions(SetLang PRIVATE WITH_ZOOM)
endif()

View File

@ -1,10 +1,22 @@
#include <stdio.h>
int foo();
#ifdef WITH_ZOOM
int zoom();
#endif
class A
{
public:
A() { this->i = foo(); }
A()
{
this->i = foo();
#ifdef WITH_ZOOM
i += zoom();
i -= zoom();
#endif
}
int i;
};

7
Tests/SetLang/zoom.zzz Normal file
View File

@ -0,0 +1,7 @@
int zoom()
{
int r = 10;
r++;
int ret = r + 10;
return ret;
}