Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmFunctionCommand.cxx
blob086fdc61bcdffe8f0ecadac288b937fcc640fd1e
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmFunctionCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-01-22 18:16:47 $
7 Version: $Revision: 1.11 $
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 "cmFunctionCommand.h"
19 #include "cmake.h"
21 // define the class for function commands
22 class cmFunctionHelperCommand : public cmCommand
24 public:
25 cmFunctionHelperCommand() {}
27 ///! clean up any memory allocated by the function
28 ~cmFunctionHelperCommand() {};
30 /**
31 * This is a virtual constructor for the command.
33 virtual cmCommand* Clone()
35 cmFunctionHelperCommand *newC = new cmFunctionHelperCommand;
36 // we must copy when we clone
37 newC->Args = this->Args;
38 newC->Functions = this->Functions;
39 newC->Policies = this->Policies;
40 return newC;
43 /**
44 * This determines if the command is invoked when in script mode.
46 virtual bool IsScriptable() { return true; }
48 /**
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,
53 cmExecutionStatus &);
55 virtual bool InitialPass(std::vector<std::string> const&,
56 cmExecutionStatus &) { return false; };
58 /**
59 * The name of the command as specified in CMakeList.txt.
61 virtual const char* GetName() { return this->Args[0].c_str(); }
63 /**
64 * Succinct documentation.
66 virtual const char* GetTerseDocumentation()
68 std::string docs = "Function named: ";
69 docs += this->GetName();
70 return docs.c_str();
73 /**
74 * More documentation.
76 virtual const char* GetFullDocumentation()
78 return this->GetTerseDocumentation();
81 cmTypeMacro(cmFunctionHelperCommand, cmCommand);
83 std::vector<std::string> Args;
84 std::vector<cmListFileFunction> Functions;
85 cmPolicies::PolicyMap Policies;
89 bool cmFunctionHelperCommand::InvokeInitialPass
90 (const std::vector<cmListFileArgument>& args,
91 cmExecutionStatus & inStatus)
93 // Expand the argument list to the function.
94 std::vector<std::string> expandedArgs;
95 this->Makefile->ExpandArguments(args, expandedArgs);
97 // make sure the number of arguments passed is at least the number
98 // required by the signature
99 if (expandedArgs.size() < this->Args.size() - 1)
101 std::string errorMsg =
102 "Function invoked with incorrect arguments for function named: ";
103 errorMsg += this->Args[0];
104 this->SetError(errorMsg.c_str());
105 return false;
108 // we push a scope on the makefile
109 cmMakefile::LexicalPushPop lexScope(this->Makefile);
110 cmMakefile::ScopePushPop varScope(this->Makefile);
111 static_cast<void>(varScope);
113 // Push a weak policy scope which restores the policies recorded at
114 // function creation.
115 cmMakefile::PolicyPushPop polScope(this->Makefile, true, this->Policies);
117 // set the value of argc
118 cmOStringStream strStream;
119 strStream << expandedArgs.size();
120 this->Makefile->AddDefinition("ARGC",strStream.str().c_str());
122 // set the values for ARGV0 ARGV1 ...
123 for (unsigned int t = 0; t < expandedArgs.size(); ++t)
125 cmOStringStream tmpStream;
126 tmpStream << "ARGV" << t;
127 this->Makefile->AddDefinition(tmpStream.str().c_str(),
128 expandedArgs[t].c_str());
131 // define the formal arguments
132 for (unsigned int j = 1; j < this->Args.size(); ++j)
134 this->Makefile->AddDefinition(this->Args[j].c_str(),
135 expandedArgs[j-1].c_str());
138 // define ARGV and ARGN
139 std::vector<std::string>::const_iterator eit;
140 std::string argvDef;
141 std::string argnDef;
142 unsigned int cnt = 0;
143 for ( eit = expandedArgs.begin(); eit != expandedArgs.end(); ++eit )
145 if ( argvDef.size() > 0 )
147 argvDef += ";";
149 argvDef += *eit;
150 if ( cnt >= this->Args.size()-1 )
152 if ( argnDef.size() > 0 )
154 argnDef += ";";
156 argnDef += *eit;
158 cnt ++;
160 this->Makefile->AddDefinition("ARGV", argvDef.c_str());
161 this->Makefile->AddDefinition("ARGN", argnDef.c_str());
163 // Invoke all the functions that were collected in the block.
164 // for each function
165 for(unsigned int c = 0; c < this->Functions.size(); ++c)
167 cmExecutionStatus status;
168 if (!this->Makefile->ExecuteCommand(this->Functions[c],status) ||
169 status.GetNestedError())
171 // The error message should have already included the call stack
172 // so we do not need to report an error here.
173 lexScope.Quiet();
174 polScope.Quiet();
175 inStatus.SetNestedError(true);
176 return false;
178 if (status.GetReturnInvoked())
180 return true;
184 // pop scope on the makefile
185 return true;
188 bool cmFunctionFunctionBlocker::
189 IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
190 cmExecutionStatus &)
192 // record commands until we hit the ENDFUNCTION
193 // at the ENDFUNCTION call we shift gears and start looking for invocations
194 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"function"))
196 this->Depth++;
198 else if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
200 // if this is the endfunction for this function then execute
201 if (!this->Depth)
203 std::string name = this->Args[0];
204 std::vector<std::string>::size_type cc;
205 name += "(";
206 for ( cc = 0; cc < this->Args.size(); cc ++ )
208 name += " " + this->Args[cc];
210 name += " )";
212 // create a new command and add it to cmake
213 cmFunctionHelperCommand *f = new cmFunctionHelperCommand();
214 f->Args = this->Args;
215 f->Functions = this->Functions;
216 mf.RecordPolicies(f->Policies);
218 // Set the FilePath on the arguments to match the function since it is
219 // not stored and the original values may be freed
220 for (unsigned int i = 0; i < f->Functions.size(); ++i)
222 for (unsigned int j = 0; j < f->Functions[i].Arguments.size(); ++j)
224 f->Functions[i].Arguments[j].FilePath =
225 f->Functions[i].FilePath.c_str();
229 std::string newName = "_" + this->Args[0];
230 mf.GetCMakeInstance()->RenameCommand(this->Args[0].c_str(),
231 newName.c_str());
232 mf.AddCommand(f);
234 // remove the function blocker now that the function is defined
235 mf.RemoveFunctionBlocker(this, lff);
236 return true;
238 else
240 // decrement for each nested function that ends
241 this->Depth--;
245 // if it wasn't an endfunction and we are not executing then we must be
246 // recording
247 this->Functions.push_back(lff);
248 return true;
252 bool cmFunctionFunctionBlocker::
253 ShouldRemove(const cmListFileFunction& lff, cmMakefile &mf)
255 if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endfunction"))
257 std::vector<std::string> expandedArguments;
258 mf.ExpandArguments(lff.Arguments, expandedArguments);
259 // if the endfunction has arguments then make sure
260 // they match the ones in the openeing function command
261 if ((expandedArguments.empty() ||
262 (expandedArguments[0] == this->Args[0])))
264 return true;
268 return false;
271 bool cmFunctionCommand
272 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
274 if(args.size() < 1)
276 this->SetError("called with incorrect number of arguments");
277 return false;
280 // create a function blocker
281 cmFunctionFunctionBlocker *f = new cmFunctionFunctionBlocker();
282 for(std::vector<std::string>::const_iterator j = args.begin();
283 j != args.end(); ++j)
285 f->Args.push_back(*j);
287 this->Makefile->AddFunctionBlocker(f);
288 return true;