cmFunctionCommand: Introduce CMAKE_CURRENT_FUNCTION* variables

`CMAKE_CURRENT_FUNCTION`
  Can be used for diagnostic or debugging messages like the
  `__PRETTY_FUNCTION__` macro of GCC.

`CMAKE_CURRENT_FUNCTION_LIST_DIR`
  Eliminates the necessity of the additional "global"
  variables inside a module used to access additional "resource"
  files from functions defined in the module.

...
This commit is contained in:
Alex Turbov
2019-12-08 02:26:14 +02:00
parent dd54290dab
commit 90e3e2a777
14 changed files with 217 additions and 0 deletions

View File

@@ -91,6 +91,12 @@ just terminate execution of the macro; rather, control is returned
from the scope of the macro call. To avoid confusion, it is recommended
to avoid :command:`return()` in macros altogether.
Unlike a function, the :variable:`CMAKE_CURRENT_FUNCTION`,
:variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`,
:variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`,
:variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE` variables are not
set for macro.
.. _`Argument Caveats`:
Argument Caveats

View File

@@ -37,6 +37,10 @@ Variables that Provide Information
/variable/CMAKE_CROSSCOMPILING_EMULATOR
/variable/CMAKE_CTEST_COMMAND
/variable/CMAKE_CURRENT_BINARY_DIR
/variable/CMAKE_CURRENT_FUNCTION
/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR
/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE
/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE
/variable/CMAKE_CURRENT_LIST_DIR
/variable/CMAKE_CURRENT_LIST_FILE
/variable/CMAKE_CURRENT_LIST_LINE

View File

@@ -0,0 +1,9 @@
CMAKE_CURRENT_FUNCTION
----------------------
* Define the following variables inside a function:
- :variable:`CMAKE_CURRENT_FUNCTION`
- :variable:`CMAKE_CURRENT_FUNCTION_LIST_DIR`
- :variable:`CMAKE_CURRENT_FUNCTION_LIST_FILE`
- :variable:`CMAKE_CURRENT_FUNCTION_LIST_LINE`

View File

@@ -0,0 +1,6 @@
CMAKE_CURRENT_FUNCTION
----------------------
When executing code inside a :command:`function`, this variable
contains the name of the current function. It can be used for
diagnostic or debug messages.

View File

@@ -0,0 +1,33 @@
CMAKE_CURRENT_FUNCTION_LIST_DIR
-------------------------------
When executing code inside a :command:`function`, this variable
contains the full directory of the listfile defining the current function.
It is quite common practice in CMake that modules use some additional files
(e.g., templates to render). And the code typically did the following:
.. code-block:: cmake
:caption: Bad
set(_THIS_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
function(foo)
configure_file(
"${_THIS_MODULE_BASE_DIR}/some.template.in"
some.output
)
endfunction()
Using this variable inside a function eliminates the neccessity of the
additional one with "global" scope:
.. code-block:: cmake
:caption: Good
function(foo)
configure_file(
"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/some.template.in"
some.output
)
endfunction()

View File

@@ -0,0 +1,5 @@
CMAKE_CURRENT_FUNCTION_LIST_FILE
--------------------------------
When executing code inside a :command:`function`, this variable
contains the full path to the listfile declaring a current function.

View File

@@ -0,0 +1,5 @@
CMAKE_CURRENT_FUNCTION_LIST_LINE
--------------------------------
When executing code inside a :command:`function`, this variable
contains the line number in the listfile where a current function has defined.

View File

@@ -18,11 +18,19 @@
#include "cmRange.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
namespace {
std::string const ARGC = "ARGC";
std::string const ARGN = "ARGN";
std::string const ARGV = "ARGV";
std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION";
std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE =
"CMAKE_CURRENT_FUNCTION_LIST_FILE";
std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR =
"CMAKE_CURRENT_FUNCTION_LIST_DIR";
std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE =
"CMAKE_CURRENT_FUNCTION_LIST_LINE";
// define the class for function commands
class cmFunctionHelperCommand
@@ -39,6 +47,7 @@ public:
std::vector<cmListFileFunction> Functions;
cmPolicies::PolicyMap Policies;
std::string FilePath;
long Line;
};
bool cmFunctionHelperCommand::operator()(
@@ -89,6 +98,17 @@ bool cmFunctionHelperCommand::operator()(
makefile.AddDefinition(ARGN, argnDef);
makefile.MarkVariableAsUsed(ARGN);
makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front());
makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION);
makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath);
makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE);
makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR,
cmSystemTools::GetFilenamePath(this->FilePath));
makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR);
makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE,
std::to_string(this->Line));
makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE);
// Invoke all the functions that were collected in the block.
// for each function
for (cmListFileFunction const& func : this->Functions) {
@@ -143,6 +163,7 @@ bool cmFunctionFunctionBlocker::Replay(
f.Args = this->Args;
f.Functions = std::move(functions);
f.FilePath = this->GetStartingContext().FilePath;
f.Line = this->GetStartingContext().Line;
mf.RecordPolicies(f.Policies);
mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f));
return true;

View File

@@ -272,6 +272,7 @@ add_RunCMake_test(find_package)
add_RunCMake_test(find_path)
add_RunCMake_test(find_program -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})
add_RunCMake_test(foreach)
add_RunCMake_test(function)
add_RunCMake_test(get_filename_component)
add_RunCMake_test(get_property)
add_RunCMake_test(if)

View File

@@ -0,0 +1,7 @@
function\(print_self\)
file\(STRINGS "\${CMAKE_CURRENT_FUNCTION_LIST_FILE}" _lines\)
math\(EXPR _begin "\${CMAKE_CURRENT_FUNCTION_LIST_LINE} - 1"\)
list\(SUBLIST _lines \${_begin} 7 _lines\) # This function has 7 lines only
list\(JOIN _lines "\\n" _lines\)
message\(STATUS "Print the `\${CMAKE_CURRENT_FUNCTION}` function:\\n\${_lines}"\)
endfunction\(\)

View File

@@ -0,0 +1,94 @@
set(_THIS_FILE "${CMAKE_CURRENT_LIST_FILE}")
set(_THIS_DIR "${CMAKE_CURRENT_LIST_DIR}")
if(CMAKE_CURRENT_FUNCTION)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_FILE)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_FILE` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_DIR)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_DIR` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_LINE)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_LINE` is not expected to be set here")
endif()
function(bar)
if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "bar")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/CMAKE_CURRENT_FUNCTION.cmake$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 17)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
endif()
endfunction()
function(foo)
if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "foo")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/function/CMAKE_CURRENT_FUNCTION.cmake$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 38)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
bar()
endfunction()
foo()
if(CMAKE_CURRENT_FUNCTION)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_FILE)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_FILE` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_DIR)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_DIR` is not expected to be set here")
endif()
if(CMAKE_CURRENT_FUNCTION_LIST_LINE)
message(SEND_ERROR "`CMAKE_CURRENT_FUNCTION_LIST_LINE` is not expected to be set here")
endif()
include("${CMAKE_CURRENT_LIST_DIR}/DummyMacro.cmake")
function(calling_macro)
dummy()
endfunction()
calling_macro()
cmake_policy(SET CMP0007 NEW)
# ATTENTION `CMAKE_CURRENT_LIST_LINE` can't be used in `math()'
function(print_self)
file(STRINGS "${CMAKE_CURRENT_FUNCTION_LIST_FILE}" _lines)
math(EXPR _begin "${CMAKE_CURRENT_FUNCTION_LIST_LINE} - 1")
list(SUBLIST _lines ${_begin} 7 _lines) # This function has 7 lines only
list(JOIN _lines "\n" _lines)
message(STATUS "Print the `${CMAKE_CURRENT_FUNCTION}` function:\n${_lines}")
endfunction()
print_self()

View File

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

View File

@@ -0,0 +1,20 @@
macro(dummy)
if(NOT CMAKE_CURRENT_FUNCTION STREQUAL "calling_macro")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE MATCHES "^.*/function/CMAKE_CURRENT_FUNCTION.cmake$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_FILE STREQUAL _THIS_FILE)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_FILE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR MATCHES "^.*/Tests/RunCMake/function$")
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_LINE EQUAL 77)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_LINE`")
endif()
if(NOT CMAKE_CURRENT_FUNCTION_LIST_DIR STREQUAL _THIS_DIR)
message(SEND_ERROR "Bad value of `CMAKE_CURRENT_FUNCTION_LIST_DIR`")
endif()
endmacro()

View File

@@ -0,0 +1,3 @@
include(RunCMake)
run_cmake(CMAKE_CURRENT_FUNCTION)