Reputation: 736
I have created a project with a subproject in cmake. In the subproject I have a function which wants to access a variable from its defining scope (not the parent project scope).
This is my folder structure:
/project
|-- CMakeLists.txt
'-- /sub
'-- CMakeLists.txt
Outer CMakeLists.txt:
project(mainproject)
cmake_minimum_required(VERSION 3.17)
add_subdirectory(sub)
message("in parent scope: ${V}")
test()
Inner CMakeLists.txt:
project(subproject)
cmake_minimum_required(VERSION 3.17)
set(V "hello")
message("defining scope: ${V}")
function(test)
message("function scope: ${V}")
endfunction()
The output I get:
defining scope: hello
parent scope:
function scope:
-- Configuring done
-- Generating done
My suspicion would be that cmake simply doesn't support closures but then there is this page in the documentation: CMAKE_CURRENT_FUNCTION_LIST_DIR
set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(foo)
configure_file(
"${_THIS_MODULE_BASE_DIR}/some.template.in"
some.output
)
endfunction()
This is almost exactly my use case and exactly what I do but it doesn't work.
What am I missing here?
Note that I could use set(V "hello" PARENT_SCOPE)
but I don't want to pollute the parent scope.
Any help appreciated!
Upvotes: 0
Views: 1418
Reputation: 65870
There is no "closure" semantic in CMake. Any variable's dereference uses the variable from the current scope. That is, if you call test
function from the top-level CMakeLists.txt
, the variable V
is searched in the scope of that script, not from the scope of sub/CMakeLists.txt
which defines given function.
Only special variables like CMAKE_CURRENT_FUNCTION_LIST_DIR or CMAKE_CURRENT_FUNCTION are exception from that rule: they are expanded according to the place (file, line, function) where they are dereferenced.
The example of the code which confuses you
set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(foo)
configure_file(
"${_THIS_MODULE_BASE_DIR}/some.template.in"
some.output
)
endfunction()
is for CMake module like foo.cmake
.
Modules are included with include
command:
include(foo)
...
foo()
which, unlike to add_subdirectory
, does NOT introduce the scope (more info about variable's scoping is here).
So variable _THIS_MODULE_BASE_DIR
is visible to the caller of the function foo
. (Would another module use the same variable name, then one variable would silently redefine another).
For make your code to work, you need to make V
variable visible to the caller of your function. E.g you could set the variable with PARENT or CACHE option, or use global property instead of the variable.
Alternatively, you could move definition of the test
function from sub/CMakeLists.txt
to the module test.cmake
, and include that module in the top-level CMakeLists.txt
via include
.
Upvotes: 2