cmLocalKdevelopGenerator.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. Copyright (c) 2004 Alexander Neundorf, [email protected]. All rights reserved.
  9. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  10. This software is distributed WITHOUT ANY WARRANTY; without even
  11. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. PURPOSE. See the above copyright notices for more information.
  13. =========================================================================*/
  14. #include "cmGlobalGenerator.h"
  15. #include "cmLocalKdevelopGenerator.h"
  16. #include "cmMakefile.h"
  17. #include "cmSystemTools.h"
  18. #include "cmSourceFile.h"
  19. #include "cmMakeDepend.h"
  20. #include "cmCacheManager.h"
  21. #include "cmGeneratedFileStream.h"
  22. #include "cmake.h"
  23. #include <cmsys/RegularExpression.hxx>
  24. cmLocalKdevelopGenerator::cmLocalKdevelopGenerator()
  25. :cmLocalUnixMakefileGenerator()
  26. {
  27. }
  28. cmLocalKdevelopGenerator::~cmLocalKdevelopGenerator()
  29. {
  30. }
  31. void cmLocalKdevelopGenerator::Generate(bool fromTheTop)
  32. {
  33. cmLocalUnixMakefileGenerator::Generate(fromTheTop);
  34. if ( m_GlobalGenerator->GetCMakeInstance()->GetLocal() )
  35. {
  36. return;
  37. }
  38. // Does this local generator contain a PROJECT command
  39. // if so, then generate a kdevelop project for it
  40. if (strcmp(m_Makefile->GetDefinition("PROJECT_BINARY_DIR"), m_Makefile->GetStartOutputDirectory())==0)
  41. {
  42. std::string outputDir=m_Makefile->GetStartOutputDirectory();
  43. std::string projectDir=m_Makefile->GetHomeDirectory();
  44. std::string projectName=m_Makefile->GetProjectName();
  45. std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
  46. if (!this->CreateFilelistFile(outputDir, projectDir, projectName, cmakeFilePattern))
  47. {
  48. return;
  49. }
  50. //try to find the name of an executable so we have something to run from kdevelop
  51. // for now just pick the first executable found
  52. std::string executable;
  53. cmTargets& targets=m_Makefile->GetTargets();
  54. for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++)
  55. {
  56. if (ti->second.GetType()==cmTarget::EXECUTABLE)
  57. {
  58. executable=ti->first;
  59. break;
  60. }
  61. }
  62. this->CreateProjectFile(outputDir, projectDir, projectName, executable, cmakeFilePattern);
  63. }
  64. }
  65. /* create the project file, if it already exists, merge it with the existing one,
  66. otherwise create a new one */
  67. void cmLocalKdevelopGenerator::CreateProjectFile(const std::string& outputDir,
  68. const std::string& projectDir,
  69. const std::string& projectname,
  70. const std::string& executable,
  71. const std::string& cmakeFilePattern)
  72. {
  73. std::string filename=outputDir+"/";
  74. filename+=projectname+".kdevelop";
  75. if (cmSystemTools::FileExists(filename.c_str()))
  76. {
  77. this->MergeProjectFiles(outputDir, projectDir, filename, executable, cmakeFilePattern);
  78. }
  79. else
  80. {
  81. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  82. }
  83. }
  84. void cmLocalKdevelopGenerator::MergeProjectFiles(const std::string& outputDir,
  85. const std::string& projectDir,
  86. const std::string& filename,
  87. const std::string& executable,
  88. const std::string& cmakeFilePattern)
  89. {
  90. std::ifstream oldProjectFile(filename.c_str());
  91. if (!oldProjectFile)
  92. {
  93. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  94. return;
  95. }
  96. /* Read the existing project file (line by line), copy all lines into the
  97. new project file, except the ones which can be reliably set from contents
  98. of the CMakeLists.txt */
  99. std::string tmp;
  100. std::vector<std::string> lines;
  101. while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
  102. {
  103. lines.push_back(tmp);
  104. }
  105. oldProjectFile.close();
  106. cmGeneratedFileStream tempFile(filename.c_str());
  107. tempFile.SetAlwaysCopy(true);
  108. std::ostream& fout = tempFile.GetStream();
  109. if(!fout)
  110. {
  111. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  112. return;
  113. }
  114. for (std::vector<std::string>::const_iterator it=lines.begin();
  115. it!=lines.end(); it++)
  116. {
  117. const char* line=(*it).c_str();
  118. // skip these tags as they are always replaced
  119. if ((strstr(line, "<projectdirectory>")!=0)
  120. || (strstr(line, "<projectmanagement>")!=0)
  121. || (strstr(line, "<absoluteprojectpath>")!=0)
  122. || (strstr(line, "<filelistdirectory>")!=0)
  123. || (strstr(line, "<buildtool>")!=0)
  124. || (strstr(line, "<builddir>")!=0))
  125. {
  126. continue;
  127. }
  128. // output the line from the file if it is not one of the above tags
  129. fout<<*it<<"\n";
  130. // if this is the <general> tag output the stuff that goes in the general tag
  131. if (strstr(line, "<general>"))
  132. {
  133. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  134. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  135. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  136. }
  137. // inside kdevcustomproject the <filelistdirectory> must be put
  138. if (strstr(line, "<kdevcustomproject>"))
  139. {
  140. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  141. }
  142. // buildtool and builddir go inside <build>
  143. if (strstr(line, "<build>"))
  144. {
  145. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  146. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  147. }
  148. }
  149. }
  150. void cmLocalKdevelopGenerator::CreateNewProjectFile(const std::string& outputDir,
  151. const std::string& projectDir,
  152. const std::string& filename,
  153. const std::string& executable,
  154. const std::string& cmakeFilePattern)
  155. {
  156. cmGeneratedFileStream tempFile(filename.c_str());
  157. tempFile.SetAlwaysCopy(true);
  158. std::ostream& fout = tempFile.GetStream();
  159. if(!fout)
  160. {
  161. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  162. return;
  163. }
  164. fout<<"<?xml version = '1.0'?>\n";
  165. fout<<"<kdevelop>\n";
  166. fout<<" <general>\n";
  167. fout<<" <author></author>\n";
  168. fout<<" <email></email>\n";
  169. fout<<" <version>$VERSION$</version>\n";
  170. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  171. fout<<" <primarylanguage>C++</primarylanguage>\n";
  172. fout<<" <ignoreparts/>\n";
  173. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  174. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  175. fout<<" <secondaryLanguages>\n";
  176. fout<<" <language>C</language>\n";
  177. fout<<" </secondaryLanguages>\n";
  178. fout<<" </general>\n";
  179. fout<<" <kdevcustomproject>\n";
  180. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  181. fout<<" <run>\n";
  182. fout<<" <mainprogram>"<<outputDir.c_str()<<"/"<<executable.c_str()<<"</mainprogram>\n";
  183. fout<<" <directoryradio>custom</directoryradio>\n";
  184. fout<<" <customdirectory>/</customdirectory>\n";
  185. fout<<" <programargs></programargs>\n";
  186. fout<<" <terminal>false</terminal>\n";
  187. fout<<" <autocompile>true</autocompile>\n";
  188. fout<<" <envvars/>\n";
  189. fout<<" </run>\n";
  190. fout<<" <build>\n";
  191. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  192. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  193. fout<<" </build>\n";
  194. fout<<" <make>\n";
  195. fout<<" <abortonerror>false</abortonerror>\n";
  196. fout<<" <numberofjobs>1</numberofjobs>\n";
  197. fout<<" <dontact>false</dontact>\n";
  198. fout<<" <makebin></makebin>\n";
  199. fout<<" <selectedenvironment>default</selectedenvironment>\n";
  200. fout<<" <environments>\n";
  201. fout<<" <default/>\n";
  202. fout<<" </environments>\n";
  203. fout<<" </make>\n";
  204. fout<<" </kdevcustomproject>\n";
  205. fout<<" <kdevfilecreate>\n";
  206. fout<<" <filetypes/>\n";
  207. fout<<" <useglobaltypes>\n";
  208. fout<<" <type ext=\"ui\" />\n";
  209. fout<<" <type ext=\"cpp\" />\n";
  210. fout<<" <type ext=\"h\" />\n";
  211. fout<<" </useglobaltypes>\n";
  212. fout<<" </kdevfilecreate>\n";
  213. fout<<" <kdevdoctreeview>\n";
  214. fout<<" <projectdoc>\n";
  215. fout<<" <userdocDir>html/</userdocDir>\n";
  216. fout<<" <apidocDir>html/</apidocDir>\n";
  217. fout<<" </projectdoc>\n";
  218. fout<<" <ignoreqt_xml/>\n";
  219. fout<<" <ignoredoxygen/>\n";
  220. fout<<" <ignorekdocs/>\n";
  221. fout<<" <ignoretocs/>\n";
  222. fout<<" <ignoredevhelp/>\n";
  223. fout<<" </kdevdoctreeview>\n";
  224. fout<<" <cppsupportpart>\n";
  225. fout<<" <filetemplates>\n";
  226. fout<<" <interfacesuffix>.h</interfacesuffix>\n";
  227. fout<<" <implementationsuffix>.cpp</implementationsuffix>\n";
  228. fout<<" </filetemplates>\n";
  229. fout<<" </cppsupportpart>\n";
  230. fout<<" <kdevcppsupport>\n";
  231. fout<<" <codecompletion>\n";
  232. fout<<" <includeGlobalFunctions>true</includeGlobalFunctions>\n";
  233. fout<<" <includeTypes>true</includeTypes>\n";
  234. fout<<" <includeEnums>true</includeEnums>\n";
  235. fout<<" <includeTypedefs>false</includeTypedefs>\n";
  236. fout<<" <automaticCodeCompletion>true</automaticCodeCompletion>\n";
  237. fout<<" <automaticArgumentsHint>true</automaticArgumentsHint>\n";
  238. fout<<" <automaticHeaderCompletion>true</automaticHeaderCompletion>\n";
  239. fout<<" <codeCompletionDelay>250</codeCompletionDelay>\n";
  240. fout<<" <argumentsHintDelay>400</argumentsHintDelay>\n";
  241. fout<<" <headerCompletionDelay>250</headerCompletionDelay>\n";
  242. fout<<" </codecompletion>\n";
  243. fout<<" <references/>\n";
  244. fout<<" </kdevcppsupport>\n";
  245. fout<<" <kdevfileview>\n";
  246. fout<<" <groups>\n";
  247. fout<<" <group pattern=\""<<cmakeFilePattern.c_str()<<"\" name=\"CMake\" />\n";
  248. fout<<" <group pattern=\"*.h;*.hxx\" name=\"Header\" />\n";
  249. fout<<" <group pattern=\"*.cpp;*.c;*.C;*.cxx\" name=\"Sources\" />\n";
  250. fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n";
  251. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  252. fout<<" </groups>\n";
  253. fout<<" <tree>\n";
  254. fout<<" <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n";
  255. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  256. fout<<" </tree>\n";
  257. fout<<" </kdevfileview>\n";
  258. fout<<"</kdevelop>\n";
  259. }
  260. bool cmLocalKdevelopGenerator::CreateFilelistFile(const std::string& outputDir, const std::string& _projectDir,
  261. const std::string& projectname,
  262. std::string& cmakeFilePattern)
  263. {
  264. std::string projectDir=_projectDir+"/";
  265. std::string filename=outputDir+"/"+projectname+".kdevelop.filelist";
  266. std::set<cmStdString> files;
  267. std::string tmp;
  268. // loop over all local generators in the entire project
  269. // This should be moved into the global generator
  270. // FIXME
  271. std::vector<cmLocalGenerator *> lgs;
  272. m_GlobalGenerator->GetLocalGenerators(lgs);
  273. for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin(); it!=lgs.end(); it++)
  274. {
  275. cmMakefile* makefile=(*it)->GetMakefile();
  276. // if the makefile GetStartOutputDirectory is not a substring of the outputDir
  277. // then skip it
  278. if (strstr(makefile->GetStartOutputDirectory(), outputDir.c_str())==0)
  279. {
  280. continue;
  281. }
  282. // This means the makefile is a sub-makefile of the current project
  283. //get all cmake files
  284. const std::vector<std::string>& listFiles=makefile->GetListFiles();
  285. for (std::vector<std::string>::const_iterator lt=listFiles.begin(); lt!=listFiles.end(); lt++)
  286. {
  287. tmp=*lt;
  288. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  289. // make sure the file is part of this source tree
  290. if (tmp[0]!='/')
  291. {
  292. files.insert(tmp);
  293. tmp=cmSystemTools::GetFilenameName(tmp);
  294. //add all files which dont match the default */CMakeLists.txt;*cmake; to the file pattern
  295. if ((tmp!="CMakeLists.txt")
  296. && (strstr(tmp.c_str(), ".cmake")==0))
  297. {
  298. cmakeFilePattern+=tmp+";";
  299. }
  300. }
  301. }
  302. //get all sources
  303. cmTargets& targets=makefile->GetTargets();
  304. for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++)
  305. {
  306. const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();
  307. for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
  308. si!=sources.end(); si++)
  309. {
  310. files.insert((*si)->GetFullPath());
  311. }
  312. for (std::vector<std::string>::const_iterator lt=listFiles.begin();
  313. lt!=listFiles.end(); lt++)
  314. {
  315. tmp=*lt;
  316. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  317. if (tmp[0]!='/')
  318. {
  319. files.insert(tmp.c_str());
  320. }
  321. }
  322. }
  323. }
  324. //check if the output file already exists and read it
  325. //insert all files which exist into the set of files
  326. std::ifstream oldFilelist(filename.c_str());
  327. if (oldFilelist)
  328. {
  329. while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))
  330. {
  331. if (tmp[0]=='/')
  332. {
  333. continue;
  334. }
  335. std::string completePath=projectDir+tmp;
  336. if (cmSystemTools::FileExists(completePath.c_str()))
  337. {
  338. files.insert(tmp);
  339. }
  340. }
  341. oldFilelist.close();
  342. }
  343. //now write the new filename
  344. cmGeneratedFileStream tempFile(filename.c_str());
  345. tempFile.SetAlwaysCopy(true);
  346. std::ostream& fout = tempFile.GetStream();
  347. if(!fout)
  348. {
  349. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  350. return false;
  351. }
  352. for (std::set<cmStdString>::const_iterator it=files.begin(); it!=files.end(); it++)
  353. {
  354. // get the full path to the file
  355. tmp=cmSystemTools::CollapseFullPath(it->c_str());
  356. // make it relative to the project dir
  357. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  358. // only put relative paths
  359. if (tmp.size() && tmp[0] != '/')
  360. {
  361. fout << tmp.c_str() <<"\n";
  362. }
  363. }
  364. return true;
  365. }