Brad King | 86578ec | 2016-09-27 19:01:08 | [diff] [blame] | 1 | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| 2 | file Copyright.txt or https://cmake.org/licensing for details. */ |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 3 | #include "cmFunctionCommand.h" |
| 4 | |
Marc Chevrier | 1591f13 | 2019-07-04 16:14:22 | [diff] [blame] | 5 | #include <utility> |
| 6 | |
Marc Chevrier | c688b40 | 2019-08-04 08:49:16 | [diff] [blame] | 7 | #include <cm/memory> |
| 8 | #include <cm/string_view> |
Marc Chevrier | f7d1260 | 2019-12-09 16:39:29 | [diff] [blame] | 9 | #include <cmext/algorithm> |
Marc Chevrier | 8d4a9ee | 2020-04-27 14:38:14 | [diff] [blame] | 10 | #include <cmext/string_view> |
Regina Pfeifer | af24e4e | 2019-07-30 16:15:13 | [diff] [blame] | 11 | |
Daniel Pfeifer | e81c323 | 2016-10-25 18:35:04 | [diff] [blame] | 12 | #include "cmExecutionStatus.h" |
Regina Pfeifer | c765009 | 2019-07-23 21:00:28 | [diff] [blame] | 13 | #include "cmFunctionBlocker.h" |
Marc Chevrier | 45f17e5 | 2023-06-20 14:32:27 | [diff] [blame] | 14 | #include "cmList.h" |
Regina Pfeifer | c765009 | 2019-07-23 21:00:28 | [diff] [blame] | 15 | #include "cmListFileCache.h" |
Daniel Pfeifer | e81c323 | 2016-10-25 18:35:04 | [diff] [blame] | 16 | #include "cmMakefile.h" |
| 17 | #include "cmPolicies.h" |
Regina Pfeifer | 9eb0e73 | 2019-02-15 20:34:44 | [diff] [blame] | 18 | #include "cmRange.h" |
Daniel Pfeifer | 64f9c28 | 2016-10-19 19:59:14 | [diff] [blame] | 19 | #include "cmState.h" |
Sebastian Holtermann | f71f7ce | 2019-07-29 10:16:40 | [diff] [blame] | 20 | #include "cmStringAlgorithms.h" |
Alex Turbov | 90e3e2a | 2019-12-08 00:26:14 | [diff] [blame] | 21 | #include "cmSystemTools.h" |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 22 | |
Gabor Bencze | 9bbe95a | 2019-07-25 17:07:00 | [diff] [blame] | 23 | namespace { |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 24 | std::string const ARGC = "ARGC"; |
| 25 | std::string const ARGN = "ARGN"; |
| 26 | std::string const ARGV = "ARGV"; |
Alex Turbov | 90e3e2a | 2019-12-08 00:26:14 | [diff] [blame] | 27 | std::string const CMAKE_CURRENT_FUNCTION = "CMAKE_CURRENT_FUNCTION"; |
| 28 | std::string const CMAKE_CURRENT_FUNCTION_LIST_FILE = |
| 29 | "CMAKE_CURRENT_FUNCTION_LIST_FILE"; |
| 30 | std::string const CMAKE_CURRENT_FUNCTION_LIST_DIR = |
| 31 | "CMAKE_CURRENT_FUNCTION_LIST_DIR"; |
| 32 | std::string const CMAKE_CURRENT_FUNCTION_LIST_LINE = |
| 33 | "CMAKE_CURRENT_FUNCTION_LIST_LINE"; |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 34 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 35 | // define the class for function commands |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 36 | class cmFunctionHelperCommand |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 37 | { |
| 38 | public: |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 39 | /** |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 40 | * This is called when the command is first encountered in |
| 41 | * the CMakeLists.txt file. |
| 42 | */ |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 43 | bool operator()(std::vector<cmListFileArgument> const& args, |
| 44 | cmExecutionStatus& inStatus) const; |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 45 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 46 | std::vector<std::string> Args; |
| 47 | std::vector<cmListFileFunction> Functions; |
Brad King | 3028ca7 | 2009-01-22 18:16:47 | [diff] [blame] | 48 | cmPolicies::PolicyMap Policies; |
Stephen Kelly | 569f478 | 2015-05-23 20:21:08 | [diff] [blame] | 49 | std::string FilePath; |
Alex Turbov | 90e3e2a | 2019-12-08 00:26:14 | [diff] [blame] | 50 | long Line; |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 51 | }; |
| 52 | |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 53 | bool cmFunctionHelperCommand::operator()( |
| 54 | std::vector<cmListFileArgument> const& args, |
| 55 | cmExecutionStatus& inStatus) const |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 56 | { |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 57 | cmMakefile& makefile = inStatus.GetMakefile(); |
| 58 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 59 | // Expand the argument list to the function. |
| 60 | std::vector<std::string> expandedArgs; |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 61 | makefile.ExpandArguments(args, expandedArgs); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 62 | |
| 63 | // make sure the number of arguments passed is at least the number |
| 64 | // required by the signature |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 65 | if (expandedArgs.size() < this->Args.size() - 1) { |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 66 | auto const errorMsg = cmStrCat( |
Sebastian Holtermann | 9b33439 | 2019-08-22 14:34:40 | [diff] [blame] | 67 | "Function invoked with incorrect arguments for function named: ", |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 68 | this->Args.front()); |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 69 | inStatus.SetError(errorMsg); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 70 | return false; |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 71 | } |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 72 | |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 73 | cmMakefile::FunctionPushPop functionScope(&makefile, this->FilePath, |
Stephen Kelly | d5dc416 | 2015-05-31 16:19:58 | [diff] [blame] | 74 | this->Policies); |
Brad King | 3028ca7 | 2009-01-22 18:16:47 | [diff] [blame] | 75 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 76 | // set the value of argc |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 77 | makefile.AddDefinition(ARGC, std::to_string(expandedArgs.size())); |
| 78 | makefile.MarkVariableAsUsed(ARGC); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 79 | |
| 80 | // set the values for ARGV0 ARGV1 ... |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 81 | for (auto t = 0u; t < expandedArgs.size(); ++t) { |
| 82 | auto const value = cmStrCat(ARGV, std::to_string(t)); |
| 83 | makefile.AddDefinition(value, expandedArgs[t]); |
| 84 | makefile.MarkVariableAsUsed(value); |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 85 | } |
Kitware Robot | 7bbaa42 | 2012-08-13 17:42:58 | [diff] [blame] | 86 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 87 | // define the formal arguments |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 88 | for (auto j = 1u; j < this->Args.size(); ++j) { |
Sebastian Holtermann | e91bfe4 | 2019-07-17 14:20:58 | [diff] [blame] | 89 | makefile.AddDefinition(this->Args[j], expandedArgs[j - 1]); |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 90 | } |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 91 | |
| 92 | // define ARGV and ARGN |
Marc Chevrier | 45f17e5 | 2023-06-20 14:32:27 | [diff] [blame] | 93 | auto const argvDef = cmList::to_string(expandedArgs); |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 94 | auto const eit = expandedArgs.begin() + (this->Args.size() - 1); |
Marc Chevrier | 45f17e5 | 2023-06-20 14:32:27 | [diff] [blame] | 95 | auto const argnDef = cmList::to_string(cmMakeRange(eit, expandedArgs.end())); |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 96 | makefile.AddDefinition(ARGV, argvDef); |
| 97 | makefile.MarkVariableAsUsed(ARGV); |
| 98 | makefile.AddDefinition(ARGN, argnDef); |
| 99 | makefile.MarkVariableAsUsed(ARGN); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 100 | |
Alex Turbov | 90e3e2a | 2019-12-08 00:26:14 | [diff] [blame] | 101 | makefile.AddDefinition(CMAKE_CURRENT_FUNCTION, this->Args.front()); |
| 102 | makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION); |
| 103 | makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_FILE, this->FilePath); |
| 104 | makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_FILE); |
| 105 | makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_DIR, |
| 106 | cmSystemTools::GetFilenamePath(this->FilePath)); |
| 107 | makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_DIR); |
| 108 | makefile.AddDefinition(CMAKE_CURRENT_FUNCTION_LIST_LINE, |
| 109 | std::to_string(this->Line)); |
| 110 | makefile.MarkVariableAsUsed(CMAKE_CURRENT_FUNCTION_LIST_LINE); |
| 111 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 112 | // Invoke all the functions that were collected in the block. |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 113 | // for each function |
Pavel Solodovnikov | 7d50957 | 2017-09-11 10:40:26 | [diff] [blame] | 114 | for (cmListFileFunction const& func : this->Functions) { |
Regina Pfeifer | de77d35 | 2019-04-07 19:27:41 | [diff] [blame] | 115 | cmExecutionStatus status(makefile); |
| 116 | if (!makefile.ExecuteCommand(func, status) || status.GetNestedError()) { |
Brad King | 680104a | 2008-03-07 13:40:36 | [diff] [blame] | 117 | // The error message should have already included the call stack |
| 118 | // so we do not need to report an error here. |
Stephen Kelly | d5dc416 | 2015-05-31 16:19:58 | [diff] [blame] | 119 | functionScope.Quiet(); |
Daniel Pfeifer | 67a8d90 | 2016-12-26 09:30:31 | [diff] [blame] | 120 | inStatus.SetNestedError(); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 121 | return false; |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 122 | } |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 123 | if (status.GetReturnInvoked()) { |
Marc Chevrier | 838a5fa | 2022-08-22 14:10:56 | [diff] [blame] | 124 | makefile.RaiseScope(status.GetReturnVariables()); |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 125 | break; |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 126 | } |
| 127 | } |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 128 | |
| 129 | // pop scope on the makefile |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 130 | return true; |
| 131 | } |
| 132 | |
Regina Pfeifer | c765009 | 2019-07-23 21:00:28 | [diff] [blame] | 133 | class cmFunctionFunctionBlocker : public cmFunctionBlocker |
| 134 | { |
| 135 | public: |
Regina Pfeifer | af24e4e | 2019-07-30 16:15:13 | [diff] [blame] | 136 | cm::string_view StartCommandName() const override { return "function"_s; } |
| 137 | cm::string_view EndCommandName() const override { return "endfunction"_s; } |
| 138 | |
Regina Pfeifer | 6491270 | 2019-07-30 20:58:40 | [diff] [blame] | 139 | bool ArgumentsMatch(cmListFileFunction const&, |
| 140 | cmMakefile& mf) const override; |
| 141 | |
Regina Pfeifer | 4136482 | 2019-07-30 21:54:12 | [diff] [blame] | 142 | bool Replay(std::vector<cmListFileFunction> functions, |
Regina Pfeifer | af24e4e | 2019-07-30 16:15:13 | [diff] [blame] | 143 | cmExecutionStatus& status) override; |
Regina Pfeifer | c765009 | 2019-07-23 21:00:28 | [diff] [blame] | 144 | |
| 145 | std::vector<std::string> Args; |
Regina Pfeifer | c765009 | 2019-07-23 21:00:28 | [diff] [blame] | 146 | }; |
| 147 | |
Regina Pfeifer | 6491270 | 2019-07-30 20:58:40 | [diff] [blame] | 148 | bool cmFunctionFunctionBlocker::ArgumentsMatch(cmListFileFunction const& lff, |
| 149 | cmMakefile& mf) const |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 150 | { |
Regina Pfeifer | 6491270 | 2019-07-30 20:58:40 | [diff] [blame] | 151 | std::vector<std::string> expandedArguments; |
Oleksandr Koval | e614528 | 2020-10-01 11:28:03 | [diff] [blame] | 152 | mf.ExpandArguments(lff.Arguments(), expandedArguments); |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 153 | return expandedArguments.empty() || |
| 154 | expandedArguments.front() == this->Args.front(); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 155 | } |
| 156 | |
Regina Pfeifer | ef38ff2 | 2019-07-23 21:50:33 | [diff] [blame] | 157 | bool cmFunctionFunctionBlocker::Replay( |
Regina Pfeifer | 4136482 | 2019-07-30 21:54:12 | [diff] [blame] | 158 | std::vector<cmListFileFunction> functions, cmExecutionStatus& status) |
Regina Pfeifer | ef38ff2 | 2019-07-23 21:50:33 | [diff] [blame] | 159 | { |
| 160 | cmMakefile& mf = status.GetMakefile(); |
| 161 | // create a new command and add it to cmake |
| 162 | cmFunctionHelperCommand f; |
| 163 | f.Args = this->Args; |
Regina Pfeifer | 4136482 | 2019-07-30 21:54:12 | [diff] [blame] | 164 | f.Functions = std::move(functions); |
Regina Pfeifer | ef38ff2 | 2019-07-23 21:50:33 | [diff] [blame] | 165 | f.FilePath = this->GetStartingContext().FilePath; |
Alex Turbov | 90e3e2a | 2019-12-08 00:26:14 | [diff] [blame] | 166 | f.Line = this->GetStartingContext().Line; |
Regina Pfeifer | ef38ff2 | 2019-07-23 21:50:33 | [diff] [blame] | 167 | mf.RecordPolicies(f.Policies); |
Kyle Edwards | 8aee7fd | 2020-10-22 20:50:42 | [diff] [blame] | 168 | return mf.GetState()->AddScriptedCommand( |
| 169 | this->Args.front(), |
| 170 | BT<cmState::Command>(std::move(f), |
| 171 | mf.GetBacktrace().Push(this->GetStartingContext())), |
| 172 | mf); |
Regina Pfeifer | ef38ff2 | 2019-07-23 21:50:33 | [diff] [blame] | 173 | } |
| 174 | |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 175 | } // anonymous namespace |
| 176 | |
Gabor Bencze | 9bbe95a | 2019-07-25 17:07:00 | [diff] [blame] | 177 | bool cmFunctionCommand(std::vector<std::string> const& args, |
| 178 | cmExecutionStatus& status) |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 179 | { |
Daniel Pfeifer | 73f648f | 2016-09-15 21:59:29 | [diff] [blame] | 180 | if (args.empty()) { |
Gabor Bencze | 9bbe95a | 2019-07-25 17:07:00 | [diff] [blame] | 181 | status.SetError("called with incorrect number of arguments"); |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 182 | return false; |
Kitware Robot | d9fd2f5 | 2016-05-16 14:34:04 | [diff] [blame] | 183 | } |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 184 | |
| 185 | // create a function blocker |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 186 | auto fb = cm::make_unique<cmFunctionFunctionBlocker>(); |
Marc Chevrier | f7d1260 | 2019-12-09 16:39:29 | [diff] [blame] | 187 | cm::append(fb->Args, args); |
Alex Turbov | dd54290 | 2019-11-05 21:15:54 | [diff] [blame] | 188 | status.GetMakefile().AddFunctionBlocker(std::move(fb)); |
| 189 | |
Ken Martin | 9514441 | 2007-12-03 17:44:42 | [diff] [blame] | 190 | return true; |
| 191 | } |