Merge topic 'enable-language-subdirectory'

86759dce81 enable_language: add support for usage in subdirectories
220fc8622d block: Fix incorrect policy scope creation order

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !12222
This commit is contained in:
Brad King
2026-08-08 14:45:11 +00:00
committed by Kitware Robot
42 changed files with 564 additions and 11 deletions

View File

@@ -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`

View File

@@ -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
View 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

View 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`.

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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();

View File

@@ -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) \

View File

@@ -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)

View File

@@ -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;

View File

@@ -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})

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View 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()

View 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()

View File

@@ -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\.

View 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()

View File

@@ -0,0 +1,3 @@
# Without the optional warning variable set, no warning is issued
add_subdirectory(cxx)

View 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\.

View File

@@ -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)

View File

@@ -0,0 +1,5 @@
# With the optional warning variable set, a warning is issued
set(CMAKE_POLICY_WARNING_CMP0220 ON)
add_subdirectory(cxx)

View File

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

View 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()

View 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)

View 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)

View 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()

View File

@@ -0,0 +1,7 @@
#include "src.h"
int main()
{
hello_world();
return 0;
}

View 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})

View 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();
}

View File

@@ -0,0 +1,2 @@
#pragma once
void hello_world();

View File

@@ -0,0 +1 @@
enable_language(CXX)

View File

@@ -0,0 +1,5 @@
block()
block()
add_subdirectory(inner)
endblock()
endblock()

View File

@@ -0,0 +1,3 @@
block()
enable_language(CXX)
endblock()

View File

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

View File

@@ -0,0 +1,4 @@
1 RCDATA
BEGIN
"EnableLanguageSubdir"
END

View File

@@ -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()

View File

@@ -0,0 +1,7 @@
#include "src.h"
int main()
{
hello_world();
return 0;
}