Initial commit.
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmMacroCommand.cxx
blob86a3723b777d5f556230ced032f8e79b4875af75
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMacroCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008/01/23 15:27:59 $
7 Version: $Revision: 1.34 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmMacroCommand.h"
19 #include "cmake.h"
21 // define the class for macro commands
22 class cmMacroHelperCommand : public cmCommand
24 public:
25 cmMacroHelperCommand() {}
27 ///! clean up any memory allocated by the macro
28 ~cmMacroHelperCommand() {};
30 /**
31 * This is a virtual constructor for the command.
33 virtual cmCommand* Clone()
35 cmMacroHelperCommand *newC = new cmMacroHelperCommand;
36 // we must copy when we clone
37 newC->Args = this->Args;
38 newC->Functions = this->Functions;
39 return newC;
42 /**
43 * This determines if the command is invoked when in script mode.
45 virtual bool IsScriptable() { return true; }
47 /**
48 * This is called when the command is first encountered in
49 * the CMakeLists.txt file.
51 virtual bool InvokeInitialPass(const std::vector<cmListFileArgument>& args,
52 cmExecutionStatus &);
54 virtual bool InitialPass(std::vector<std::string> const&,
55 cmExecutionStatus &) { return false; };
57 /**
58 * The name of the command as specified in CMakeList.txt.
60 virtual const char* GetName() { return this->Args[0].c_str(); }
62 /**
63 * Succinct documentation.
65 virtual const char* GetTerseDocumentation()
67 std::string docs = "Macro named: ";
68 docs += this->GetName();
69 return docs.c_str();
72 /**
73 * More documentation.
75 virtual const char* GetFullDocumentation()
77 return this->GetTerseDocumentation();
80 cmTypeMacro(cmMacroHelperCommand, cmCommand);
82 std::vector<std::string> Args;
83 std::vector<cmListFileFunction> Functions;
87 bool cmMacroHelperCommand::InvokeInitialPass
88 (const std::vector<cmListFileArgument>& args,
89 cmExecutionStatus &inStatus)
91 // Expand the argument list to the macro.
92 std::vector<std::string> expandedArgs;
93 this->Makefile->ExpandArguments(args, expandedArgs);
95 std::string tmps;
96 cmListFileArgument arg;
97 std::string variable;
99 // make sure the number of arguments passed is at least the number
100 // required by the signature
101 if (expandedArgs.size() < this->Args.size() - 1)
103 std::string errorMsg =
104 "Macro invoked with incorrect arguments for macro named: ";
105 errorMsg += this->Args[0];
106 this->SetError(errorMsg.c_str());
107 return false;
110 // set the value of argc
111 cmOStringStream argcDefStream;
112 argcDefStream << expandedArgs.size();
113 std::string argcDef = argcDefStream.str();
115 // declare varuiables for ARGV ARGN but do not compute until needed
116 std::string argvDef;
117 std::string argnDef;
118 bool argnDefInitialized = false;
119 bool argvDefInitialized = false;
121 // Invoke all the functions that were collected in the block.
122 cmListFileFunction newLFF;
123 // for each function
124 for(unsigned int c = 0; c < this->Functions.size(); ++c)
126 // Replace the formal arguments and then invoke the command.
127 newLFF.Arguments.clear();
128 newLFF.Arguments.reserve(this->Functions[c].Arguments.size());
129 newLFF.Name = this->Functions[c].Name;
130 newLFF.FilePath = this->Functions[c].FilePath;
131 newLFF.Line = this->Functions[c].Line;
132 const char* def = this->Makefile->GetDefinition
133 ("CMAKE_MACRO_REPORT_DEFINITION_LOCATION");
134 bool macroReportLocation = false;
135 if(def && !cmSystemTools::IsOff(def))
137 macroReportLocation = true;
140 // for each argument of the current function
141 for (std::vector<cmListFileArgument>::const_iterator k =
142 this->Functions[c].Arguments.begin();
143 k != this->Functions[c].Arguments.end(); ++k)
145 tmps = k->Value;
146 // replace formal arguments
147 for (unsigned int j = 1; j < this->Args.size(); ++j)
149 variable = "${";
150 variable += this->Args[j];
151 variable += "}";
152 cmSystemTools::ReplaceString(tmps, variable.c_str(),
153 expandedArgs[j-1].c_str());
155 // replace argc
156 cmSystemTools::ReplaceString(tmps, "${ARGC}",argcDef.c_str());
158 // repleace ARGN
159 if (tmps.find("${ARGN}") != std::string::npos)
161 if (!argnDefInitialized)
163 std::vector<std::string>::const_iterator eit;
164 std::vector<std::string>::size_type cnt = 0;
165 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
167 if ( cnt >= this->Args.size()-1 )
169 if ( argnDef.size() > 0 )
171 argnDef += ";";
173 argnDef += *eit;
175 cnt ++;
177 argnDefInitialized = true;
179 cmSystemTools::ReplaceString(tmps, "${ARGN}", argnDef.c_str());
182 // if the current argument of the current function has ${ARGV in it
183 // then try replacing ARGV values
184 if (tmps.find("${ARGV") != std::string::npos)
186 char argvName[60];
188 // repleace ARGV, compute it only once
189 if (!argvDefInitialized)
191 std::vector<std::string>::const_iterator eit;
192 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
194 if ( argvDef.size() > 0 )
196 argvDef += ";";
198 argvDef += *eit;
200 argvDefInitialized = true;
202 cmSystemTools::ReplaceString(tmps, "${ARGV}", argvDef.c_str());
204 // also replace the ARGV1 ARGV2 ... etc
205 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
207 sprintf(argvName,"${ARGV%i}",t);
208 cmSystemTools::ReplaceString(tmps, argvName,
209 expandedArgs[t].c_str());
213 arg.Value = tmps;
214 arg.Quoted = k->Quoted;
215 if(macroReportLocation)
217 // Report the location of the argument where the macro was
218 // defined.
219 arg.FilePath = k->FilePath;
220 arg.Line = k->Line;
222 else
224 // Report the location of the argument where the macro was
225 // invoked.
226 if (args.size())
228 arg.FilePath = args[0].FilePath;
229 arg.Line = args[0].Line;
231 else
233 arg.FilePath = "Unknown";
234 arg.Line = 0;
237 newLFF.Arguments.push_back(arg);
239 cmExecutionStatus status;
240 if(!this->Makefile->ExecuteCommand(newLFF,status))
242 if(args.size())
244 arg.FilePath = args[0].FilePath;
245 arg.Line = args[0].Line;
247 else
249 arg.FilePath = "Unknown";
250 arg.Line = 0;
252 cmOStringStream error;
253 error << "Error in cmake code at\n"
254 << arg.FilePath << ":" << arg.Line << ":\n"
255 << "A command failed during the invocation of macro \""
256 << this->Args[0].c_str() << "\".";
257 cmSystemTools::Error(error.str().c_str());
258 return false;
260 if (status.GetReturnInvoked())
262 inStatus.SetReturnInvoked(true);
263 return true;
265 if (status.GetBreakInvoked())
267 inStatus.SetBreakInvoked(true);
268 return true;
271 return true;
274 bool cmMacroFunctionBlocker::
275 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
276 cmExecutionStatus &)
278 // record commands until we hit the ENDMACRO
279 // at the ENDMACRO call we shift gears and start looking for invocations
280 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"macro"))
282 this->Depth++;
284 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
286 // if this is the endmacro for this macro then execute
287 if (!this->Depth)
289 std::string name = this->Args[0];
290 std::vector<std::string>::size_type cc;
291 name += "(";
292 for ( cc = 0; cc < this->Args.size(); cc ++ )
294 name += " " + this->Args[cc];
296 name += " )";
297 mf.AddMacro(this->Args[0].c_str(), name.c_str());
298 // create a new command and add it to cmake
299 cmMacroHelperCommand *f = new cmMacroHelperCommand();
300 f->Args = this->Args;
301 f->Functions = this->Functions;
302 std::string newName = "_" + this->Args[0];
303 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
304 newName.c_str());
305 mf.AddCommand(f);
307 // remove the function blocker now that the macro is defined
308 mf.RemoveFunctionBlocker(lff);
309 return true;
311 else
313 // decrement for each nested macro that ends
314 this->Depth--;
318 // if it wasn't an endmacro and we are not executing then we must be
319 // recording
320 this->Functions.push_back(lff);
321 return true;
325 bool cmMacroFunctionBlocker::
326 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
328 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endmacro"))
330 std::vector<std::string> expandedArguments;
331 mf.ExpandArguments(lff.Arguments, expandedArguments);
332 if ((!expandedArguments.empty() &&
333 (expandedArguments[0] == this->Args[0]))
334 || cmSystemTools::IsOn
335 (mf.GetPropertyOrDefinition("CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS")))
337 return true;
341 return false;
344 void cmMacroFunctionBlocker::
345 ScopeEnded(cmMakefile &mf)
347 // macros should end with an EndMacro
348 cmSystemTools::Error(
349 "The end of a CMakeLists file was reached with a MACRO statement that "
350 "was not closed properly. Within the directory: ",
351 mf.GetCurrentDirectory(), " with macro ",
352 this->Args[0].c_str());
355 bool cmMacroCommand::InitialPass(std::vector<std::string> const& args,
356 cmExecutionStatus &)
358 if(args.size() < 1)
360 this->SetError("called with incorrect number of arguments");
361 return false;
364 // create a function blocker
365 cmMacroFunctionBlocker *f = new cmMacroFunctionBlocker();
366 for(std::vector<std::string>::const_iterator j = args.begin();
367 j != args.end(); ++j)
369 f->Args.push_back(*j);
371 this->Makefile->AddFunctionBlocker(f);
372 return true;