Features: Define meaning for no language standard default
Define an empty string in CMAKE_<LANG>_STANDARD_DEFAULT to mean that the toolchain has no notion of lanuage standard levels. In this case the <LANG>_STANDARD[_REQUIRED] properties will have no effect. Update the RunCMake.CompileFeatures test to exclude the LinkImplementationFeatureCycle test when there is no standard default. It can never fail because no use of specific features will adjust the CXX_STANDARD level required for any target since the standard levels have no meaning in this case.
This commit is contained in:
parent
ea7ca139ea
commit
3228fc5049
|
@ -80,7 +80,9 @@ When adding the first supported feature to a particular CompilerId, it is
|
||||||
necessary to list support for all features known to cmake (See
|
necessary to list support for all features known to cmake (See
|
||||||
:variable:`CMAKE_C_COMPILE_FEATURES` and
|
:variable:`CMAKE_C_COMPILE_FEATURES` and
|
||||||
:variable:`CMAKE_CXX_COMPILE_FEATURES` as appropriate), where available for
|
:variable:`CMAKE_CXX_COMPILE_FEATURES` as appropriate), where available for
|
||||||
the compiler.
|
the compiler. Furthermore, set ``CMAKE_<LANG>_STANDARD_DEFAULT`` to the
|
||||||
|
default language standard level the compiler uses, or to the empty string
|
||||||
|
if the compiler has no notion of standard levels (such as ``MSVC``).
|
||||||
|
|
||||||
It is sensible to record the features for the most recent version of a
|
It is sensible to record the features for the most recent version of a
|
||||||
particular CompilerId first, and then work backwards. It is sensible to
|
particular CompilerId first, and then work backwards. It is sensible to
|
||||||
|
|
|
@ -5,7 +5,8 @@ The C++ standard whose features are requested to build this target.
|
||||||
|
|
||||||
This property specifies the C++ standard whose features are requested
|
This property specifies the C++ standard whose features are requested
|
||||||
to build this target. For some compilers, this results in adding a
|
to build this target. For some compilers, this results in adding a
|
||||||
flag such as ``-std=gnu++11`` to the compile line.
|
flag such as ``-std=gnu++11`` to the compile line. For compilers that
|
||||||
|
have no notion of a standard level, such as MSVC, this has no effect.
|
||||||
|
|
||||||
Supported values are ``98``, ``11`` and ``14``.
|
Supported values are ``98``, ``11`` and ``14``.
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ If this property is set to ``ON``, then the value of the
|
||||||
:prop_tgt:`CXX_STANDARD` target property is treated as a requirement. If this
|
:prop_tgt:`CXX_STANDARD` target property is treated as a requirement. If this
|
||||||
property is ``OFF`` or unset, the :prop_tgt:`CXX_STANDARD` target property is
|
property is ``OFF`` or unset, the :prop_tgt:`CXX_STANDARD` target property is
|
||||||
treated as optional and may "decay" to a previous standard if the requested is
|
treated as optional and may "decay" to a previous standard if the requested is
|
||||||
not available.
|
not available. For compilers that have no notion of a standard level, such as
|
||||||
|
MSVC, this has no effect.
|
||||||
|
|
||||||
See the :manual:`cmake-compile-features(7)` manual for information on
|
See the :manual:`cmake-compile-features(7)` manual for information on
|
||||||
compile features.
|
compile features.
|
||||||
|
|
|
@ -5,7 +5,8 @@ The C standard whose features are requested to build this target.
|
||||||
|
|
||||||
This property specifies the C standard whose features are requested
|
This property specifies the C standard whose features are requested
|
||||||
to build this target. For some compilers, this results in adding a
|
to build this target. For some compilers, this results in adding a
|
||||||
flag such as ``-std=gnu11`` to the compile line.
|
flag such as ``-std=gnu11`` to the compile line. For compilers that
|
||||||
|
have no notion of a standard level, such as MSVC, this has no effect.
|
||||||
|
|
||||||
Supported values are ``90``, ``99`` and ``11``.
|
Supported values are ``90``, ``99`` and ``11``.
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ If this property is set to ``ON``, then the value of the
|
||||||
:prop_tgt:`C_STANDARD` target property is treated as a requirement. If this
|
:prop_tgt:`C_STANDARD` target property is treated as a requirement. If this
|
||||||
property is ``OFF`` or unset, the :prop_tgt:`C_STANDARD` target property is
|
property is ``OFF`` or unset, the :prop_tgt:`C_STANDARD` target property is
|
||||||
treated as optional and may "decay" to a previous standard if the requested is
|
treated as optional and may "decay" to a previous standard if the requested is
|
||||||
not available.
|
not available. For compilers that have no notion of a standard level, such as
|
||||||
|
MSVC, this has no effect.
|
||||||
|
|
||||||
See the :manual:`cmake-compile-features(7)` manual for information on
|
See the :manual:`cmake-compile-features(7)` manual for information on
|
||||||
compile features.
|
compile features.
|
||||||
|
|
|
@ -1370,6 +1370,8 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
|
||||||
{
|
{
|
||||||
std::vector<std::string> const& langAvailable
|
std::vector<std::string> const& langAvailable
|
||||||
= availableFeatures[lit->first];
|
= availableFeatures[lit->first];
|
||||||
|
const char* standardDefault = context->Makefile
|
||||||
|
->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT");
|
||||||
for (std::vector<std::string>::const_iterator it = lit->second.begin();
|
for (std::vector<std::string>::const_iterator it = lit->second.begin();
|
||||||
it != lit->second.end(); ++it)
|
it != lit->second.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -1378,6 +1380,12 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
|
||||||
{
|
{
|
||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
|
if (standardDefault && !*standardDefault)
|
||||||
|
{
|
||||||
|
// This compiler has no notion of language standard levels.
|
||||||
|
// All features known for the language are always available.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!context->Makefile->HaveStandardAvailable(target,
|
if (!context->Makefile->HaveStandardAvailable(target,
|
||||||
lit->first, *it))
|
lit->first, *it))
|
||||||
{
|
{
|
||||||
|
@ -1386,8 +1394,7 @@ static const struct CompileFeaturesNode : public cmGeneratorExpressionNode
|
||||||
const char* l = target->GetProperty(lit->first + "_STANDARD");
|
const char* l = target->GetProperty(lit->first + "_STANDARD");
|
||||||
if (!l)
|
if (!l)
|
||||||
{
|
{
|
||||||
l = context->Makefile
|
l = standardDefault;
|
||||||
->GetDefinition("CMAKE_" + lit->first + "_STANDARD_DEFAULT");
|
|
||||||
}
|
}
|
||||||
assert(l);
|
assert(l);
|
||||||
context->MaxLanguageStandard[target][lit->first] = l;
|
context->MaxLanguageStandard[target][lit->first] = l;
|
||||||
|
|
|
@ -2207,6 +2207,13 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const char* defaultStd
|
||||||
|
= this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT");
|
||||||
|
if (defaultStd && !*defaultStd)
|
||||||
|
{
|
||||||
|
// This compiler has no notion of language standard levels.
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::string stdProp = lang + "_STANDARD";
|
std::string stdProp = lang + "_STANDARD";
|
||||||
const char *standardProp = target->GetProperty(stdProp);
|
const char *standardProp = target->GetProperty(stdProp);
|
||||||
if (!standardProp)
|
if (!standardProp)
|
||||||
|
@ -2269,8 +2276,6 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
|
||||||
std::find(stds.begin(), stds.end(), standard);
|
std::find(stds.begin(), stds.end(), standard);
|
||||||
assert(stdIt != stds.end());
|
assert(stdIt != stds.end());
|
||||||
|
|
||||||
const char* defaultStd
|
|
||||||
= this->Makefile->GetDefinition("CMAKE_" + lang + "_STANDARD_DEFAULT");
|
|
||||||
std::vector<std::string>::const_iterator defaultStdIt;
|
std::vector<std::string>::const_iterator defaultStdIt;
|
||||||
if (defaultStd)
|
if (defaultStd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5253,6 +5253,27 @@ bool cmMakefile::
|
||||||
HaveCStandardAvailable(cmTarget const* target,
|
HaveCStandardAvailable(cmTarget const* target,
|
||||||
const std::string& feature) const
|
const std::string& feature) const
|
||||||
{
|
{
|
||||||
|
const char* defaultCStandard =
|
||||||
|
this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
|
||||||
|
if (!defaultCStandard)
|
||||||
|
{
|
||||||
|
std::ostringstream e;
|
||||||
|
e << "CMAKE_C_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
|
||||||
|
"not fully configured for this compiler.";
|
||||||
|
this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
|
||||||
|
// Return true so the caller does not try to lookup the default standard.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
|
||||||
|
cmStrCmp(defaultCStandard)) == cmArrayEnd(C_STANDARDS))
|
||||||
|
{
|
||||||
|
std::ostringstream e;
|
||||||
|
e << "The CMAKE_C_STANDARD_DEFAULT variable contains an "
|
||||||
|
"invalid value: \"" << defaultCStandard << "\".";
|
||||||
|
this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool needC90 = false;
|
bool needC90 = false;
|
||||||
bool needC99 = false;
|
bool needC99 = false;
|
||||||
bool needC11 = false;
|
bool needC11 = false;
|
||||||
|
@ -5262,7 +5283,7 @@ HaveCStandardAvailable(cmTarget const* target,
|
||||||
const char *existingCStandard = target->GetProperty("C_STANDARD");
|
const char *existingCStandard = target->GetProperty("C_STANDARD");
|
||||||
if (!existingCStandard)
|
if (!existingCStandard)
|
||||||
{
|
{
|
||||||
existingCStandard = this->GetDefinition("CMAKE_C_STANDARD_DEFAULT");
|
existingCStandard = defaultCStandard;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
|
if (std::find_if(cmArrayBegin(C_STANDARDS), cmArrayEnd(C_STANDARDS),
|
||||||
|
@ -5331,6 +5352,27 @@ bool cmMakefile::IsLaterStandard(std::string const& lang,
|
||||||
bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target,
|
bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target,
|
||||||
const std::string& feature) const
|
const std::string& feature) const
|
||||||
{
|
{
|
||||||
|
const char* defaultCxxStandard =
|
||||||
|
this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
|
||||||
|
if (!defaultCxxStandard)
|
||||||
|
{
|
||||||
|
std::ostringstream e;
|
||||||
|
e << "CMAKE_CXX_STANDARD_DEFAULT is not set. COMPILE_FEATURES support "
|
||||||
|
"not fully configured for this compiler.";
|
||||||
|
this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
|
||||||
|
// Return true so the caller does not try to lookup the default standard.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
|
||||||
|
cmStrCmp(defaultCxxStandard)) == cmArrayEnd(CXX_STANDARDS))
|
||||||
|
{
|
||||||
|
std::ostringstream e;
|
||||||
|
e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an "
|
||||||
|
"invalid value: \"" << defaultCxxStandard << "\".";
|
||||||
|
this->IssueMessage(cmake::INTERNAL_ERROR, e.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool needCxx98 = false;
|
bool needCxx98 = false;
|
||||||
bool needCxx11 = false;
|
bool needCxx11 = false;
|
||||||
bool needCxx14 = false;
|
bool needCxx14 = false;
|
||||||
|
@ -5339,7 +5381,7 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target,
|
||||||
const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
|
const char *existingCxxStandard = target->GetProperty("CXX_STANDARD");
|
||||||
if (!existingCxxStandard)
|
if (!existingCxxStandard)
|
||||||
{
|
{
|
||||||
existingCxxStandard = this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT");
|
existingCxxStandard = defaultCxxStandard;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
|
if (std::find_if(cmArrayBegin(CXX_STANDARDS), cmArrayEnd(CXX_STANDARDS),
|
||||||
|
|
|
@ -128,26 +128,30 @@ foreach(lang CXX C)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if (CMAKE_C_COMPILE_FEATURES)
|
if (CMAKE_C_COMPILE_FEATURES)
|
||||||
string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx)
|
if (CMAKE_C_STANDARD_DEFAULT)
|
||||||
if (std_flag_idx EQUAL -1)
|
string(FIND "${CMAKE_C_FLAGS}" "-std=" std_flag_idx)
|
||||||
add_executable(default_dialect_C default_dialect.c)
|
if (std_flag_idx EQUAL -1)
|
||||||
target_compile_definitions(default_dialect_C PRIVATE
|
add_executable(default_dialect_C default_dialect.c)
|
||||||
DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
|
target_compile_definitions(default_dialect_C PRIVATE
|
||||||
DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
|
DEFAULT_C11=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},11>
|
||||||
DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
|
DEFAULT_C99=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},99>
|
||||||
)
|
DEFAULT_C90=$<EQUAL:${CMAKE_C_STANDARD_DEFAULT},90>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILE_FEATURES)
|
if (CMAKE_CXX_COMPILE_FEATURES)
|
||||||
string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx)
|
if (CMAKE_CXX_STANDARD_DEFAULT)
|
||||||
if (std_flag_idx EQUAL -1)
|
string(FIND "${CMAKE_CXX_FLAGS}" "-std=" std_flag_idx)
|
||||||
add_executable(default_dialect default_dialect.cpp)
|
if (std_flag_idx EQUAL -1)
|
||||||
target_compile_definitions(default_dialect PRIVATE
|
add_executable(default_dialect default_dialect.cpp)
|
||||||
DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
|
target_compile_definitions(default_dialect PRIVATE
|
||||||
DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11>
|
DEFAULT_CXX14=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},14>
|
||||||
DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98>
|
DEFAULT_CXX11=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},11>
|
||||||
)
|
DEFAULT_CXX98=$<EQUAL:${CMAKE_CXX_STANDARD_DEFAULT},98>
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(CompileFeatures main.cpp)
|
add_executable(CompileFeatures main.cpp)
|
||||||
|
|
|
@ -17,6 +17,8 @@ file(READ
|
||||||
"${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt"
|
"${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_features.txt"
|
||||||
CXX_FEATURES
|
CXX_FEATURES
|
||||||
)
|
)
|
||||||
|
include("${RunCMake_BINARY_DIR}/generate_feature_list-build/c_standard_default.cmake")
|
||||||
|
include("${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx_standard_default.cmake")
|
||||||
|
|
||||||
if (NOT C_FEATURES)
|
if (NOT C_FEATURES)
|
||||||
run_cmake(NoSupportedCFeatures)
|
run_cmake(NoSupportedCFeatures)
|
||||||
|
@ -27,7 +29,9 @@ if (NOT CXX_FEATURES)
|
||||||
run_cmake(NoSupportedCxxFeatures)
|
run_cmake(NoSupportedCxxFeatures)
|
||||||
run_cmake(NoSupportedCxxFeaturesGenex)
|
run_cmake(NoSupportedCxxFeaturesGenex)
|
||||||
else()
|
else()
|
||||||
run_cmake(LinkImplementationFeatureCycle)
|
if(CXX_STANDARD_DEFAULT)
|
||||||
|
run_cmake(LinkImplementationFeatureCycle)
|
||||||
|
endif()
|
||||||
run_cmake(LinkImplementationFeatureCycleSolved)
|
run_cmake(LinkImplementationFeatureCycleSolved)
|
||||||
|
|
||||||
if (";${CXX_FEATURES};" MATCHES ";cxx_final;")
|
if (";${CXX_FEATURES};" MATCHES ";cxx_final;")
|
||||||
|
@ -38,17 +42,19 @@ else()
|
||||||
unset(RunCMake_TEST_OPTIONS)
|
unset(RunCMake_TEST_OPTIONS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach(standard 98 11)
|
if(CXX_STANDARD_DEFAULT)
|
||||||
file(READ
|
foreach(standard 98 11)
|
||||||
"${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx${standard}_flag.txt"
|
file(READ
|
||||||
CXX${standard}_FLAG
|
"${RunCMake_BINARY_DIR}/generate_feature_list-build/cxx${standard}_flag.txt"
|
||||||
)
|
CXX${standard}_FLAG
|
||||||
if (CXX${standard}_FLAG STREQUAL NOTFOUND)
|
)
|
||||||
run_cmake(RequireCXX${standard})
|
if (CXX${standard}_FLAG STREQUAL NOTFOUND)
|
||||||
run_cmake(RequireCXX${standard}Variable)
|
run_cmake(RequireCXX${standard})
|
||||||
endif()
|
run_cmake(RequireCXX${standard}Variable)
|
||||||
if (CXX${standard}EXT_FLAG STREQUAL NOTFOUND)
|
endif()
|
||||||
run_cmake(RequireCXX${standard}Ext)
|
if (CXX${standard}EXT_FLAG STREQUAL NOTFOUND)
|
||||||
run_cmake(RequireCXX${standard}ExtVariable)
|
run_cmake(RequireCXX${standard}Ext)
|
||||||
endif()
|
run_cmake(RequireCXX${standard}ExtVariable)
|
||||||
endforeach()
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
|
@ -9,6 +9,20 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_features.txt"
|
||||||
"${CMAKE_CXX_COMPILE_FEATURES}"
|
"${CMAKE_CXX_COMPILE_FEATURES}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(DEFINED CMAKE_C_STANDARD_DEFAULT)
|
||||||
|
set(c_standard_default_code "set(C_STANDARD_DEFAULT \"${CMAKE_C_STANDARD_DEFAULT}\")\n")
|
||||||
|
else()
|
||||||
|
set(c_standard_default_code "unset(C_STANDARD_DEFAULT)\n")
|
||||||
|
endif()
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/c_standard_default.cmake" "${c_standard_default_code}")
|
||||||
|
|
||||||
|
if(DEFINED CMAKE_CXX_STANDARD_DEFAULT)
|
||||||
|
set(cxx_standard_default_code "set(CXX_STANDARD_DEFAULT \"${CMAKE_CXX_STANDARD_DEFAULT}\")\n")
|
||||||
|
else()
|
||||||
|
set(cxx_standard_default_code "unset(CXX_STANDARD_DEFAULT)\n")
|
||||||
|
endif()
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_standard_default.cmake" "${cxx_standard_default_code}")
|
||||||
|
|
||||||
foreach(standard 98 11)
|
foreach(standard 98 11)
|
||||||
set(CXX${standard}_FLAG NOTFOUND)
|
set(CXX${standard}_FLAG NOTFOUND)
|
||||||
if (DEFINED CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
|
if (DEFINED CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION)
|
||||||
|
|
Loading…
Reference in New Issue