summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/command/macro.rst6
-rw-r--r--Help/manual/cmake-variables.7.rst4
-rw-r--r--Help/release/dev/CMAKE_CURRENT_FUNCTION.rst9
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION.rst6
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst33
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst5
-rw-r--r--Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst5
-rw-r--r--Source/cmFunctionCommand.cxx21
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt7
-rw-r--r--Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake94
-rw-r--r--Tests/RunCMake/function/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/function/DummyMacro.cmake20
-rw-r--r--Tests/RunCMake/function/RunCMakeTest.cmake3
14 files changed, 217 insertions, 0 deletions
diff --git a/Help/command/macro.rst b/Help/command/macro.rst
index 05e5d79..3f6f2f9 100644
--- a/Help/command/macro.rst
+++ b/Help/command/macro.rst
@@ -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
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 84018b7..4c797a5 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -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
diff --git a/Help/release/dev/CMAKE_CURRENT_FUNCTION.rst b/Help/release/dev/CMAKE_CURRENT_FUNCTION.rst
new file mode 100644
index 0000000..a15e63d
--- /dev/null
+++ b/Help/release/dev/CMAKE_CURRENT_FUNCTION.rst
@@ -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`
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION.rst b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
new file mode 100644
index 0000000..aa2936c
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION.rst
@@ -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.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
new file mode 100644
index 0000000..0119381
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_DIR.rst
@@ -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()
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
new file mode 100644
index 0000000..d2c846a
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_FILE.rst
@@ -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.
diff --git a/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
new file mode 100644
index 0000000..5a7cd13
--- /dev/null
+++ b/Help/variable/CMAKE_CURRENT_FUNCTION_LIST_LINE.rst
@@ -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.
diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx
index bd96115..4b2f145 100644
--- a/Source/cmFunctionCommand.cxx
+++ b/Source/cmFunctionCommand.cxx
@@ -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;
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 31b280b..18ac6f9 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -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)
diff --git a/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt
new file mode 100644
index 0000000..5ebc89a
--- /dev/null
+++ b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION-stdout.txt
@@ -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\(\)
diff --git a/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake
new file mode 100644
index 0000000..38c032f
--- /dev/null
+++ b/Tests/RunCMake/function/CMAKE_CURRENT_FUNCTION.cmake
@@ -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()
diff --git a/Tests/RunCMake/function/CMakeLists.txt b/Tests/RunCMake/function/CMakeLists.txt
new file mode 100644
index 0000000..2632ffa
--- /dev/null
+++ b/Tests/RunCMake/function/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.16)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/function/DummyMacro.cmake b/Tests/RunCMake/function/DummyMacro.cmake
new file mode 100644
index 0000000..1ab53e4
--- /dev/null
+++ b/Tests/RunCMake/function/DummyMacro.cmake
@@ -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()
diff --git a/Tests/RunCMake/function/RunCMakeTest.cmake b/Tests/RunCMake/function/RunCMakeTest.cmake
new file mode 100644
index 0000000..88f48af
--- /dev/null
+++ b/Tests/RunCMake/function/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake(CMAKE_CURRENT_FUNCTION)