mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-08 16:50:48 +00:00
Merge topic 'enable-language-subdirectory'
86759dce81enable_language: add support for usage in subdirectories220fc8622dblock: Fix incorrect policy scope creation order Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !12222
This commit is contained in:
@@ -15,14 +15,15 @@ variables that are created by the :command:`project` command.
|
||||
|
||||
The following restrictions apply to where ``enable_language()`` may be called:
|
||||
|
||||
* It must be called in file scope, not in a :command:`function` call
|
||||
nor inside a :command:`block()`.
|
||||
* It must not be called before the first call to :command:`project`.
|
||||
See policy :policy:`CMP0165`.
|
||||
* It must be called in the highest directory common to all targets
|
||||
using the named language directly for compiling sources or
|
||||
indirectly through link dependencies. It is simplest to enable all
|
||||
needed languages in the top-level directory of a project.
|
||||
* It must be called such that the command executes before any targets that
|
||||
use the language directly for compiling sources or indirectly through link
|
||||
dependencies.
|
||||
|
||||
.. note::
|
||||
Further restrictions apply if policy :policy:`CMP0220` is not set
|
||||
to ``NEW``. See the policy documentation for details.
|
||||
|
||||
The ``OPTIONAL`` keyword is a placeholder for future implementation and
|
||||
does not currently work. Instead you can use the :module:`CheckLanguage`
|
||||
|
||||
@@ -94,6 +94,14 @@ Supported Policies
|
||||
|
||||
The following policies are supported.
|
||||
|
||||
Policies Introduced by CMake 4.5
|
||||
--------------------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
CMP0220: Languages enabled in subdirectories propagate to the top-level directory. </policy/CMP0220>
|
||||
|
||||
Policies Introduced by CMake 4.4
|
||||
--------------------------------
|
||||
|
||||
|
||||
64
Help/policy/CMP0220.rst
Normal file
64
Help/policy/CMP0220.rst
Normal file
@@ -0,0 +1,64 @@
|
||||
CMP0220
|
||||
-------
|
||||
|
||||
.. versionadded:: 4.5
|
||||
|
||||
Languages enabled in subdirectories propagate to the top-level directory.
|
||||
|
||||
In CMake 4.4 and below, enabling a language with the :command:`project`
|
||||
command or :command:`enable_language` command had some restrictions:
|
||||
|
||||
* It had to be called in file scope, not in a :command:`function` call
|
||||
nor inside a :command:`block`.
|
||||
* It had be called in the highest directory common to all targets
|
||||
using the named language directly for compiling sources or
|
||||
indirectly through link dependencies.
|
||||
|
||||
While these restrictions could be met by enabling all needed languages
|
||||
in the top-level directory of a project, this was not always easy.
|
||||
|
||||
CMake 4.5 and above prefer to relax these restrictions so that languages
|
||||
enabled by calls to the :command:`project` and :command:`enable_language`
|
||||
commands in subdirectories are available to targets created in ancestor
|
||||
and sibling directories created afterward. This policy provides
|
||||
compatibility with projects that have not been updated for the new behavior.
|
||||
|
||||
One may think of an :command:`add_subdirectory` call as an effective call
|
||||
site to :command:`enable_language` for languages enabled inside the
|
||||
subdirectory's tree. Similarly, for languages enabled in :command:`function`
|
||||
and :command:`block` scopes, the function or :command:`endblock` calls are
|
||||
effectively call sites to :command:`enable_language`.
|
||||
|
||||
This policy is evaluated independently at each "effective call site",
|
||||
proceeding up the stack of variable scopes to determine if the language
|
||||
should be enabled at that level. This propagation stops at the first
|
||||
ancestor scope whose ``CMP0220`` is not ``NEW``. For example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
block()
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
block()
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
block()
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
enable_language(CXX)
|
||||
# CXX is enabled in this scope
|
||||
endblock()
|
||||
# CXX is enabled in this scope
|
||||
endblock()
|
||||
# CXX is not enabled in this scope
|
||||
endblock()
|
||||
# CXX is not enabled in this scope
|
||||
|
||||
.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.5
|
||||
.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn by default
|
||||
.. include:: include/STANDARD_ADVICE.rst
|
||||
|
||||
See documentation of the
|
||||
:variable:`CMAKE_POLICY_WARNING_CMP0220 <CMAKE_POLICY_WARNING_CMP<NNNN>>`
|
||||
variable to control the warning.
|
||||
|
||||
.. include:: include/DEPRECATED.rst
|
||||
9
Help/release/dev/enable_language-subdirectory.rst
Normal file
9
Help/release/dev/enable_language-subdirectory.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
enable_language-subdirectory
|
||||
----------------------------
|
||||
|
||||
* The :command:`enable_language` command, and the :command:`project` command
|
||||
that calls it, may now be used in a subdirectory to enable a language for
|
||||
targets in ancestor directory scopes. The language configuration is
|
||||
propagated up to enclosing scopes. This also lifts the restriction for
|
||||
calling inside of :command:`block` and :command:`function` commands. See
|
||||
policy :policy:`CMP0220`.
|
||||
@@ -42,6 +42,8 @@ only for the policies that do not warn by default:
|
||||
policy :policy:`CMP0172`.
|
||||
* ``CMAKE_POLICY_WARNING_CMP0206`` controls the warning for
|
||||
policy :policy:`CMP0206`.
|
||||
* ``CMAKE_POLICY_WARNING_CMP0220`` controls the warning for
|
||||
policy :policy:`CMP0220`.
|
||||
|
||||
This variable should not be set by a project in CMake code. Project
|
||||
developers running CMake may set this variable in their cache to
|
||||
|
||||
@@ -40,19 +40,19 @@ public:
|
||||
BlockScopePushPop& operator=(BlockScopePushPop const&) = delete;
|
||||
|
||||
private:
|
||||
std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
|
||||
std::unique_ptr<cmMakefile::VariablePushPop> VariableScope;
|
||||
std::unique_ptr<cmMakefile::PolicyPushPop> PolicyScope;
|
||||
std::unique_ptr<cmMakefile::DiagnosticPushPop> DiagnosticScope;
|
||||
};
|
||||
|
||||
BlockScopePushPop::BlockScopePushPop(cmMakefile* mf, ScopeSet const& scopes)
|
||||
{
|
||||
if (scopes.contains(ScopeType::POLICIES)) {
|
||||
this->PolicyScope = cm::make_unique<cmMakefile::PolicyPushPop>(mf);
|
||||
}
|
||||
if (scopes.contains(ScopeType::VARIABLES)) {
|
||||
this->VariableScope = cm::make_unique<cmMakefile::VariablePushPop>(mf);
|
||||
}
|
||||
if (scopes.contains(ScopeType::POLICIES)) {
|
||||
this->PolicyScope = cm::make_unique<cmMakefile::PolicyPushPop>(mf);
|
||||
}
|
||||
if (scopes.contains(ScopeType::DIAGNOSTICS)) {
|
||||
this->DiagnosticScope = cm::make_unique<cmMakefile::DiagnosticPushPop>(mf);
|
||||
}
|
||||
|
||||
@@ -626,6 +626,13 @@ void cmGlobalGenerator::EnableLanguage(
|
||||
return;
|
||||
}
|
||||
|
||||
bool propagate = true;
|
||||
// If enable_language calls logic that calls enable_language, we don't
|
||||
// need to propagate variables twice
|
||||
if (!this->LanguagesInProgress.empty()) {
|
||||
propagate = false;
|
||||
}
|
||||
|
||||
std::set<std::string> cur_languages(languages.begin(), languages.end());
|
||||
for (std::string const& li : cur_languages) {
|
||||
if (!this->LanguagesInProgress.insert(li).second) {
|
||||
@@ -658,6 +665,12 @@ void cmGlobalGenerator::EnableLanguage(
|
||||
}
|
||||
}
|
||||
|
||||
// Variable scope to capture enable_language variables to be raised to root.
|
||||
std::unique_ptr<cmMakefile::VariablePushPop> variableScope;
|
||||
if (propagate) {
|
||||
variableScope = cm::make_unique<cmMakefile::VariablePushPop>(mf);
|
||||
}
|
||||
|
||||
bool fatalError = false;
|
||||
|
||||
mf->AddDefinitionBool("RUN_CONFIGURE", true);
|
||||
@@ -1109,6 +1122,30 @@ void cmGlobalGenerator::EnableLanguage(
|
||||
for (std::string const& lang : cur_languages) {
|
||||
this->LanguagesInProgress.erase(lang);
|
||||
}
|
||||
|
||||
// Propagate captured variables and set them at all scopes up to the root
|
||||
if (propagate) {
|
||||
cmStateSnapshot snapshot = mf->GetStateSnapshot();
|
||||
bool warnCMP0220 = false;
|
||||
for (std::string const& key : snapshot.LocalKeys()) {
|
||||
// Should never need to propagate unsets
|
||||
if (!key.empty()) {
|
||||
if (mf->RaiseToRoot(key, snapshot.GetDefinition(key).GetCStr()) ==
|
||||
cmStateSnapshot::WarnCMP0220::Yes) {
|
||||
warnCMP0220 = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (warnCMP0220 &&
|
||||
mf->PolicyOptionalWarningEnabled("CMAKE_POLICY_WARNING_CMP0220")) {
|
||||
mf->IssuePolicyWarning(
|
||||
cmPolicies::CMP0220, {},
|
||||
"For compatibility with older versions of CMake, the language "
|
||||
"configuration set by this call is not propagated to the enclosing "
|
||||
"variable scopes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cmGlobalGenerator::PrintCompilerAdvice(std::ostream& os,
|
||||
|
||||
@@ -3992,6 +3992,25 @@ void cmMakefile::RaiseScope(std::vector<std::string> const& variables)
|
||||
}
|
||||
}
|
||||
|
||||
cmStateSnapshot::WarnCMP0220 cmMakefile::RaiseToRoot(std::string const& var,
|
||||
char const* varDef)
|
||||
{
|
||||
if (var.empty()) {
|
||||
return cmStateSnapshot::WarnCMP0220::No;
|
||||
}
|
||||
cmStateSnapshot::WarnCMP0220 const warnCMP0220 =
|
||||
this->StateSnapshot.RaiseToRoot(var, varDef,
|
||||
cmStateSnapshot::CheckCMP0220::No);
|
||||
#ifndef CMAKE_BOOTSTRAP
|
||||
cmVariableWatch* vv = this->GetVariableWatch();
|
||||
if (vv) {
|
||||
vv->VariableAccessed(var, cmVariableWatch::VARIABLE_MODIFIED_ACCESS,
|
||||
varDef, this);
|
||||
}
|
||||
#endif
|
||||
return warnCMP0220;
|
||||
}
|
||||
|
||||
cmTarget* cmMakefile::AddImportedTarget(std::string const& name,
|
||||
cm::TargetType type,
|
||||
cm::ImportedTargetScope scope)
|
||||
|
||||
@@ -972,6 +972,8 @@ public:
|
||||
this->RaiseScope(var, value.GetCStr());
|
||||
}
|
||||
void RaiseScope(std::vector<std::string> const& variables);
|
||||
cmStateSnapshot::WarnCMP0220 RaiseToRoot(std::string const& var,
|
||||
char const* varDef);
|
||||
|
||||
// push and pop loop scopes
|
||||
void PushLoopBlockBarrier();
|
||||
|
||||
@@ -658,7 +658,11 @@ class cmMakefile;
|
||||
4, 4, 0, WARN) \
|
||||
SELECT(POLICY, CMP0219, \
|
||||
"Macro invocations preserve backslashes in arguments.", 4, 4, 0, \
|
||||
WARN)
|
||||
WARN) \
|
||||
SELECT(POLICY, CMP0220, \
|
||||
"Languages enabled in subdirectories propagate to the top-level " \
|
||||
"directory.", \
|
||||
4, 5, 0, WARN)
|
||||
|
||||
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
|
||||
#define CM_FOR_EACH_POLICY_ID(POLICY) \
|
||||
|
||||
@@ -225,6 +225,43 @@ cmPolicies::PolicyStatus cmStateSnapshot::GetPolicy(cmPolicies::PolicyID id,
|
||||
return status;
|
||||
}
|
||||
|
||||
cmPolicies::PolicyStatus cmStateSnapshot::GetScopePolicy(
|
||||
cmPolicies::PolicyID id) const
|
||||
{
|
||||
if (cmPolicies::IsRemoved(id)) {
|
||||
return cmPolicies::NEW;
|
||||
}
|
||||
|
||||
cmPolicies::PolicyStatus status = cmPolicies::WARN;
|
||||
|
||||
cmLinkedTree<cmStateDetail::BuildsystemDirectoryStateType>::iterator dir =
|
||||
this->Position->BuildSystemDirectory;
|
||||
|
||||
// Logic mirrors GetPolicy(), except that the search starts at this
|
||||
// snapshot's exact scope rather than the directory's current top scope.
|
||||
cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator leaf =
|
||||
this->Position->Policies;
|
||||
cmLinkedTree<cmStateDetail::PolicyStackEntry>::iterator root =
|
||||
this->Position->PolicyRoot;
|
||||
while (true) {
|
||||
assert(dir.IsValid());
|
||||
for (; leaf != root; ++leaf) {
|
||||
if (leaf->IsDefined(id)) {
|
||||
return leaf->Get(id);
|
||||
}
|
||||
}
|
||||
cmStateDetail::PositionType e = dir->CurrentScope;
|
||||
cmStateDetail::PositionType p = e->DirectoryParent;
|
||||
if (p == this->State->SnapshotData.Root()) {
|
||||
break;
|
||||
}
|
||||
dir = p->BuildSystemDirectory;
|
||||
leaf = dir->CurrentScope->Policies;
|
||||
root = dir->CurrentScope->PolicyRoot;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void cmStateSnapshot::PushDiagnostic(cmDiagnostics::DiagnosticMap entry,
|
||||
bool weak)
|
||||
{
|
||||
@@ -377,6 +414,27 @@ std::vector<std::string> cmStateSnapshot::ClosureKeys() const
|
||||
this->Position->Root);
|
||||
}
|
||||
|
||||
std::vector<std::string> cmStateSnapshot::LocalKeys() const
|
||||
{
|
||||
std::vector<std::string> keys = cmDefinitions::ClosureKeys(
|
||||
this->Position->Vars, this->Position->ScopeParent->Vars);
|
||||
|
||||
// Remove keys that are the same in the parent scope to avoid propagating
|
||||
// logic meant to restore variables back to their original value.
|
||||
keys.erase(std::remove_if(
|
||||
keys.begin(), keys.end(),
|
||||
[this](std::string const& key) {
|
||||
return cmDefinitions::Get(key, this->Position->Vars,
|
||||
this->Position->Root) ==
|
||||
cmDefinitions::Get(key, this->Position->ScopeParent->Vars,
|
||||
this->Position->ScopeParent->Root);
|
||||
}),
|
||||
keys.end());
|
||||
std::sort(keys.begin(), keys.end());
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
bool cmStateSnapshot::RaiseScope(std::string const& var, char const* varDef)
|
||||
{
|
||||
if (this->Position->ScopeParent == this->Position->DirectoryParent) {
|
||||
@@ -406,6 +464,40 @@ bool cmStateSnapshot::RaiseScope(std::string const& var, char const* varDef)
|
||||
return true;
|
||||
}
|
||||
|
||||
cmStateSnapshot::WarnCMP0220 cmStateSnapshot::RaiseToRoot(
|
||||
std::string const& var, char const* varDef, CheckCMP0220 checkCMP0220)
|
||||
{
|
||||
// If we are at the top of a directory, propagate to the parent directory (if
|
||||
// any).
|
||||
cmStateSnapshot parentScope =
|
||||
this->Position->ScopeParent == this->Position->DirectoryParent
|
||||
? this->GetBuildsystemDirectoryParent()
|
||||
: cmStateSnapshot(this->State, this->Position->ScopeParent);
|
||||
|
||||
if (!parentScope.IsValid()) {
|
||||
return WarnCMP0220::No;
|
||||
}
|
||||
|
||||
// First raise always occurs to propagate out of capturing variable scope.
|
||||
if (checkCMP0220 == CheckCMP0220::Yes) {
|
||||
switch (parentScope.GetScopePolicy(cmPolicies::CMP0220)) {
|
||||
case cmPolicies::NEW:
|
||||
break;
|
||||
case cmPolicies::OLD:
|
||||
return WarnCMP0220::No;
|
||||
case cmPolicies::WARN:
|
||||
return WarnCMP0220::Yes;
|
||||
}
|
||||
}
|
||||
|
||||
if (varDef) {
|
||||
parentScope.SetDefinition(var, varDef);
|
||||
} else {
|
||||
parentScope.RemoveDefinition(var);
|
||||
}
|
||||
return parentScope.RaiseToRoot(var, varDef, CheckCMP0220::Yes);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void InitializeContentFromParent(T& parentContent, T& thisContent,
|
||||
U& contentEndPosition)
|
||||
|
||||
@@ -30,8 +30,22 @@ public:
|
||||
void SetDefinition(std::string const& name, cm::string_view value);
|
||||
void RemoveDefinition(std::string const& name);
|
||||
std::vector<std::string> ClosureKeys() const;
|
||||
std::vector<std::string> LocalKeys() const;
|
||||
bool RaiseScope(std::string const& var, char const* varDef);
|
||||
|
||||
enum class CheckCMP0220
|
||||
{
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
enum class WarnCMP0220
|
||||
{
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
WarnCMP0220 RaiseToRoot(std::string const& var, char const* varDef,
|
||||
CheckCMP0220 checkCMP0220);
|
||||
|
||||
void SetListFile(std::string const& listfile);
|
||||
|
||||
std::string const& GetExecutionListFile() const;
|
||||
@@ -54,6 +68,7 @@ public:
|
||||
void SetPolicy(cmPolicies::PolicyID id, cmPolicies::PolicyStatus status);
|
||||
cmPolicies::PolicyStatus GetPolicy(cmPolicies::PolicyID id,
|
||||
bool parent_scope = false) const;
|
||||
cmPolicies::PolicyStatus GetScopePolicy(cmPolicies::PolicyID id) const;
|
||||
void PushPolicy(cmPolicies::PolicyMap const& entry, bool weak);
|
||||
bool PopPolicy();
|
||||
bool CanPopPolicyScope() const;
|
||||
|
||||
@@ -619,6 +619,13 @@ add_RunCMake_test(LanguageStandards
|
||||
)
|
||||
set_property(TEST RunCMake.LanguageStandards APPEND PROPERTY LABELS "CUDA" "HIP")
|
||||
|
||||
add_RunCMake_test(EnableLanguageSubdir
|
||||
-DCMake_TEST_CUDA=${CMake_TEST_CUDA}
|
||||
-DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES})
|
||||
if(CMake_TEST_CUDA)
|
||||
set_property(TEST RunCMake.EnableLanguageSubdir APPEND PROPERTY LABELS "CUDA")
|
||||
endif()
|
||||
|
||||
add_RunCMake_test(LinkItemValidation)
|
||||
add_RunCMake_test(LinkStatic)
|
||||
add_RunCMake_test(ARCHIVER-prefix -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID})
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
# enable_language() policy check should respect the policy inside of block()
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
block()
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
add_subdirectory(cxx)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was incorrectly propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
endblock()
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
# Policy is checked at every scope level for CXX and its implicit RC language.
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
block()
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
block()
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
add_subdirectory(cxx)
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was not propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
if(NOT CMAKE_RC_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): implicit RC language configuration was not propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
endblock()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was incorrectly propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
if(CMAKE_RC_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): implicit RC language configuration was incorrectly propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
endblock()
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
# Policy is checked at every scope level inside a subdirectory
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
block()
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
block()
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
add_subdirectory(cxx)
|
||||
if(NOT CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was not propagated up a subdirectory with CMP0220 NEW inside a block()")
|
||||
endif()
|
||||
endblock()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was incorrectly propagated up a subdirectory with CMP0220 OLD inside a block()")
|
||||
endif()
|
||||
endblock()
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
# enable_language() propagates through a function call
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
function(enable_cxx)
|
||||
enable_language(CXX)
|
||||
endfunction()
|
||||
|
||||
enable_cxx()
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was not propagated up a subdirectory with CMP0220 NEW inside a function()")
|
||||
endif()
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
# Ensure propagation through many subdirectories each with multiple scopes
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
add_subdirectory(outer)
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was not propagated up across "
|
||||
"multiple levels of directories.")
|
||||
endif()
|
||||
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-NEW.cmake
Normal file
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-NEW.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
# With CMP0220 NEW, a language enabled in a subdirectory is propagated up to this scope
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
add_subdirectory(cxx)
|
||||
|
||||
if(NOT CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was not propagated up a subdirectory with CMP0220 NEW")
|
||||
endif()
|
||||
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-OLD.cmake
Normal file
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-OLD.cmake
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
# With CMP0220 OLD, a language enabled in a subdirectory is not propagated
|
||||
cmake_policy(SET CMP0220 OLD)
|
||||
|
||||
add_subdirectory(cxx)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was propagated up a subdirectory with CMP0220 OLD")
|
||||
endif()
|
||||
@@ -0,0 +1,12 @@
|
||||
CMake Warning \(policy\) at CMP0220-WARN-block\.cmake:[0-9]+ \(enable_language\):
|
||||
Policy CMP0220 is not set: Languages enabled in subdirectories propagate to
|
||||
the top-level directory\. Run "cmake --help-policy CMP0220" for policy
|
||||
details\. Use the cmake_policy command to set the policy and suppress this
|
||||
warning\.
|
||||
|
||||
For compatibility with older versions of CMake, the language configuration
|
||||
set by this call is not propagated to the enclosing variable scopes\.
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)
|
||||
This warning is for project developers\. Use -Wno-author or -Wno-policy to
|
||||
suppress it\.
|
||||
12
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN-block.cmake
Normal file
12
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN-block.cmake
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
# A block() creates a variable scope, so enable_language() could be propagated with NEW behavior
|
||||
set(CMAKE_POLICY_WARNING_CMP0220 ON)
|
||||
|
||||
block()
|
||||
enable_language(CXX)
|
||||
endblock()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_LOADED)
|
||||
message(FATAL_ERROR
|
||||
"enable_language(): language configuration was propagated out of a block() scope with CMP0220 WARN")
|
||||
endif()
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
# Without the optional warning variable set, no warning is issued
|
||||
add_subdirectory(cxx)
|
||||
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN-stderr.txt
Normal file
10
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN-stderr.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
CMake Warning \(policy\) at cxx/CMakeLists\.txt:[0-9]+ \(enable_language\):
|
||||
Policy CMP0220 is not set: Languages enabled in subdirectories propagate to
|
||||
the top-level directory\. Run "cmake --help-policy CMP0220" for policy
|
||||
details\. Use the cmake_policy command to set the policy and suppress this
|
||||
warning\.
|
||||
|
||||
For compatibility with older versions of CMake, the language configuration
|
||||
set by this call is not propagated to the enclosing variable scopes\.
|
||||
This warning is for project developers\. Use -Wno-author or -Wno-policy to
|
||||
suppress it\.
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
# A top-level enable_language() has no ancestor scope to propagate into, so it
|
||||
# never warns for CMP0220 even when the optional warning is enabled.
|
||||
set(CMAKE_POLICY_WARNING_CMP0220 ON)
|
||||
|
||||
enable_language(CXX)
|
||||
5
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN.cmake
Normal file
5
Tests/RunCMake/EnableLanguageSubdir/CMP0220-WARN.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
# With the optional warning variable set, a warning is issued
|
||||
set(CMAKE_POLICY_WARNING_CMP0220 ON)
|
||||
|
||||
add_subdirectory(cxx)
|
||||
3
Tests/RunCMake/EnableLanguageSubdir/CMakeLists.txt
Normal file
3
Tests/RunCMake/EnableLanguageSubdir/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 4.4)
|
||||
project(${RunCMake_TEST} NONE)
|
||||
include(${RunCMake_TEST}.cmake)
|
||||
14
Tests/RunCMake/EnableLanguageSubdir/CUDAParent.cmake
Normal file
14
Tests/RunCMake/EnableLanguageSubdir/CUDAParent.cmake
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
# With CMP0220 NEW, CUDA enabled in a subdirectory propagates up to this scope.
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
enable_language(CXX)
|
||||
|
||||
add_subdirectory(cuda)
|
||||
|
||||
add_executable(main cuda-main.cxx)
|
||||
target_link_libraries(main PRIVATE cuda_lib)
|
||||
|
||||
if(APPLE)
|
||||
set_property(TARGET main PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
|
||||
endif()
|
||||
9
Tests/RunCMake/EnableLanguageSubdir/CUDASibling.cmake
Normal file
9
Tests/RunCMake/EnableLanguageSubdir/CUDASibling.cmake
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
# With CMP0220 NEW, CUDA enabled in a subdirectory propagates up to this scope.
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
enable_language(CXX)
|
||||
|
||||
add_subdirectory(cuda)
|
||||
|
||||
add_subdirectory(sibling)
|
||||
7
Tests/RunCMake/EnableLanguageSubdir/CXXImplicitRC.cmake
Normal file
7
Tests/RunCMake/EnableLanguageSubdir/CXXImplicitRC.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
# With CMP0220 NEW, CXX and its implicit RC language propagate up to this scope.
|
||||
cmake_policy(SET CMP0220 NEW)
|
||||
|
||||
add_subdirectory(cxx)
|
||||
|
||||
add_executable(main rc-main.cxx resource.rc)
|
||||
48
Tests/RunCMake/EnableLanguageSubdir/RunCMakeTest.cmake
Normal file
48
Tests/RunCMake/EnableLanguageSubdir/RunCMakeTest.cmake
Normal file
@@ -0,0 +1,48 @@
|
||||
include(RunCMake)
|
||||
|
||||
function(configure_and_build case)
|
||||
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
|
||||
run_cmake(${case})
|
||||
set(RunCMake_TEST_NO_CLEAN 1)
|
||||
set(RunCMake_TEST_OUTPUT_MERGE 1)
|
||||
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --target main)
|
||||
unset(RunCMake_TEST_NO_CLEAN)
|
||||
unset(RunCMake_TEST_OUTPUT_MERGE)
|
||||
unset(RunCMake_TEST_BINARY_DIR)
|
||||
endfunction()
|
||||
|
||||
# CMP0220 policy behavior. These cases are language-agnostic (they use CXX)
|
||||
# and configure-only, so they run on every platform regardless of CMake_TEST_CUDA.
|
||||
|
||||
# NEW: language configuration propagates up out of the enabling scope.
|
||||
run_cmake(CMP0220-NEW)
|
||||
run_cmake(CMP0220-NEW-function)
|
||||
run_cmake(CMP0220-NEW-multilevel)
|
||||
|
||||
# OLD: language configuration stays in the scope that enabled it.
|
||||
run_cmake(CMP0220-OLD)
|
||||
|
||||
# MIXED: NEW and OLD set at different scope levels around the enabling scope.
|
||||
run_cmake(CMP0220-MIXED-block)
|
||||
run_cmake(CMP0220-MIXED-nested-block)
|
||||
|
||||
# WARN: whether the optional CMP0220 warning is emitted.
|
||||
run_cmake(CMP0220-WARN)
|
||||
run_cmake(CMP0220-WARN-default)
|
||||
run_cmake(CMP0220-WARN-block)
|
||||
run_cmake(CMP0220-WARN-top-level)
|
||||
|
||||
# These cases enable CXX in a subdirectory and verify that its implicit RC
|
||||
# language state is usable from an ancestor scope.
|
||||
if(CMake_TEST_RESOURCES)
|
||||
configure_and_build(CXXImplicitRC)
|
||||
run_cmake(CMP0220-MIXED-implicit-RC)
|
||||
endif()
|
||||
|
||||
# The following cases enable CUDA in a subdirectory and build a target in an
|
||||
# ancestor scope, so they require a working CUDA toolchain.
|
||||
if(CMake_TEST_CUDA)
|
||||
foreach(case IN ITEMS CUDAParent CUDASibling)
|
||||
configure_and_build(${case})
|
||||
endforeach()
|
||||
endif()
|
||||
7
Tests/RunCMake/EnableLanguageSubdir/cuda-main.cxx
Normal file
7
Tests/RunCMake/EnableLanguageSubdir/cuda-main.cxx
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "src.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
hello_world();
|
||||
return 0;
|
||||
}
|
||||
4
Tests/RunCMake/EnableLanguageSubdir/cuda/CMakeLists.txt
Normal file
4
Tests/RunCMake/EnableLanguageSubdir/cuda/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
enable_language(CUDA)
|
||||
|
||||
add_library(cuda_lib STATIC src.cu)
|
||||
target_include_directories(cuda_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
14
Tests/RunCMake/EnableLanguageSubdir/cuda/src.cu
Normal file
14
Tests/RunCMake/EnableLanguageSubdir/cuda/src.cu
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <cstdio>
|
||||
|
||||
#include "src.h"
|
||||
|
||||
__global__ void hello_world_kernel()
|
||||
{
|
||||
printf("Hello from GPU thread %d\n", threadIdx.x);
|
||||
}
|
||||
|
||||
void hello_world()
|
||||
{
|
||||
hello_world_kernel<<<1, 1>>>();
|
||||
cudaDeviceSynchronize();
|
||||
}
|
||||
2
Tests/RunCMake/EnableLanguageSubdir/cuda/src.h
Normal file
2
Tests/RunCMake/EnableLanguageSubdir/cuda/src.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
void hello_world();
|
||||
1
Tests/RunCMake/EnableLanguageSubdir/cxx/CMakeLists.txt
Normal file
1
Tests/RunCMake/EnableLanguageSubdir/cxx/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
enable_language(CXX)
|
||||
5
Tests/RunCMake/EnableLanguageSubdir/outer/CMakeLists.txt
Normal file
5
Tests/RunCMake/EnableLanguageSubdir/outer/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
block()
|
||||
block()
|
||||
add_subdirectory(inner)
|
||||
endblock()
|
||||
endblock()
|
||||
@@ -0,0 +1,3 @@
|
||||
block()
|
||||
enable_language(CXX)
|
||||
endblock()
|
||||
4
Tests/RunCMake/EnableLanguageSubdir/rc-main.cxx
Normal file
4
Tests/RunCMake/EnableLanguageSubdir/rc-main.cxx
Normal file
@@ -0,0 +1,4 @@
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
4
Tests/RunCMake/EnableLanguageSubdir/resource.rc
Normal file
4
Tests/RunCMake/EnableLanguageSubdir/resource.rc
Normal file
@@ -0,0 +1,4 @@
|
||||
1 RCDATA
|
||||
BEGIN
|
||||
"EnableLanguageSubdir"
|
||||
END
|
||||
@@ -0,0 +1,6 @@
|
||||
add_executable(main main.cxx)
|
||||
target_link_libraries(main PRIVATE cuda_lib)
|
||||
|
||||
if(APPLE)
|
||||
set_property(TARGET main PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})
|
||||
endif()
|
||||
7
Tests/RunCMake/EnableLanguageSubdir/sibling/main.cxx
Normal file
7
Tests/RunCMake/EnableLanguageSubdir/sibling/main.cxx
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "src.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
hello_world();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user