1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmListFileCache.cxx,v $
6 Date: $Date: 2008-03-20 14:46:24 $
7 Version: $Revision: 1.44 $
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 "cmListFileCache.h"
19 #include "cmListFileLexer.h"
20 #include "cmSystemTools.h"
21 #include "cmMakefile.h"
22 #include "cmVersion.h"
24 #include <cmsys/RegularExpression.hxx>
27 # pragma warn -8060 /* possibly incorrect assignment */
30 bool cmListFileCacheParseFunction(cmListFileLexer
* lexer
,
31 cmListFileFunction
& function
,
32 const char* filename
);
34 bool cmListFile::ParseFile(const char* filename
,
38 if(!cmSystemTools::FileExists(filename
))
43 // Create the scanner.
44 cmListFileLexer
* lexer
= cmListFileLexer_New();
47 cmSystemTools::Error("cmListFileCache: error allocating lexer ");
52 if(!cmListFileLexer_SetFileName(lexer
, filename
))
54 cmListFileLexer_Delete(lexer
);
55 cmSystemTools::Error("cmListFileCache: error can not open file ",
60 // Use a simple recursive-descent parser to process the token
62 this->ModifiedTime
= cmSystemTools::ModifiedTime(filename
);
63 bool parseError
= false;
64 bool haveNewline
= true;
65 cmListFileLexer_Token
* token
;
66 while(!parseError
&& (token
= cmListFileLexer_Scan(lexer
)))
68 if(token
->type
== cmListFileLexer_Token_Newline
)
72 else if(token
->type
== cmListFileLexer_Token_Identifier
)
77 cmListFileFunction inFunction
;
78 inFunction
.Name
= token
->text
;
79 inFunction
.FilePath
= filename
;
80 inFunction
.Line
= token
->line
;
81 if(cmListFileCacheParseFunction(lexer
, inFunction
, filename
))
83 this->Functions
.push_back(inFunction
);
92 cmOStringStream error
;
93 error
<< "Error in cmake code at\n"
94 << filename
<< ":" << token
->line
<< ":\n"
95 << "Parse error. Expected a newline, got "
96 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
97 << " with text \"" << token
->text
<< "\".";
98 cmSystemTools::Error(error
.str().c_str());
104 cmOStringStream error
;
105 error
<< "Error in cmake code at\n"
106 << filename
<< ":" << token
->line
<< ":\n"
107 << "Parse error. Expected a command name, got "
108 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
110 << token
->text
<< "\".";
111 cmSystemTools::Error(error
.str().c_str());
117 this->ModifiedTime
= 0;
120 cmListFileLexer_Delete(lexer
);
122 // do we need a cmake_policy(VERSION call?
125 bool hasVersion
= false;
126 // search for the right policy command
127 for(std::vector
<cmListFileFunction
>::iterator i
128 = this->Functions
.begin();
129 i
!= this->Functions
.end(); ++i
)
131 if (cmSystemTools::LowerCase(i
->Name
) == "cmake_minimum_required")
137 // if no policy command is found this is an error if they use any non advanced functions or a lot of functions
140 bool isProblem
= true;
141 if (this->Functions
.size() < 30)
143 // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
144 // these commands must have backwards compatibility forever and
145 // and that is a lot longer than your tiny mind can comprehend mortal
146 std::set
<std::string
> allowedCommands
;
147 allowedCommands
.insert("project");
148 allowedCommands
.insert("set");
149 allowedCommands
.insert("if");
150 allowedCommands
.insert("endif");
151 allowedCommands
.insert("else");
152 allowedCommands
.insert("elseif");
153 allowedCommands
.insert("add_executable");
154 allowedCommands
.insert("add_library");
155 allowedCommands
.insert("target_link_libraries");
156 allowedCommands
.insert("option");
157 allowedCommands
.insert("message");
159 for(std::vector
<cmListFileFunction
>::iterator i
160 = this->Functions
.begin();
161 i
!= this->Functions
.end(); ++i
)
163 std::string name
= cmSystemTools::LowerCase(i
->Name
);
164 if (allowedCommands
.find(name
) == allowedCommands
.end())
175 msg
<< "No cmake_minimum_required command is present. "
176 << "A line of code such as\n"
177 << " cmake_minimum_required(VERSION "
178 << cmVersion::GetMajorVersion() << "."
179 << cmVersion::GetMinorVersion()
181 << "should be added at the top of the file. "
182 << "The version specified may be lower if you wish to "
183 << "support older CMake versions for this project. "
184 << "For more information run "
185 << "\"cmake --help-policy CMP0000\".";
186 switch (mf
->GetPolicyStatus(cmPolicies::CMP0000
))
188 case cmPolicies::WARN
:
189 mf
->IssueMessage(cmake::AUTHOR_WARNING
, msg
.str().c_str());
190 case cmPolicies::OLD
:
191 // Implicitly set the version for the user.
192 mf
->SetPolicyVersion("2.4");
195 mf
->IssueMessage(cmake::FATAL_ERROR
, msg
.str().c_str());
204 bool hasProject
= false;
205 // search for a project command
206 for(std::vector
<cmListFileFunction
>::iterator i
207 = this->Functions
.begin();
208 i
!= this->Functions
.end(); ++i
)
210 if(cmSystemTools::LowerCase(i
->Name
) == "project")
216 // if no project command is found, add one
219 cmListFileFunction project
;
220 project
.Name
= "PROJECT";
221 cmListFileArgument
prj("Project", false, filename
, 0);
222 project
.Arguments
.push_back(prj
);
223 this->Functions
.insert(this->Functions
.begin(),project
);
233 bool cmListFileCacheParseFunction(cmListFileLexer
* lexer
,
234 cmListFileFunction
& function
,
235 const char* filename
)
237 // Command name has already been parsed. Read the left paren.
238 cmListFileLexer_Token
* token
;
239 if(!(token
= cmListFileLexer_Scan(lexer
)))
241 cmOStringStream error
;
242 error
<< "Error in cmake code at\n"
243 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
244 << "Parse error. Function missing opening \"(\".";
245 cmSystemTools::Error(error
.str().c_str());
248 if(token
->type
!= cmListFileLexer_Token_ParenLeft
)
250 cmOStringStream error
;
251 error
<< "Error in cmake code at\n"
252 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
) << ":\n"
253 << "Parse error. Expected \"(\", got "
254 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
255 << " with text \"" << token
->text
<< "\".";
256 cmSystemTools::Error(error
.str().c_str());
261 unsigned long lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
262 while((token
= cmListFileLexer_Scan(lexer
)))
264 if(token
->type
== cmListFileLexer_Token_ParenRight
)
268 else if(token
->type
== cmListFileLexer_Token_Identifier
||
269 token
->type
== cmListFileLexer_Token_ArgumentUnquoted
)
271 cmListFileArgument
a(token
->text
,
272 false, filename
, token
->line
);
273 function
.Arguments
.push_back(a
);
275 else if(token
->type
== cmListFileLexer_Token_ArgumentQuoted
)
277 cmListFileArgument
a(token
->text
,
278 true, filename
, token
->line
);
279 function
.Arguments
.push_back(a
);
281 else if(token
->type
!= cmListFileLexer_Token_Newline
)
284 cmOStringStream error
;
285 error
<< "Error in cmake code at\n"
286 << filename
<< ":" << cmListFileLexer_GetCurrentLine(lexer
)
288 << "Parse error. Function missing ending \")\". "
290 << cmListFileLexer_GetTypeAsString(lexer
, token
->type
)
291 << " with text \"" << token
->text
<< "\".";
292 cmSystemTools::Error(error
.str().c_str());
295 lastLine
= cmListFileLexer_GetCurrentLine(lexer
);
298 cmOStringStream error
;
299 error
<< "Error in cmake code at\n"
300 << filename
<< ":" << lastLine
<< ":\n"
301 << "Parse error. Function missing ending \")\". "
302 << "End of file reached.";
303 cmSystemTools::Error(error
.str().c_str());
308 //----------------------------------------------------------------------------
309 std::ostream
& operator<<(std::ostream
& os
, cmListFileContext
const& lfc
)
314 os
<< ":" << lfc
.Line
;
315 if(!lfc
.Name
.empty())
317 os
<< " (" << lfc
.Name
<< ")";