1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
8 This software is distributed WITHOUT ANY WARRANTY; without even the
9 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 See the License for more information.
11 ============================================================================*/
12 #include "cmFunctionCommand.h"
16 // define the class for function commands
17 class cmFunctionHelperCommand : public cmCommand
20 cmFunctionHelperCommand() {}
22 ///! clean up any memory allocated by the function
23 ~cmFunctionHelperCommand() {};
26 * This is used to avoid including this command
27 * in documentation. This is mainly used by
28 * cmMacroHelperCommand and cmFunctionHelperCommand
29 * which cannot provide appropriate documentation.
31 virtual bool ShouldAppearInDocumentation() const
37 * This is a virtual constructor for the command.
39 virtual cmCommand* Clone()
41 cmFunctionHelperCommand *newC = new cmFunctionHelperCommand;
42 // we must copy when we clone
43 newC->Args = this->Args;
44 newC->Functions = this->Functions;
45 newC->Policies = this->Policies;
50 * This determines if the command is invoked when in script mode.
52 virtual bool IsScriptable() const { return true; }
55 * This is called when the command is first encountered in
56 * the CMakeLists.txt file.
58 virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
61 virtual bool InitialPass(std::vector<std::string> const&,
62 cmExecutionStatus &) { return false; };
65 * The name of the command as specified in CMakeList.txt.
67 virtual const char* GetName() const { return this->Args[0].c_str(); }
70 * Succinct documentation.
72 virtual const char* GetTerseDocumentation() const
74 std::string docs = "Function named: ";
75 docs += this->GetName();
82 virtual const char* GetFullDocumentation() const
84 return this->GetTerseDocumentation();
87 cmTypeMacro(cmFunctionHelperCommand, cmCommand);
89 std::vector<std::string> Args;
90 std::vector<cmListFileFunction> Functions;
91 cmPolicies::PolicyMap Policies;
95 bool cmFunctionHelperCommand::InvokeInitialPass
96 (const std::vector<cmListFileArgument>& args,
97 cmExecutionStatus & inStatus)
99 // Expand the argument list to the function.
100 std::vector<std::string> expandedArgs;
101 this->Makefile->ExpandArguments(args, expandedArgs);
103 // make sure the number of arguments passed is at least the number
104 // required by the signature
105 if (expandedArgs.size() < this->Args.size() - 1)
107 std::string errorMsg =
108 "Function invoked with incorrect arguments for function named: ";
109 errorMsg += this->Args[0];
110 this->SetError(errorMsg.c_str());
114 // we push a scope on the makefile
115 cmMakefile::LexicalPushPop lexScope(this->Makefile);
116 cmMakefile::ScopePushPop varScope(this->Makefile);
117 static_cast<void>(varScope);
119 // Push a weak policy scope which restores the policies recorded at
120 // function creation.
121 cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
123 // set the value of argc
124 cmOStringStream strStream;
125 strStream << expandedArgs.size();
126 this->Makefile->AddDefinition("ARGC",strStream.str().c_str());
127 this->Makefile->MarkVariableAsUsed("ARGC");
129 // set the values for ARGV0 ARGV1 ...
130 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
132 cmOStringStream tmpStream;
133 tmpStream << "ARGV" << t;
134 this->Makefile->AddDefinition(tmpStream.str().c_str(),
135 expandedArgs[t].c_str());
136 this->Makefile->MarkVariableAsUsed(tmpStream.str().c_str());
139 // define the formal arguments
140 for (unsigned int j = 1; j < this->Args.size(); ++j)
142 this->Makefile->AddDefinition(this->Args[j].c_str(),
143 expandedArgs[j-1].c_str());
146 // define ARGV and ARGN
147 std::vector<std::string>::const_iterator eit;
150 unsigned int cnt = 0;
151 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
153 if ( argvDef.size() > 0 )
158 if ( cnt >= this->Args.size()-1 )
160 if ( argnDef.size() > 0 )
168 this->Makefile->AddDefinition("ARGV", argvDef.c_str());
169 this->Makefile->MarkVariableAsUsed("ARGV");
170 this->Makefile->AddDefinition("ARGN", argnDef.c_str());
171 this->Makefile->MarkVariableAsUsed("ARGN");
173 // Invoke all the functions that were collected in the block.
175 for(unsigned int c = 0; c < this->Functions.size(); ++c)
177 cmExecutionStatus status;
178 if (!this->Makefile->ExecuteCommand(this->Functions[c],status) ||
179 status.GetNestedError())
181 // The error message should have already included the call stack
182 // so we do not need to report an error here.
185 inStatus.SetNestedError(true);
188 if (status.GetReturnInvoked())
194 // pop scope on the makefile
198 bool cmFunctionFunctionBlocker::
199 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
202 // record commands until we hit the ENDFUNCTION
203 // at the ENDFUNCTION call we shift gears and start looking for invocations
204 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"function"))
208 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
210 // if this is the endfunction for this function then execute
213 std::string name = this->Args[0];
214 std::vector<std::string>::size_type cc;
216 for ( cc = 0; cc < this->Args.size(); cc ++ )
218 name += " " + this->Args[cc];
222 // create a new command and add it to cmake
223 cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
224 f->Args = this->Args;
225 f->Functions = this->Functions;
226 mf.RecordPolicies(f->Policies);
228 // Set the FilePath on the arguments to match the function since it is
229 // not stored and the original values may be freed
230 for (unsigned int i = 0; i < f->Functions.size(); ++i)
232 for (unsigned int j = 0; j < f->Functions[i].Arguments.size(); ++j)
234 f->Functions[i].Arguments[j].FilePath =
235 f->Functions[i].FilePath.c_str();
239 std::string newName = "_" + this->Args[0];
240 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
244 // remove the function blocker now that the function is defined
245 mf.RemoveFunctionBlocker(this, lff);
250 // decrement for each nested function that ends
255 // if it wasn't an endfunction and we are not executing then we must be
257 this->Functions.push_back(lff);
262 bool cmFunctionFunctionBlocker::
263 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
265 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
267 std::vector<std::string> expandedArguments;
268 mf.ExpandArguments(lff.Arguments, expandedArguments);
269 // if the endfunction has arguments then make sure
270 // they match the ones in the opening function command
271 if ((expandedArguments.empty() ||
272 (expandedArguments[0] == this->Args[0])))
281 bool cmFunctionCommand
282 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
286 this->SetError("called with incorrect number of arguments");
290 // create a function blocker
291 cmFunctionFunctionBlocker *f = new cmFunctionFunctionBlocker();
292 for(std::vector<std::string>::const_iterator j = args.begin();
293 j != args.end(); ++j)
295 f->Args.push_back(*j);
297 this->Makefile->AddFunctionBlocker(f);