cmLocalKdevelopGenerator.cxx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  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. void cmLocalKdevelopGenerator::CreateProjectFile(const std::string& outputDir,
  66. const std::string& projectDir,
  67. const std::string& projectname,
  68. const std::string& executable,
  69. const std::string& cmakeFilePattern)
  70. {
  71. std::string filename=outputDir+"/";
  72. filename+=projectname+".kdevelop";
  73. if (cmSystemTools::FileExists(filename.c_str()))
  74. {
  75. this->MergeProjectFiles(outputDir, projectDir, filename, executable, cmakeFilePattern);
  76. }
  77. else
  78. {
  79. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  80. }
  81. }
  82. void cmLocalKdevelopGenerator::MergeProjectFiles(const std::string& outputDir,
  83. const std::string& projectDir,
  84. const std::string& filename,
  85. const std::string& executable,
  86. const std::string& cmakeFilePattern)
  87. {
  88. std::ifstream oldProjectFile(filename.c_str());
  89. if (!oldProjectFile)
  90. {
  91. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  92. return;
  93. }
  94. std::string tmp;
  95. std::vector<std::string> lines;
  96. while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
  97. {
  98. lines.push_back(tmp);
  99. }
  100. oldProjectFile.close();
  101. cmGeneratedFileStream tempFile(filename.c_str());
  102. tempFile.SetAlwaysCopy(true);
  103. std::ostream& fout = tempFile.GetStream();
  104. if(!fout)
  105. {
  106. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  107. return;
  108. }
  109. for (std::vector<std::string>::const_iterator it=lines.begin();
  110. it!=lines.end(); it++)
  111. {
  112. const char* line=(*it).c_str();
  113. // skip these tags as they are always replaced
  114. if ((strstr(line, "<projectdirectory>")!=0)
  115. || (strstr(line, "<projectmanagement>")!=0)
  116. || (strstr(line, "<absoluteprojectpath>")!=0)
  117. || (strstr(line, "<filelistdirectory>")!=0)
  118. || (strstr(line, "<buildtool>")!=0)
  119. || (strstr(line, "<builddir>")!=0))
  120. {
  121. continue;
  122. }
  123. // output the line from the file if it is not one of the above tags
  124. fout<<*it<<"\n";
  125. // if this is the <general> tag output the stuff that goes in the general tag
  126. if (strstr(line, "<general>"))
  127. {
  128. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  129. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  130. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  131. }
  132. // inside kdevcustomproject the <filelistdirectory> must be put
  133. if (strstr(line, "<kdevcustomproject>"))
  134. {
  135. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  136. }
  137. // buildtool and builddir go inside <build>
  138. if (strstr(line, "<build>"))
  139. {
  140. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  141. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  142. }
  143. }
  144. }
  145. void cmLocalKdevelopGenerator::CreateNewProjectFile(const std::string& outputDir,
  146. const std::string& projectDir,
  147. const std::string& filename,
  148. const std::string& executable,
  149. const std::string& cmakeFilePattern)
  150. {
  151. cmGeneratedFileStream tempFile(filename.c_str());
  152. tempFile.SetAlwaysCopy(true);
  153. std::ostream& fout = tempFile.GetStream();
  154. if(!fout)
  155. {
  156. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  157. return;
  158. }
  159. fout<<"<?xml version = '1.0'?>\n";
  160. fout<<"<kdevelop>\n";
  161. fout<<" <general>\n";
  162. fout<<" <author></author>\n";
  163. fout<<" <email></email>\n";
  164. fout<<" <version>$VERSION$</version>\n";
  165. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  166. fout<<" <primarylanguage>C++</primarylanguage>\n";
  167. fout<<" <ignoreparts/>\n";
  168. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  169. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  170. fout<<" <secondaryLanguages>\n";
  171. fout<<" <language>C</language>\n";
  172. fout<<" </secondaryLanguages>\n";
  173. fout<<" </general>\n";
  174. fout<<" <kdevcustomproject>\n";
  175. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  176. fout<<" <run>\n";
  177. fout<<" <mainprogram>"<<outputDir.c_str()<<"/"<<executable.c_str()<<"</mainprogram>\n";
  178. fout<<" <directoryradio>custom</directoryradio>\n";
  179. fout<<" <customdirectory>/</customdirectory>\n";
  180. fout<<" <programargs></programargs>\n";
  181. fout<<" <terminal>false</terminal>\n";
  182. fout<<" <autocompile>true</autocompile>\n";
  183. fout<<" <envvars/>\n";
  184. fout<<" </run>\n";
  185. fout<<" <build>\n";
  186. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  187. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  188. fout<<" </build>\n";
  189. fout<<" <make>\n";
  190. fout<<" <abortonerror>false</abortonerror>\n";
  191. fout<<" <numberofjobs>1</numberofjobs>\n";
  192. fout<<" <dontact>false</dontact>\n";
  193. fout<<" <makebin></makebin>\n";
  194. fout<<" <selectedenvironment>default</selectedenvironment>\n";
  195. fout<<" <environments>\n";
  196. fout<<" <default/>\n";
  197. fout<<" </environments>\n";
  198. fout<<" </make>\n";
  199. fout<<" </kdevcustomproject>\n";
  200. fout<<" <kdevfilecreate>\n";
  201. fout<<" <filetypes/>\n";
  202. fout<<" <useglobaltypes>\n";
  203. fout<<" <type ext=\"ui\" />\n";
  204. fout<<" <type ext=\"cpp\" />\n";
  205. fout<<" <type ext=\"h\" />\n";
  206. fout<<" </useglobaltypes>\n";
  207. fout<<" </kdevfilecreate>\n";
  208. fout<<" <kdevdoctreeview>\n";
  209. fout<<" <projectdoc>\n";
  210. fout<<" <userdocDir>html/</userdocDir>\n";
  211. fout<<" <apidocDir>html/</apidocDir>\n";
  212. fout<<" </projectdoc>\n";
  213. fout<<" <ignoreqt_xml/>\n";
  214. fout<<" <ignoredoxygen/>\n";
  215. fout<<" <ignorekdocs/>\n";
  216. fout<<" <ignoretocs/>\n";
  217. fout<<" <ignoredevhelp/>\n";
  218. fout<<" </kdevdoctreeview>\n";
  219. fout<<" <cppsupportpart>\n";
  220. fout<<" <filetemplates>\n";
  221. fout<<" <interfacesuffix>.h</interfacesuffix>\n";
  222. fout<<" <implementationsuffix>.cpp</implementationsuffix>\n";
  223. fout<<" </filetemplates>\n";
  224. fout<<" </cppsupportpart>\n";
  225. fout<<" <kdevcppsupport>\n";
  226. fout<<" <codecompletion>\n";
  227. fout<<" <includeGlobalFunctions>true</includeGlobalFunctions>\n";
  228. fout<<" <includeTypes>true</includeTypes>\n";
  229. fout<<" <includeEnums>true</includeEnums>\n";
  230. fout<<" <includeTypedefs>false</includeTypedefs>\n";
  231. fout<<" <automaticCodeCompletion>true</automaticCodeCompletion>\n";
  232. fout<<" <automaticArgumentsHint>true</automaticArgumentsHint>\n";
  233. fout<<" <automaticHeaderCompletion>true</automaticHeaderCompletion>\n";
  234. fout<<" <codeCompletionDelay>250</codeCompletionDelay>\n";
  235. fout<<" <argumentsHintDelay>400</argumentsHintDelay>\n";
  236. fout<<" <headerCompletionDelay>250</headerCompletionDelay>\n";
  237. fout<<" </codecompletion>\n";
  238. fout<<" <references/>\n";
  239. fout<<" </kdevcppsupport>\n";
  240. fout<<" <kdevfileview>\n";
  241. fout<<" <groups>\n";
  242. fout<<" <group pattern=\""<<cmakeFilePattern.c_str()<<"\" name=\"CMake\" />\n";
  243. fout<<" <group pattern=\"*.h;*.hxx\" name=\"Header\" />\n";
  244. fout<<" <group pattern=\"*.cpp;*.c;*.C;*.cxx\" name=\"Sources\" />\n";
  245. fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n";
  246. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  247. fout<<" </groups>\n";
  248. fout<<" <tree>\n";
  249. fout<<" <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n";
  250. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  251. fout<<" </tree>\n";
  252. fout<<" </kdevfileview>\n";
  253. fout<<"</kdevelop>\n";
  254. }
  255. bool cmLocalKdevelopGenerator::CreateFilelistFile(const std::string& outputDir, const std::string& _projectDir,
  256. const std::string& projectname,
  257. std::string& cmakeFilePattern)
  258. {
  259. std::string projectDir=_projectDir+"/";
  260. std::string filename=outputDir+"/"+projectname+".kdevelop.filelist";
  261. std::set<cmStdString> files;
  262. std::string tmp;
  263. // loop over all local generators in the entire project
  264. // This should be moved into the global generator
  265. // FIXME
  266. std::vector<cmLocalGenerator *> lgs;
  267. m_GlobalGenerator->GetLocalGenerators(lgs);
  268. for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin(); it!=lgs.end(); it++)
  269. {
  270. cmMakefile* makefile=(*it)->GetMakefile();
  271. // if the makefile GetStartOutputDirectory is not a substring of the outputDir
  272. // then skip it
  273. if (strstr(makefile->GetStartOutputDirectory(), outputDir.c_str())==0)
  274. {
  275. continue;
  276. }
  277. // This means the makefile is a sub-makefile of the current project
  278. //get all cmake files
  279. const std::vector<std::string>& listFiles=makefile->GetListFiles();
  280. for (std::vector<std::string>::const_iterator lt=listFiles.begin(); lt!=listFiles.end(); lt++)
  281. {
  282. tmp=*lt;
  283. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  284. // make sure the file is part of this source tree
  285. if (tmp[0]!='/')
  286. {
  287. files.insert(tmp);
  288. tmp=cmSystemTools::GetFilenameName(tmp);
  289. //add all files which dont match the default */CMakeLists.txt;*cmake; to the file pattern
  290. if ((tmp!="CMakeLists.txt")
  291. && (strstr(tmp.c_str(), ".cmake")==0))
  292. {
  293. cmakeFilePattern+=tmp+";";
  294. }
  295. }
  296. }
  297. //get all sources
  298. cmTargets& targets=makefile->GetTargets();
  299. for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++)
  300. {
  301. const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();
  302. for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
  303. si!=sources.end(); si++)
  304. {
  305. files.insert((*si)->GetFullPath());
  306. }
  307. for (std::vector<std::string>::const_iterator lt=listFiles.begin();
  308. lt!=listFiles.end(); lt++)
  309. {
  310. tmp=*lt;
  311. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  312. if (tmp[0]!='/')
  313. {
  314. files.insert(tmp.c_str());
  315. }
  316. }
  317. }
  318. }
  319. //check if the output file already exists and read it
  320. //insert all files which exist into the set of files
  321. std::ifstream oldFilelist(filename.c_str());
  322. if (oldFilelist)
  323. {
  324. while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))
  325. {
  326. if (tmp[0]=='/')
  327. {
  328. continue;
  329. }
  330. std::string completePath=projectDir+tmp;
  331. if (cmSystemTools::FileExists(completePath.c_str()))
  332. {
  333. files.insert(tmp);
  334. }
  335. }
  336. oldFilelist.close();
  337. }
  338. cmGeneratedFileStream tempFile(filename.c_str());
  339. tempFile.SetAlwaysCopy(true);
  340. std::ostream& fout = tempFile.GetStream();
  341. if(!fout)
  342. {
  343. cmSystemTools::Error("Error can not open for write: ", filename.c_str());
  344. return false;
  345. }
  346. for (std::set<cmStdString>::const_iterator it=files.begin(); it!=files.end(); it++)
  347. {
  348. // get the full path to the file
  349. tmp=cmSystemTools::CollapseFullPath(it->c_str());
  350. // make it relative to the project dir
  351. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  352. // only put relative paths
  353. if (tmp.size() && tmp[0] != '/')
  354. {
  355. fout << tmp.c_str() <<"\n";
  356. }
  357. }
  358. return true;
  359. }