enable_language: add support for usage in subdirectories

Propagates variables set in enable_language() logic up variable scopes
so that the language can be used by targets in the ancestor directories.
Works through block() and function() scopes as well. The
add_subdirectory() call can be thought of as the effective call site for
enabling the language. The same holds for endblock() and the actual
function call.

Adds a policy CMP0220 to control this behavior. As the language is
"enabled" at each ancestor scope, the policy is checked. If OLD, the
language is not enabled at this scope and the ones above.

Closes: #27881 #27508 #27389
Related: #26751 #27564
This commit is contained in:
Arha Gatram
2026-08-07 11:05:57 -04:00
committed by Brad King
parent 220fc8622d
commit 86759dce81
41 changed files with 560 additions and 7 deletions
+7 -6
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`
+8
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
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
@@ -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
+37
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,
+19
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)
+2
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();
+5 -1
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) \
+92
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)
+15
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;
+7
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})
@@ -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()
@@ -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()
@@ -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\.
@@ -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)
@@ -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)
@@ -0,0 +1,5 @@
# With the optional warning variable set, a warning is issued
set(CMAKE_POLICY_WARNING_CMP0220 ON)
add_subdirectory(cxx)
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 4.4)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
@@ -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()
@@ -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)
@@ -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)
@@ -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()
@@ -0,0 +1,7 @@
#include "src.h"
int main()
{
hello_world();
return 0;
}
@@ -0,0 +1,4 @@
enable_language(CUDA)
add_library(cuda_lib STATIC src.cu)
target_include_directories(cuda_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
@@ -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();
}
@@ -0,0 +1,2 @@
#pragma once
void hello_world();
@@ -0,0 +1 @@
enable_language(CXX)
@@ -0,0 +1,5 @@
block()
block()
add_subdirectory(inner)
endblock()
endblock()
@@ -0,0 +1,3 @@
block()
enable_language(CXX)
endblock()
@@ -0,0 +1,4 @@
int main()
{
return 0;
}
@@ -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()
@@ -0,0 +1,7 @@
#include "src.h"
int main()
{
hello_world();
return 0;
}