1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMacroCommand.cxx,v $
6 Date: $Date: 2009-01-22 18:16:47 $
7 Version: $Revision: 1.41 $
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"
21 // define the class for macro commands
22 class cmMacroHelperCommand
: public cmCommand
25 cmMacroHelperCommand() {}
27 ///! clean up any memory allocated by the macro
28 ~cmMacroHelperCommand() {};
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 newC
->Policies
= this->Policies
;
44 * This determines if the command is invoked when in script mode.
46 virtual bool IsScriptable() { return true; }
49 * This is called when the command is first encountered in
50 * the CMakeLists.txt file.
52 virtual bool InvokeInitialPass(const std::vector
<cmListFileArgument
>& args
,
55 virtual bool InitialPass(std::vector
<std::string
> const&,
56 cmExecutionStatus
&) { return false; };
59 * The name of the command as specified in CMakeList.txt.
61 virtual const char* GetName() { return this->Args
[0].c_str(); }
64 * Succinct documentation.
66 virtual const char* GetTerseDocumentation()
68 std::string docs
= "Macro named: ";
69 docs
+= this->GetName();
76 virtual const char* GetFullDocumentation()
78 return this->GetTerseDocumentation();
81 cmTypeMacro(cmMacroHelperCommand
, cmCommand
);
83 std::vector
<std::string
> Args
;
84 std::vector
<cmListFileFunction
> Functions
;
85 cmPolicies::PolicyMap Policies
;
89 bool cmMacroHelperCommand::InvokeInitialPass
90 (const std::vector
<cmListFileArgument
>& args
,
91 cmExecutionStatus
&inStatus
)
93 // Expand the argument list to the macro.
94 std::vector
<std::string
> expandedArgs
;
95 this->Makefile
->ExpandArguments(args
, expandedArgs
);
98 cmListFileArgument arg
;
101 // make sure the number of arguments passed is at least the number
102 // required by the signature
103 if (expandedArgs
.size() < this->Args
.size() - 1)
105 std::string errorMsg
=
106 "Macro invoked with incorrect arguments for macro named: ";
107 errorMsg
+= this->Args
[0];
108 this->SetError(errorMsg
.c_str());
112 // Enforce matching logical blocks inside the macro.
113 cmMakefile::LexicalPushPop
lexScope(this->Makefile
);
115 // Push a weak policy scope which restores the policies recorded at
117 cmMakefile::PolicyPushPop
polScope(this->Makefile
, true, this->Policies
);
119 // set the value of argc
120 cmOStringStream argcDefStream
;
121 argcDefStream
<< expandedArgs
.size();
122 std::string argcDef
= argcDefStream
.str();
124 // declare varuiables for ARGV ARGN but do not compute until needed
127 bool argnDefInitialized
= false;
128 bool argvDefInitialized
= false;
130 // Invoke all the functions that were collected in the block.
131 cmListFileFunction newLFF
;
133 for(unsigned int c
= 0; c
< this->Functions
.size(); ++c
)
135 // Replace the formal arguments and then invoke the command.
136 newLFF
.Arguments
.clear();
137 newLFF
.Arguments
.reserve(this->Functions
[c
].Arguments
.size());
138 newLFF
.Name
= this->Functions
[c
].Name
;
139 newLFF
.FilePath
= this->Functions
[c
].FilePath
;
140 newLFF
.Line
= this->Functions
[c
].Line
;
142 // for each argument of the current function
143 for (std::vector
<cmListFileArgument
>::const_iterator k
=
144 this->Functions
[c
].Arguments
.begin();
145 k
!= this->Functions
[c
].Arguments
.end(); ++k
)
148 // replace formal arguments
149 for (unsigned int j
= 1; j
< this->Args
.size(); ++j
)
152 variable
+= this->Args
[j
];
154 cmSystemTools::ReplaceString(tmps
, variable
.c_str(),
155 expandedArgs
[j
-1].c_str());
158 cmSystemTools::ReplaceString(tmps
, "${ARGC}",argcDef
.c_str());
161 if (tmps
.find("${ARGN}") != std::string::npos
)
163 if (!argnDefInitialized
)
165 std::vector
<std::string
>::const_iterator eit
;
166 std::vector
<std::string
>::size_type cnt
= 0;
167 for ( eit
= expandedArgs
.begin(); eit
!= expandedArgs
.end(); ++eit
)
169 if ( cnt
>= this->Args
.size()-1 )
171 if ( argnDef
.size() > 0 )
179 argnDefInitialized
= true;
181 cmSystemTools::ReplaceString(tmps
, "${ARGN}", argnDef
.c_str());
184 // if the current argument of the current function has ${ARGV in it
185 // then try replacing ARGV values
186 if (tmps
.find("${ARGV") != std::string::npos
)
190 // repleace ARGV, compute it only once
191 if (!argvDefInitialized
)
193 std::vector
<std::string
>::const_iterator eit
;
194 for ( eit
= expandedArgs
.begin(); eit
!= expandedArgs
.end(); ++eit
)
196 if ( argvDef
.size() > 0 )
202 argvDefInitialized
= true;
204 cmSystemTools::ReplaceString(tmps
, "${ARGV}", argvDef
.c_str());
206 // also replace the ARGV1 ARGV2 ... etc
207 for (unsigned int t
= 0; t
< expandedArgs
.size(); ++t
)
209 sprintf(argvName
,"${ARGV%i}",t
);
210 cmSystemTools::ReplaceString(tmps
, argvName
,
211 expandedArgs
[t
].c_str());
216 arg
.Quoted
= k
->Quoted
;
217 arg
.FilePath
= k
->FilePath
;
219 newLFF
.Arguments
.push_back(arg
);
221 cmExecutionStatus status
;
222 if(!this->Makefile
->ExecuteCommand(newLFF
, status
) ||
223 status
.GetNestedError())
225 // The error message should have already included the call stack
226 // so we do not need to report an error here.
229 inStatus
.SetNestedError(true);
232 if (status
.GetReturnInvoked())
234 inStatus
.SetReturnInvoked(true);
237 if (status
.GetBreakInvoked())
239 inStatus
.SetBreakInvoked(true);
246 bool cmMacroFunctionBlocker::
247 IsFunctionBlocked(const cmListFileFunction
& lff
, cmMakefile
&mf
,
250 // record commands until we hit the ENDMACRO
251 // at the ENDMACRO call we shift gears and start looking for invocations
252 if(!cmSystemTools::Strucmp(lff
.Name
.c_str(),"macro"))
256 else if(!cmSystemTools::Strucmp(lff
.Name
.c_str(),"endmacro"))
258 // if this is the endmacro for this macro then execute
261 std::string name
= this->Args
[0];
262 std::vector
<std::string
>::size_type cc
;
264 for ( cc
= 0; cc
< this->Args
.size(); cc
++ )
266 name
+= " " + this->Args
[cc
];
269 mf
.AddMacro(this->Args
[0].c_str(), name
.c_str());
270 // create a new command and add it to cmake
271 cmMacroHelperCommand
*f
= new cmMacroHelperCommand();
272 f
->Args
= this->Args
;
273 f
->Functions
= this->Functions
;
274 mf
.RecordPolicies(f
->Policies
);
275 std::string newName
= "_" + this->Args
[0];
276 mf
.GetCMakeInstance()->RenameCommand(this->Args
[0].c_str(),
280 // remove the function blocker now that the macro is defined
281 mf
.RemoveFunctionBlocker(this, lff
);
286 // decrement for each nested macro that ends
291 // if it wasn't an endmacro and we are not executing then we must be
293 this->Functions
.push_back(lff
);
298 bool cmMacroFunctionBlocker::
299 ShouldRemove(const cmListFileFunction
& lff
, cmMakefile
&mf
)
301 if(!cmSystemTools::Strucmp(lff
.Name
.c_str(),"endmacro"))
303 std::vector
<std::string
> expandedArguments
;
304 mf
.ExpandArguments(lff
.Arguments
, expandedArguments
);
305 // if the endmacro has arguments make sure they
306 // match the arguments of the macro
307 if ((expandedArguments
.empty() ||
308 (expandedArguments
[0] == this->Args
[0])))
317 bool cmMacroCommand::InitialPass(std::vector
<std::string
> const& args
,
322 this->SetError("called with incorrect number of arguments");
326 // create a function blocker
327 cmMacroFunctionBlocker
*f
= new cmMacroFunctionBlocker();
328 for(std::vector
<std::string
>::const_iterator j
= args
.begin();
329 j
!= args
.end(); ++j
)
331 f
->Args
.push_back(*j
);
333 this->Makefile
->AddFunctionBlocker(f
);