cmListFileCache.cxx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
  4. Distributed under the OSI-approved BSD License (the "License");
  5. see accompanying file Copyright.txt for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even the
  7. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  8. See the License for more information.
  9. ============================================================================*/
  10. #include "cmListFileCache.h"
  11. #include "cmListFileLexer.h"
  12. #include "cmSystemTools.h"
  13. #include "cmMakefile.h"
  14. #include "cmVersion.h"
  15. #include <cmsys/RegularExpression.hxx>
  16. #ifdef __BORLANDC__
  17. # pragma warn -8060 /* possibly incorrect assignment */
  18. #endif
  19. bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
  20. cmListFileFunction& function,
  21. const char* filename);
  22. bool cmListFile::ParseFile(const char* filename,
  23. bool topLevel,
  24. cmMakefile *mf)
  25. {
  26. if(!cmSystemTools::FileExists(filename))
  27. {
  28. return false;
  29. }
  30. // Create the scanner.
  31. cmListFileLexer* lexer = cmListFileLexer_New();
  32. if(!lexer)
  33. {
  34. cmSystemTools::Error("cmListFileCache: error allocating lexer ");
  35. return false;
  36. }
  37. // Open the file.
  38. if(!cmListFileLexer_SetFileName(lexer, filename))
  39. {
  40. cmListFileLexer_Delete(lexer);
  41. cmSystemTools::Error("cmListFileCache: error can not open file ",
  42. filename);
  43. return false;
  44. }
  45. // Use a simple recursive-descent parser to process the token
  46. // stream.
  47. this->ModifiedTime = cmSystemTools::ModifiedTime(filename);
  48. bool parseError = false;
  49. bool haveNewline = true;
  50. cmListFileLexer_Token* token;
  51. while(!parseError && (token = cmListFileLexer_Scan(lexer)))
  52. {
  53. if(token->type == cmListFileLexer_Token_Newline)
  54. {
  55. haveNewline = true;
  56. }
  57. else if(token->type == cmListFileLexer_Token_Identifier)
  58. {
  59. if(haveNewline)
  60. {
  61. haveNewline = false;
  62. cmListFileFunction inFunction;
  63. inFunction.Name = token->text;
  64. inFunction.FilePath = filename;
  65. inFunction.Line = token->line;
  66. if(cmListFileCacheParseFunction(lexer, inFunction, filename))
  67. {
  68. this->Functions.push_back(inFunction);
  69. }
  70. else
  71. {
  72. parseError = true;
  73. }
  74. }
  75. else
  76. {
  77. cmOStringStream error;
  78. error << "Error in cmake code at\n"
  79. << filename << ":" << token->line << ":\n"
  80. << "Parse error. Expected a newline, got "
  81. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  82. << " with text \"" << token->text << "\".";
  83. cmSystemTools::Error(error.str().c_str());
  84. parseError = true;
  85. }
  86. }
  87. else
  88. {
  89. cmOStringStream error;
  90. error << "Error in cmake code at\n"
  91. << filename << ":" << token->line << ":\n"
  92. << "Parse error. Expected a command name, got "
  93. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  94. << " with text \""
  95. << token->text << "\".";
  96. cmSystemTools::Error(error.str().c_str());
  97. parseError = true;
  98. }
  99. }
  100. if (parseError)
  101. {
  102. this->ModifiedTime = 0;
  103. }
  104. cmListFileLexer_Delete(lexer);
  105. // do we need a cmake_policy(VERSION call?
  106. if(topLevel)
  107. {
  108. bool hasVersion = false;
  109. // search for the right policy command
  110. for(std::vector<cmListFileFunction>::iterator i
  111. = this->Functions.begin();
  112. i != this->Functions.end(); ++i)
  113. {
  114. if (cmSystemTools::LowerCase(i->Name) == "cmake_minimum_required")
  115. {
  116. hasVersion = true;
  117. break;
  118. }
  119. }
  120. // if no policy command is found this is an error if they use any
  121. // non advanced functions or a lot of functions
  122. if(!hasVersion)
  123. {
  124. bool isProblem = true;
  125. if (this->Functions.size() < 30)
  126. {
  127. // the list of simple commands DO NOT ADD TO THIS LIST!!!!!
  128. // these commands must have backwards compatibility forever and
  129. // and that is a lot longer than your tiny mind can comprehend mortal
  130. std::set<std::string> allowedCommands;
  131. allowedCommands.insert("project");
  132. allowedCommands.insert("set");
  133. allowedCommands.insert("if");
  134. allowedCommands.insert("endif");
  135. allowedCommands.insert("else");
  136. allowedCommands.insert("elseif");
  137. allowedCommands.insert("add_executable");
  138. allowedCommands.insert("add_library");
  139. allowedCommands.insert("target_link_libraries");
  140. allowedCommands.insert("option");
  141. allowedCommands.insert("message");
  142. isProblem = false;
  143. for(std::vector<cmListFileFunction>::iterator i
  144. = this->Functions.begin();
  145. i != this->Functions.end(); ++i)
  146. {
  147. std::string name = cmSystemTools::LowerCase(i->Name);
  148. if (allowedCommands.find(name) == allowedCommands.end())
  149. {
  150. isProblem = true;
  151. break;
  152. }
  153. }
  154. }
  155. if (isProblem)
  156. {
  157. // Tell the top level cmMakefile to diagnose
  158. // this violation of CMP0000.
  159. mf->SetCheckCMP0000(true);
  160. // Implicitly set the version for the user.
  161. mf->SetPolicyVersion("2.4");
  162. }
  163. }
  164. }
  165. if(topLevel)
  166. {
  167. bool hasProject = false;
  168. // search for a project command
  169. for(std::vector<cmListFileFunction>::iterator i
  170. = this->Functions.begin();
  171. i != this->Functions.end(); ++i)
  172. {
  173. if(cmSystemTools::LowerCase(i->Name) == "project")
  174. {
  175. hasProject = true;
  176. break;
  177. }
  178. }
  179. // if no project command is found, add one
  180. if(!hasProject)
  181. {
  182. cmListFileFunction project;
  183. project.Name = "PROJECT";
  184. cmListFileArgument prj("Project", false, filename, 0);
  185. project.Arguments.push_back(prj);
  186. this->Functions.insert(this->Functions.begin(),project);
  187. }
  188. }
  189. if(parseError)
  190. {
  191. return false;
  192. }
  193. return true;
  194. }
  195. bool cmListFileCacheParseFunction(cmListFileLexer* lexer,
  196. cmListFileFunction& function,
  197. const char* filename)
  198. {
  199. // Command name has already been parsed. Read the left paren.
  200. cmListFileLexer_Token* token;
  201. if(!(token = cmListFileLexer_Scan(lexer)))
  202. {
  203. cmOStringStream error;
  204. error << "Error in cmake code at\n"
  205. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  206. << "Parse error. Function missing opening \"(\".";
  207. cmSystemTools::Error(error.str().c_str());
  208. return false;
  209. }
  210. if(token->type != cmListFileLexer_Token_ParenLeft)
  211. {
  212. cmOStringStream error;
  213. error << "Error in cmake code at\n"
  214. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer) << ":\n"
  215. << "Parse error. Expected \"(\", got "
  216. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  217. << " with text \"" << token->text << "\".";
  218. cmSystemTools::Error(error.str().c_str());
  219. return false;
  220. }
  221. // Arguments.
  222. unsigned long lastLine = cmListFileLexer_GetCurrentLine(lexer);
  223. unsigned long parenDepth = 0;
  224. while((token = cmListFileLexer_Scan(lexer)))
  225. {
  226. if(token->type == cmListFileLexer_Token_ParenLeft)
  227. {
  228. parenDepth++;
  229. cmListFileArgument a("(",
  230. false, filename, token->line);
  231. function.Arguments.push_back(a);
  232. }
  233. else if(token->type == cmListFileLexer_Token_ParenRight)
  234. {
  235. if (parenDepth == 0)
  236. {
  237. return true;
  238. }
  239. parenDepth--;
  240. cmListFileArgument a(")",
  241. false, filename, token->line);
  242. function.Arguments.push_back(a);
  243. }
  244. else if(token->type == cmListFileLexer_Token_Identifier ||
  245. token->type == cmListFileLexer_Token_ArgumentUnquoted)
  246. {
  247. cmListFileArgument a(token->text,
  248. false, filename, token->line);
  249. function.Arguments.push_back(a);
  250. }
  251. else if(token->type == cmListFileLexer_Token_ArgumentQuoted)
  252. {
  253. cmListFileArgument a(token->text,
  254. true, filename, token->line);
  255. function.Arguments.push_back(a);
  256. }
  257. else if(token->type != cmListFileLexer_Token_Newline)
  258. {
  259. // Error.
  260. cmOStringStream error;
  261. error << "Error in cmake code at\n"
  262. << filename << ":" << cmListFileLexer_GetCurrentLine(lexer)
  263. << ":\n"
  264. << "Parse error. Function missing ending \")\". "
  265. << "Instead found "
  266. << cmListFileLexer_GetTypeAsString(lexer, token->type)
  267. << " with text \"" << token->text << "\".";
  268. cmSystemTools::Error(error.str().c_str());
  269. return false;
  270. }
  271. lastLine = cmListFileLexer_GetCurrentLine(lexer);
  272. }
  273. cmOStringStream error;
  274. error << "Error in cmake code at\n"
  275. << filename << ":" << lastLine << ":\n"
  276. << "Parse error. Function missing ending \")\". "
  277. << "End of file reached.";
  278. cmSystemTools::Error(error.str().c_str());
  279. return false;
  280. }
  281. //----------------------------------------------------------------------------
  282. std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
  283. {
  284. os << lfc.FilePath;
  285. if(lfc.Line)
  286. {
  287. os << ":" << lfc.Line;
  288. if(!lfc.Name.empty())
  289. {
  290. os << " (" << lfc.Name << ")";
  291. }
  292. }
  293. return os;
  294. }