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 "cmMacroCommand.h"
16 // define the class for macro commands
17 class cmMacroHelperCommand : public cmCommand
20 cmMacroHelperCommand() {}
22 ///! clean up any memory allocated by the macro
23 ~cmMacroHelperCommand() {};
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 cmMacroHelperCommand *newC = new cmMacroHelperCommand;
42 // we must copy when we clone
43 newC->Args = this->Args;
44 newC->Functions = this->Functions;
45 newC->FilePath = this->FilePath;
46 newC->Policies = this->Policies;
51 * This determines if the command is invoked when in script mode.
53 virtual bool IsScriptable() const { return true; }
56 * This is called when the command is first encountered in
57 * the CMakeLists.txt file.
59 virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
62 virtual bool InitialPass(std::vector<std::string> const&,
63 cmExecutionStatus &) { return false; };
66 * The name of the command as specified in CMakeList.txt.
68 virtual const char* GetName() const { return this->Args[0].c_str(); }
71 * Succinct documentation.
73 virtual const char* GetTerseDocumentation() const
75 std::string docs = "Macro named: ";
76 docs += this->GetName();
83 virtual const char* GetFullDocumentation() const
85 return this->GetTerseDocumentation();
88 cmTypeMacro(cmMacroHelperCommand, cmCommand);
90 std::vector<std::string> Args;
91 std::vector<cmListFileFunction> Functions;
92 cmPolicies::PolicyMap Policies;
97 bool cmMacroHelperCommand::InvokeInitialPass
98 (const std::vector<cmListFileArgument>& args,
99 cmExecutionStatus &inStatus)
101 // Expand the argument list to the macro.
102 std::vector<std::string> expandedArgs;
103 this->Makefile->ExpandArguments(args, expandedArgs);
106 cmListFileArgument arg;
107 std::string variable;
109 // make sure the number of arguments passed is at least the number
110 // required by the signature
111 if (expandedArgs.size() < this->Args.size() - 1)
113 std::string errorMsg =
114 "Macro invoked with incorrect arguments for macro named: ";
115 errorMsg += this->Args[0];
116 this->SetError(errorMsg.c_str());
120 // Enforce matching logical blocks inside the macro.
121 cmMakefile::LexicalPushPop lexScope(this->Makefile);
123 // Push a weak policy scope which restores the policies recorded at
125 cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
127 // set the value of argc
128 cmOStringStream argcDefStream;
129 argcDefStream << expandedArgs.size();
130 std::string argcDef = argcDefStream.str();
132 // declare varuiables for ARGV ARGN but do not compute until needed
135 bool argnDefInitialized = false;
136 bool argvDefInitialized = false;
137 if( this->Functions.size())
139 this->FilePath = this->Functions[0].FilePath;
141 // Invoke all the functions that were collected in the block.
142 cmListFileFunction newLFF;
144 for(unsigned int c = 0; c < this->Functions.size(); ++c)
146 // Replace the formal arguments and then invoke the command.
147 newLFF.Arguments.clear();
148 newLFF.Arguments.reserve(this->Functions[c].Arguments.size());
149 newLFF.Name = this->Functions[c].Name;
150 newLFF.FilePath = this->Functions[c].FilePath;
151 newLFF.Line = this->Functions[c].Line;
153 // for each argument of the current function
154 for (std::vector<cmListFileArgument>::iterator k =
155 this->Functions[c].Arguments.begin();
156 k != this->Functions[c].Arguments.end(); ++k)
158 // Set the FilePath on the arguments to match the function since it is
159 // not stored and the original values may be freed
160 k->FilePath = this->FilePath.c_str();
162 // replace formal arguments
163 for (unsigned int j = 1; j < this->Args.size(); ++j)
166 variable += this->Args[j];
168 cmSystemTools::ReplaceString(tmps, variable.c_str(),
169 expandedArgs[j-1].c_str());
172 cmSystemTools::ReplaceString(tmps, "${ARGC}",argcDef.c_str());
175 if (tmps.find("${ARGN}") != std::string::npos)
177 if (!argnDefInitialized)
179 std::vector<std::string>::const_iterator eit;
180 std::vector<std::string>::size_type cnt = 0;
181 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
183 if ( cnt >= this->Args.size()-1 )
185 if ( argnDef.size() > 0 )
193 argnDefInitialized = true;
195 cmSystemTools::ReplaceString(tmps, "${ARGN}", argnDef.c_str());
198 // if the current argument of the current function has ${ARGV in it
199 // then try replacing ARGV values
200 if (tmps.find("${ARGV") != std::string::npos)
204 // repleace ARGV, compute it only once
205 if (!argvDefInitialized)
207 std::vector<std::string>::const_iterator eit;
208 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
210 if ( argvDef.size() > 0 )
216 argvDefInitialized = true;
218 cmSystemTools::ReplaceString(tmps, "${ARGV}", argvDef.c_str());
220 // also replace the ARGV1 ARGV2 ... etc
221 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
223 sprintf(argvName,"${ARGV%i}",t);
224 cmSystemTools::ReplaceString(tmps, argvName,
225 expandedArgs[t].c_str());
230 arg.Quoted = k->Quoted;
231 arg.FilePath = k->FilePath;
233 newLFF.Arguments.push_back(arg);
235 cmExecutionStatus status;
236 if(!this->Makefile->ExecuteCommand(newLFF, status) ||
237 status.GetNestedError())
239 // The error message should have already included the call stack
240 // so we do not need to report an error here.
243 inStatus.SetNestedError(true);
246 if (status.GetReturnInvoked())
248 inStatus.SetReturnInvoked(true);
251 if (status.GetBreakInvoked())
253 inStatus.SetBreakInvoked(true);
260 bool cmMacroFunctionBlocker::
261 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
264 // record commands until we hit the ENDMACRO
265 // at the ENDMACRO call we shift gears and start looking for invocations
266 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"macro"))
270 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
272 // if this is the endmacro for this macro then execute
275 std::string name = this->Args[0];
276 std::vector<std::string>::size_type cc;
278 for ( cc = 0; cc < this->Args.size(); cc ++ )
280 name += " " + this->Args[cc];
283 mf.AddMacro(this->Args[0].c_str(), name.c_str());
284 // create a new command and add it to cmake
285 cmMacroHelperCommand *f = new cmMacroHelperCommand();
286 f->Args = this->Args;
287 f->Functions = this->Functions;
288 mf.RecordPolicies(f->Policies);
289 std::string newName = "_" + this->Args[0];
290 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
294 // remove the function blocker now that the macro is defined
295 mf.RemoveFunctionBlocker(this, lff);
300 // decrement for each nested macro that ends
305 // if it wasn't an endmacro and we are not executing then we must be
307 this->Functions.push_back(lff);
312 bool cmMacroFunctionBlocker::
313 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
315 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
317 std::vector<std::string> expandedArguments;
318 mf.ExpandArguments(lff.Arguments, expandedArguments);
319 // if the endmacro has arguments make sure they
320 // match the arguments of the macro
321 if ((expandedArguments.empty() ||
322 (expandedArguments[0] == this->Args[0])))
331 bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
336 this->SetError("called with incorrect number of arguments");
340 // create a function blocker
341 cmMacroFunctionBlocker *f = new cmMacroFunctionBlocker();
342 for(std::vector<std::string>::const_iterator j = args.begin();
343 j != args.end(); ++j)
345 f->Args.push_back(*j);
347 this->Makefile->AddFunctionBlocker(f);