cmLocalKdevelopGenerator.cxx 14 KB

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