Merge topic 'function-var-current'

24fdd51f45 Refactor: Replace CMAKE_CURRENT_LIST_DIR with CMAKE_CURRENT_FUNCTION_LIST_DIR
90e3e2a777 cmFunctionCommand: Introduce `CMAKE_CURRENT_FUNCTION*` variables
dd54290dab Refactor: Modernize `function` command

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Ben Boeckel <ben.boeckel@kitware.com>
Merge-request: !4000
This commit is contained in:
Kyle Edwards 2019-12-12 19:00:30 +00:00 committed by Kitware Robot
commit 966a9eece3
19 changed files with 253 additions and 41 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

@ -76,8 +76,6 @@ Module Functions
include(${CMAKE_CURRENT_LIST_DIR}/ExternalData.cmake)
set(_AndroidTestUtilities_SELF_DIR "${CMAKE_CURRENT_LIST_DIR}")
# The parameters to this function should be set to the list of directories,
# files, and libraries that need to be installed prior to testing.
function(android_add_test_data test_name)
@ -159,6 +157,6 @@ function(android_add_test_data test_name)
"-Darg_files=${processed_FILES}"
"-Darg_libs=${AST_LIBS}"
"-Darg_src_dir=${CMAKE_CURRENT_SOURCE_DIR}"
-P ${_AndroidTestUtilities_SELF_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake)
-P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/AndroidTestUtilities/PushToAndroidDevice.cmake)
endif()
endfunction()

View File

@ -43,7 +43,6 @@ future version that supports installation of the external project
binaries during ``make install``.
#]=======================================================================]
set(_MS_MINGW_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
include(CheckLanguage)
include(ExternalProject)
@ -87,11 +86,11 @@ function(_setup_mingw_config_and_build source_dir build_dir)
file(TO_NATIVE_PATH "${MINGW_PATH}" MINGW_PATH)
string(REPLACE "\\" "\\\\" MINGW_PATH "${MINGW_PATH}")
configure_file(
${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/config_mingw.cmake.in
${build_dir}/config_mingw.cmake
@ONLY)
configure_file(
${_MS_MINGW_SOURCE_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/CMakeAddFortranSubdirectory/build_mingw.cmake.in
${build_dir}/build_mingw.cmake
@ONLY)
endfunction()

View File

@ -106,7 +106,6 @@ and plugin installation. See documentation of FIXUP_QT4_BUNDLE.
# The functions defined in this file depend on the fixup_bundle function
# (and others) found in BundleUtilities.cmake
set(DeployQt4_cmake_dir "${CMAKE_CURRENT_LIST_DIR}")
set(DeployQt4_apple_plugins_dir "PlugIns")
function(write_qt4_conf qt_conf_dir qt_conf_contents)
@ -392,7 +391,7 @@ function(install_qt4_executable executable)
resolve_qt4_paths(libs "")
install(CODE
"include(\"${DeployQt4_cmake_dir}/DeployQt4.cmake\")
"include(\"${CMAKE_CURRENT_FUNCTION_LIST_DIR}/DeployQt4.cmake\")
set(BU_CHMOD_BUNDLE_ITEMS TRUE)
FIXUP_QT4_EXECUTABLE(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${executable}\" \"\" \"${libs}\" \"${dirs}\" \"${plugins_dir}\" \"${request_qt_conf}\")"
${component}

View File

@ -596,9 +596,6 @@ current working directory.
#]=======================================================================]
set(__FetchContent_privateDir "${CMAKE_CURRENT_LIST_DIR}/FetchContent")
#=======================================================================
# Recording and retrieving content details for later population
#=======================================================================
@ -888,7 +885,7 @@ function(__FetchContent_directPopulate contentName)
# anything to be updated, so extra rebuilds of the project won't occur.
# Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project
# has this set to something not findable on the PATH.
configure_file("${__FetchContent_privateDir}/CMakeLists.cmake.in"
configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/FetchContent/CMakeLists.cmake.in"
"${ARG_SUBBUILD_DIR}/CMakeLists.txt")
execute_process(
COMMAND ${CMAKE_COMMAND} ${generatorOpts} .

View File

@ -405,7 +405,6 @@ endfunction()
# define helper scripts
set(_JAVA_EXPORT_TARGETS_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/javaTargets.cmake.in)
set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
if (CMAKE_HOST_WIN32 AND NOT CYGWIN AND CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
@ -627,7 +626,7 @@ function(add_jar _TARGET_NAME)
COMMAND ${CMAKE_COMMAND}
-DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
-DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
-P ${_JAVA_CLASS_FILELIST_SCRIPT}
-P ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/UseJavaClassFilelist.cmake
DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

View File

@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmFunctionCommand.h"
#include <sstream>
#include <utility>
#include <cm/memory>
@ -19,8 +18,20 @@
#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
{
@ -36,8 +47,8 @@ public:
std::vector<cmListFileFunction> Functions;
cmPolicies::PolicyMap Policies;
std::string FilePath;
long Line;
};
}
bool cmFunctionHelperCommand::operator()(
std::vector<cmListFileArgument> const& args,
@ -52,9 +63,9 @@ bool cmFunctionHelperCommand::operator()(
// make sure the number of arguments passed is at least the number
// required by the signature
if (expandedArgs.size() < this->Args.size() - 1) {
std::string errorMsg = cmStrCat(
auto const errorMsg = cmStrCat(
"Function invoked with incorrect arguments for function named: ",
this->Args[0]);
this->Args.front());
inStatus.SetError(errorMsg);
return false;
}
@ -63,30 +74,40 @@ bool cmFunctionHelperCommand::operator()(
this->Policies);
// set the value of argc
makefile.AddDefinition("ARGC", std::to_string(expandedArgs.size()));
makefile.MarkVariableAsUsed("ARGC");
makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size()));
makefile.MarkVariableAsUsed(ARGC);
// set the values for ARGV0 ARGV1 ...
for (unsigned int t = 0; t < expandedArgs.size(); ++t) {
std::ostringstream tmpStream;
tmpStream << "ARGV" << t;
makefile.AddDefinition(tmpStream.str(), expandedArgs[t]);
makefile.MarkVariableAsUsed(tmpStream.str());
for (auto t = 0u; t < expandedArgs.size(); ++t) {
auto const value = cmStrCat(ARGV, std::to_string(t));
makefile.AddDefinition(value, expandedArgs[t]);
makefile.MarkVariableAsUsed(value);
}
// define the formal arguments
for (unsigned int j = 1; j < this->Args.size(); ++j) {
for (auto j = 1u; j < this->Args.size(); ++j) {
makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]);
}
// define ARGV and ARGN
std::string argvDef = cmJoin(expandedArgs, ";");
auto eit = expandedArgs.begin() + (this->Args.size() - 1);
std::string argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
makefile.AddDefinition("ARGV", argvDef);
makefile.MarkVariableAsUsed("ARGV");
makefile.AddDefinition("ARGN", argnDef);
makefile.MarkVariableAsUsed("ARGN");
auto const argvDef = cmJoin(expandedArgs, ";");
auto const eit = expandedArgs.begin() + (this->Args.size() - 1);
auto const argnDef = cmJoin(cmMakeRange(eit, expandedArgs.end()), ";");
makefile.AddDefinition(ARGV, argvDef);
makefile.MarkVariableAsUsed(ARGV);
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
@ -100,7 +121,7 @@ bool cmFunctionHelperCommand::operator()(
return false;
}
if (status.GetReturnInvoked()) {
return true;
break;
}
}
@ -129,7 +150,8 @@ bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff,
std::vector<std::string> expandedArguments;
mf.ExpandArguments(lff.Arguments, expandedArguments,
this->GetStartingContext().FilePath.c_str());
return expandedArguments.empty() || expandedArguments[0] == this->Args[0];
return expandedArguments.empty() ||
expandedArguments.front() == this->Args.front();
}
bool cmFunctionFunctionBlocker::Replay(
@ -141,11 +163,14 @@ 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[0], std::move(f));
mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f));
return true;
}
} // anonymous namespace
bool cmFunctionCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
@ -155,10 +180,9 @@ bool cmFunctionCommand(std::vector<std::string> const& args,
}
// create a function blocker
{
auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
cmAppend(fb->Args, args);
status.GetMakefile().AddFunctionBlocker(std::move(fb));
}
auto fb = cm::make_unique<cmFunctionFunctionBlocker>();
cmAppend(fb->Args, args);
status.GetMakefile().AddFunctionBlocker(std::move(fb));
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)