cmLocalKdevelopGenerator.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. // Ideas for moving this stuff into the global generator
  25. // Right now in your local generator you read and write a file to build
  26. // up a list of all files in the project.
  27. // Basically, there does not need to be a local kdevlop generator at all,
  28. // it can just use the unix makefile one. Then in the global generators
  29. // Generate method you do something like this:
  30. // unsigned int i;
  31. // for(i = 0; i < m_LocalGenerators.size(); ++i)
  32. // {
  33. // // Get list of targets and sources from local generator i
  34. // // add them to a file map like you do now in the local generator
  35. // }
  36. // // now write out the Project.filelist file and Project.kdevlop files
  37. // It should most likely do the same thing as the visual studio generators and
  38. // write out all the sub-projects as well. And also honor the exclude from above
  39. // option.
  40. // I guess at the end of the day it should do something like this:
  41. // TopProject.kdevelop
  42. // TopProject.kdevelop.filelist
  43. // SubProject/SubProject.kdevelop
  44. // SubProject/SubProject.kdevelop.filelist
  45. // if SubProject was in a SUBDIR(EXCLUDE_FROM_ALL SubProject)
  46. // then its files should not be in TopProject.filelist.
  47. // If you look at these functions you can see how the visual studio
  48. // cmGlobalVisualStudio7Generator::Generate() // generate the project
  49. // void cmGlobalVisualStudio7Generator::CollectSubprojects() // create a map of project names to local
  50. // // generators
  51. // void cmGlobalVisualStudio7Generator::OutputSLNFile(cmLocalGenerator* root,
  52. // std::vector<cmLocalGenerator*>& generators)
  53. // // output a project for each project and sub project
  54. cmLocalKdevelopGenerator::cmLocalKdevelopGenerator()
  55. :cmLocalUnixMakefileGenerator()
  56. {
  57. }
  58. cmLocalKdevelopGenerator::~cmLocalKdevelopGenerator()
  59. {
  60. }
  61. void cmLocalKdevelopGenerator::Generate(bool fromTheTop)
  62. {
  63. cmLocalUnixMakefileGenerator::Generate(fromTheTop);
  64. if ( m_GlobalGenerator->GetCMakeInstance()->GetLocal() )
  65. {
  66. return;
  67. }
  68. // Does this local generator contain a PROJECT command
  69. // if so, then generate a kdevelop project for it
  70. if (strcmp(m_Makefile->GetDefinition("PROJECT_BINARY_DIR"), m_Makefile->GetStartOutputDirectory())==0)
  71. {
  72. std::string outputDir=m_Makefile->GetStartOutputDirectory();
  73. std::string projectDir=m_Makefile->GetHomeDirectory();
  74. std::string projectName=m_Makefile->GetProjectName();
  75. std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
  76. if (!this->CreateFilelistFile(outputDir, projectDir, projectName, cmakeFilePattern))
  77. {
  78. return;
  79. }
  80. //try to find the name of an executable so we have something to run from kdevelop
  81. // for now just pick the first executable found
  82. std::string executable;
  83. cmTargets& targets=m_Makefile->GetTargets();
  84. for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++)
  85. {
  86. if (ti->second.GetType()==cmTarget::EXECUTABLE)
  87. {
  88. executable=ti->first;
  89. break;
  90. }
  91. }
  92. this->CreateProjectFile(outputDir, projectDir, projectName, executable, cmakeFilePattern);
  93. }
  94. }
  95. /* create the project file, if it already exists, merge it with the existing one,
  96. otherwise create a new one */
  97. void cmLocalKdevelopGenerator::CreateProjectFile(const std::string& outputDir,
  98. const std::string& projectDir,
  99. const std::string& projectname,
  100. const std::string& executable,
  101. const std::string& cmakeFilePattern)
  102. {
  103. std::string filename=outputDir+"/";
  104. filename+=projectname+".kdevelop";
  105. if (cmSystemTools::FileExists(filename.c_str()))
  106. {
  107. this->MergeProjectFiles(outputDir, projectDir, filename, executable, cmakeFilePattern);
  108. }
  109. else
  110. {
  111. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  112. }
  113. }
  114. void cmLocalKdevelopGenerator::MergeProjectFiles(const std::string& outputDir,
  115. const std::string& projectDir,
  116. const std::string& filename,
  117. const std::string& executable,
  118. const std::string& cmakeFilePattern)
  119. {
  120. std::ifstream oldProjectFile(filename.c_str());
  121. if (!oldProjectFile)
  122. {
  123. this->CreateNewProjectFile(outputDir, projectDir, filename, executable, cmakeFilePattern);
  124. return;
  125. }
  126. /* Read the existing project file (line by line), copy all lines into the
  127. new project file, except the ones which can be reliably set from contents
  128. of the CMakeLists.txt */
  129. std::string tmp;
  130. std::vector<std::string> lines;
  131. while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp))
  132. {
  133. lines.push_back(tmp);
  134. }
  135. oldProjectFile.close();
  136. cmGeneratedFileStream fout(filename.c_str());
  137. if(!fout)
  138. {
  139. return;
  140. }
  141. for (std::vector<std::string>::const_iterator it=lines.begin();
  142. it!=lines.end(); it++)
  143. {
  144. const char* line=(*it).c_str();
  145. // skip these tags as they are always replaced
  146. if ((strstr(line, "<projectdirectory>")!=0)
  147. || (strstr(line, "<projectmanagement>")!=0)
  148. || (strstr(line, "<absoluteprojectpath>")!=0)
  149. || (strstr(line, "<filelistdirectory>")!=0)
  150. || (strstr(line, "<buildtool>")!=0)
  151. || (strstr(line, "<builddir>")!=0))
  152. {
  153. continue;
  154. }
  155. // output the line from the file if it is not one of the above tags
  156. fout<<*it<<"\n";
  157. // if this is the <general> tag output the stuff that goes in the general tag
  158. if (strstr(line, "<general>"))
  159. {
  160. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  161. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  162. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  163. }
  164. // inside kdevcustomproject the <filelistdirectory> must be put
  165. if (strstr(line, "<kdevcustomproject>"))
  166. {
  167. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  168. }
  169. // buildtool and builddir go inside <build>
  170. if (strstr(line, "<build>"))
  171. {
  172. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  173. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  174. }
  175. }
  176. }
  177. void cmLocalKdevelopGenerator::CreateNewProjectFile(const std::string& outputDir,
  178. const std::string& projectDir,
  179. const std::string& filename,
  180. const std::string& executable,
  181. const std::string& cmakeFilePattern)
  182. {
  183. cmGeneratedFileStream fout(filename.c_str());
  184. if(!fout)
  185. {
  186. return;
  187. }
  188. fout<<"<?xml version = '1.0'?>\n";
  189. fout<<"<kdevelop>\n";
  190. fout<<" <general>\n";
  191. fout<<" <author></author>\n";
  192. fout<<" <email></email>\n";
  193. fout<<" <version>$VERSION$</version>\n";
  194. fout<<" <projectmanagement>KDevCustomProject</projectmanagement>\n";
  195. fout<<" <primarylanguage>C++</primarylanguage>\n";
  196. fout<<" <ignoreparts/>\n";
  197. fout<<" <projectdirectory>"<<projectDir.c_str()<<"</projectdirectory>\n"; //this one is important
  198. fout<<" <absoluteprojectpath>true</absoluteprojectpath>\n"; //and this one
  199. fout<<" <secondaryLanguages>\n";
  200. fout<<" <language>C</language>\n";
  201. fout<<" </secondaryLanguages>\n";
  202. fout<<" </general>\n";
  203. fout<<" <kdevcustomproject>\n";
  204. fout<<" <filelistdirectory>"<<outputDir.c_str()<<"</filelistdirectory>\n";
  205. fout<<" <run>\n";
  206. fout<<" <mainprogram>"<<outputDir.c_str()<<"/"<<executable.c_str()<<"</mainprogram>\n";
  207. fout<<" <directoryradio>custom</directoryradio>\n";
  208. fout<<" <customdirectory>/</customdirectory>\n";
  209. fout<<" <programargs></programargs>\n";
  210. fout<<" <terminal>false</terminal>\n";
  211. fout<<" <autocompile>true</autocompile>\n";
  212. fout<<" <envvars/>\n";
  213. fout<<" </run>\n";
  214. fout<<" <build>\n";
  215. fout<<" <buildtool>make</buildtool>\n"; //this one is important
  216. fout<<" <builddir>"<<outputDir.c_str()<<"</builddir>\n"; //and this one
  217. fout<<" </build>\n";
  218. fout<<" <make>\n";
  219. fout<<" <abortonerror>false</abortonerror>\n";
  220. fout<<" <numberofjobs>1</numberofjobs>\n";
  221. fout<<" <dontact>false</dontact>\n";
  222. fout<<" <makebin></makebin>\n";
  223. fout<<" <selectedenvironment>default</selectedenvironment>\n";
  224. fout<<" <environments>\n";
  225. fout<<" <default/>\n";
  226. fout<<" </environments>\n";
  227. fout<<" </make>\n";
  228. fout<<" </kdevcustomproject>\n";
  229. fout<<" <kdevfilecreate>\n";
  230. fout<<" <filetypes/>\n";
  231. fout<<" <useglobaltypes>\n";
  232. fout<<" <type ext=\"ui\" />\n";
  233. fout<<" <type ext=\"cpp\" />\n";
  234. fout<<" <type ext=\"h\" />\n";
  235. fout<<" </useglobaltypes>\n";
  236. fout<<" </kdevfilecreate>\n";
  237. fout<<" <kdevdoctreeview>\n";
  238. fout<<" <projectdoc>\n";
  239. fout<<" <userdocDir>html/</userdocDir>\n";
  240. fout<<" <apidocDir>html/</apidocDir>\n";
  241. fout<<" </projectdoc>\n";
  242. fout<<" <ignoreqt_xml/>\n";
  243. fout<<" <ignoredoxygen/>\n";
  244. fout<<" <ignorekdocs/>\n";
  245. fout<<" <ignoretocs/>\n";
  246. fout<<" <ignoredevhelp/>\n";
  247. fout<<" </kdevdoctreeview>\n";
  248. fout<<" <cppsupportpart>\n";
  249. fout<<" <filetemplates>\n";
  250. fout<<" <interfacesuffix>.h</interfacesuffix>\n";
  251. fout<<" <implementationsuffix>.cpp</implementationsuffix>\n";
  252. fout<<" </filetemplates>\n";
  253. fout<<" </cppsupportpart>\n";
  254. fout<<" <kdevcppsupport>\n";
  255. fout<<" <codecompletion>\n";
  256. fout<<" <includeGlobalFunctions>true</includeGlobalFunctions>\n";
  257. fout<<" <includeTypes>true</includeTypes>\n";
  258. fout<<" <includeEnums>true</includeEnums>\n";
  259. fout<<" <includeTypedefs>false</includeTypedefs>\n";
  260. fout<<" <automaticCodeCompletion>true</automaticCodeCompletion>\n";
  261. fout<<" <automaticArgumentsHint>true</automaticArgumentsHint>\n";
  262. fout<<" <automaticHeaderCompletion>true</automaticHeaderCompletion>\n";
  263. fout<<" <codeCompletionDelay>250</codeCompletionDelay>\n";
  264. fout<<" <argumentsHintDelay>400</argumentsHintDelay>\n";
  265. fout<<" <headerCompletionDelay>250</headerCompletionDelay>\n";
  266. fout<<" </codecompletion>\n";
  267. fout<<" <references/>\n";
  268. fout<<" </kdevcppsupport>\n";
  269. fout<<" <kdevfileview>\n";
  270. fout<<" <groups>\n";
  271. fout<<" <group pattern=\""<<cmakeFilePattern.c_str()<<"\" name=\"CMake\" />\n";
  272. fout<<" <group pattern=\"*.h;*.hxx\" name=\"Header\" />\n";
  273. fout<<" <group pattern=\"*.cpp;*.c;*.C;*.cxx\" name=\"Sources\" />\n";
  274. fout<<" <group pattern=\"*.ui\" name=\"Qt Designer files\" />\n";
  275. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  276. fout<<" </groups>\n";
  277. fout<<" <tree>\n";
  278. fout<<" <hidepatterns>*.o,*.lo,CVS,*~,cmake*</hidepatterns>\n";
  279. fout<<" <hidenonprojectfiles>true</hidenonprojectfiles>\n";
  280. fout<<" </tree>\n";
  281. fout<<" </kdevfileview>\n";
  282. fout<<"</kdevelop>\n";
  283. }
  284. bool cmLocalKdevelopGenerator::CreateFilelistFile(const std::string& outputDir, const std::string& _projectDir,
  285. const std::string& projectname,
  286. std::string& cmakeFilePattern)
  287. {
  288. std::string projectDir=_projectDir+"/";
  289. std::string filename=outputDir+"/"+projectname+".kdevelop.filelist";
  290. std::set<cmStdString> files;
  291. std::string tmp;
  292. // loop over all local generators in the entire project
  293. // This should be moved into the global generator
  294. // FIXME
  295. std::vector<cmLocalGenerator *> lgs;
  296. m_GlobalGenerator->GetLocalGenerators(lgs);
  297. for (std::vector<cmLocalGenerator*>::const_iterator it=lgs.begin(); it!=lgs.end(); it++)
  298. {
  299. cmMakefile* makefile=(*it)->GetMakefile();
  300. // if the makefile GetStartOutputDirectory is not a substring of the outputDir
  301. // then skip it
  302. if (strstr(makefile->GetStartOutputDirectory(), outputDir.c_str())==0)
  303. {
  304. continue;
  305. }
  306. // This means the makefile is a sub-makefile of the current project
  307. //get all cmake files
  308. const std::vector<std::string>& listFiles=makefile->GetListFiles();
  309. for (std::vector<std::string>::const_iterator lt=listFiles.begin(); lt!=listFiles.end(); lt++)
  310. {
  311. tmp=*lt;
  312. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  313. // make sure the file is part of this source tree
  314. if (tmp[0]!='/')
  315. {
  316. files.insert(tmp);
  317. tmp=cmSystemTools::GetFilenameName(tmp);
  318. //add all files which dont match the default */CMakeLists.txt;*cmake; to the file pattern
  319. if ((tmp!="CMakeLists.txt")
  320. && (strstr(tmp.c_str(), ".cmake")==0))
  321. {
  322. cmakeFilePattern+=tmp+";";
  323. }
  324. }
  325. }
  326. //get all sources
  327. cmTargets& targets=makefile->GetTargets();
  328. for (cmTargets::const_iterator ti = targets.begin(); ti != targets.end(); ti++)
  329. {
  330. const std::vector<cmSourceFile*>& sources=ti->second.GetSourceFiles();
  331. for (std::vector<cmSourceFile*>::const_iterator si=sources.begin();
  332. si!=sources.end(); si++)
  333. {
  334. tmp=(*si)->GetFullPath();
  335. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  336. if (tmp[0]!='/')
  337. {
  338. files.insert(tmp);
  339. }
  340. }
  341. for (std::vector<std::string>::const_iterator lt=listFiles.begin();
  342. lt!=listFiles.end(); lt++)
  343. {
  344. tmp=*lt;
  345. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  346. if (tmp[0]!='/')
  347. {
  348. files.insert(tmp.c_str());
  349. }
  350. }
  351. }
  352. }
  353. //check if the output file already exists and read it
  354. //insert all files which exist into the set of files
  355. std::ifstream oldFilelist(filename.c_str());
  356. if (oldFilelist)
  357. {
  358. while (cmSystemTools::GetLineFromStream(oldFilelist, tmp))
  359. {
  360. if (tmp[0]=='/')
  361. {
  362. continue;
  363. }
  364. std::string completePath=projectDir+tmp;
  365. if (cmSystemTools::FileExists(completePath.c_str()))
  366. {
  367. files.insert(tmp);
  368. }
  369. }
  370. oldFilelist.close();
  371. }
  372. //now write the new filename
  373. cmGeneratedFileStream fout(filename.c_str());
  374. if(!fout)
  375. {
  376. return false;
  377. }
  378. for (std::set<cmStdString>::const_iterator it=files.begin(); it!=files.end(); it++)
  379. {
  380. // get the full path to the file
  381. tmp=cmSystemTools::CollapseFullPath(it->c_str(), projectDir.c_str());
  382. // make it relative to the project dir
  383. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  384. // only put relative paths
  385. if (tmp.size() && tmp[0] != '/')
  386. {
  387. fout << tmp.c_str() <<"\n";
  388. }
  389. }
  390. return true;
  391. }