cmGlobalKdevelopGenerator.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmGlobalKdevelopGenerator.h"
  4. #include "cmGeneratedFileStream.h"
  5. #include "cmGeneratorTarget.h"
  6. #include "cmGlobalGenerator.h"
  7. #include "cmLocalGenerator.h"
  8. #include "cmMakefile.h"
  9. #include "cmSourceFile.h"
  10. #include "cmStateTypes.h"
  11. #include "cmSystemTools.h"
  12. #include "cmTarget.h"
  13. #include "cmXMLWriter.h"
  14. #include "cmake.h"
  15. #include "cmsys/Directory.hxx"
  16. #include "cmsys/FStream.hxx"
  17. #include <map>
  18. #include <set>
  19. #include <string.h>
  20. #include <utility>
  21. cmGlobalKdevelopGenerator::cmGlobalKdevelopGenerator()
  22. : cmExternalMakefileProjectGenerator()
  23. {
  24. }
  25. cmExternalMakefileProjectGeneratorFactory*
  26. cmGlobalKdevelopGenerator::GetFactory()
  27. {
  28. static cmExternalMakefileProjectGeneratorSimpleFactory<
  29. cmGlobalKdevelopGenerator>
  30. factory("KDevelop3", "Generates KDevelop 3 project files.");
  31. if (factory.GetSupportedGlobalGenerators().empty()) {
  32. factory.AddSupportedGlobalGenerator("Unix Makefiles");
  33. #ifdef CMAKE_USE_NINJA
  34. factory.AddSupportedGlobalGenerator("Ninja");
  35. #endif
  36. factory.Aliases.push_back("KDevelop3");
  37. }
  38. return &factory;
  39. }
  40. void cmGlobalKdevelopGenerator::Generate()
  41. {
  42. // for each sub project in the project create
  43. // a kdevelop project
  44. for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
  45. it = this->GlobalGenerator->GetProjectMap().begin();
  46. it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
  47. std::string outputDir = it->second[0]->GetCurrentBinaryDirectory();
  48. std::string projectDir = it->second[0]->GetSourceDirectory();
  49. std::string projectName = it->second[0]->GetProjectName();
  50. std::string cmakeFilePattern("CMakeLists.txt;*.cmake;");
  51. std::string fileToOpen;
  52. const std::vector<cmLocalGenerator*>& lgs = it->second;
  53. // create the project.kdevelop.filelist file
  54. if (!this->CreateFilelistFile(lgs, outputDir, projectDir, projectName,
  55. cmakeFilePattern, fileToOpen)) {
  56. cmSystemTools::Error("Can not create filelist file");
  57. return;
  58. }
  59. // try to find the name of an executable so we have something to
  60. // run from kdevelop for now just pick the first executable found
  61. std::string executable;
  62. for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
  63. lg != lgs.end(); lg++) {
  64. std::vector<cmGeneratorTarget*> const& targets =
  65. (*lg)->GetGeneratorTargets();
  66. for (std::vector<cmGeneratorTarget*>::const_iterator ti =
  67. targets.begin();
  68. ti != targets.end(); ti++) {
  69. if ((*ti)->GetType() == cmStateEnums::EXECUTABLE) {
  70. executable = (*ti)->GetLocation("");
  71. break;
  72. }
  73. }
  74. if (!executable.empty()) {
  75. break;
  76. }
  77. }
  78. // now create a project file
  79. this->CreateProjectFile(outputDir, projectDir, projectName, executable,
  80. cmakeFilePattern, fileToOpen);
  81. }
  82. }
  83. bool cmGlobalKdevelopGenerator::CreateFilelistFile(
  84. const std::vector<cmLocalGenerator*>& lgs, const std::string& outputDir,
  85. const std::string& projectDirIn, const std::string& projectname,
  86. std::string& cmakeFilePattern, std::string& fileToOpen)
  87. {
  88. std::string projectDir = projectDirIn + "/";
  89. std::string filename = outputDir + "/" + projectname + ".kdevelop.filelist";
  90. std::set<std::string> files;
  91. std::string tmp;
  92. std::vector<std::string> const& hdrExts =
  93. this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
  94. for (std::vector<cmLocalGenerator*>::const_iterator it = lgs.begin();
  95. it != lgs.end(); it++) {
  96. cmMakefile* makefile = (*it)->GetMakefile();
  97. const std::vector<std::string>& listFiles = makefile->GetListFiles();
  98. for (std::vector<std::string>::const_iterator lt = listFiles.begin();
  99. lt != listFiles.end(); lt++) {
  100. tmp = *lt;
  101. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  102. // make sure the file is part of this source tree
  103. if ((tmp[0] != '/') &&
  104. (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
  105. CM_NULLPTR)) {
  106. files.insert(tmp);
  107. tmp = cmSystemTools::GetFilenameName(tmp);
  108. // add all files which dont match the default
  109. // */CMakeLists.txt;*cmake; to the file pattern
  110. if ((tmp != "CMakeLists.txt") &&
  111. (strstr(tmp.c_str(), ".cmake") == CM_NULLPTR)) {
  112. cmakeFilePattern += tmp + ";";
  113. }
  114. }
  115. }
  116. // get all sources
  117. const std::vector<cmGeneratorTarget*>& targets =
  118. (*it)->GetGeneratorTargets();
  119. for (std::vector<cmGeneratorTarget*>::const_iterator ti = targets.begin();
  120. ti != targets.end(); ti++) {
  121. std::vector<cmSourceFile*> sources;
  122. cmGeneratorTarget* gt = *ti;
  123. gt->GetSourceFiles(sources, gt->Target->GetMakefile()->GetSafeDefinition(
  124. "CMAKE_BUILD_TYPE"));
  125. for (std::vector<cmSourceFile*>::const_iterator si = sources.begin();
  126. si != sources.end(); si++) {
  127. tmp = (*si)->GetFullPath();
  128. std::string headerBasename = cmSystemTools::GetFilenamePath(tmp);
  129. headerBasename += "/";
  130. headerBasename += cmSystemTools::GetFilenameWithoutExtension(tmp);
  131. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  132. if ((tmp[0] != '/') &&
  133. (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
  134. CM_NULLPTR) &&
  135. (cmSystemTools::GetFilenameExtension(tmp) != ".moc")) {
  136. files.insert(tmp);
  137. // check if there's a matching header around
  138. for (std::vector<std::string>::const_iterator ext = hdrExts.begin();
  139. ext != hdrExts.end(); ++ext) {
  140. std::string hname = headerBasename;
  141. hname += ".";
  142. hname += *ext;
  143. if (cmSystemTools::FileExists(hname.c_str())) {
  144. cmSystemTools::ReplaceString(hname, projectDir.c_str(), "");
  145. files.insert(hname);
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. for (std::vector<std::string>::const_iterator lt = listFiles.begin();
  152. lt != listFiles.end(); lt++) {
  153. tmp = *lt;
  154. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  155. if ((tmp[0] != '/') &&
  156. (strstr(tmp.c_str(), cmake::GetCMakeFilesDirectoryPostSlash()) ==
  157. CM_NULLPTR)) {
  158. files.insert(tmp);
  159. }
  160. }
  161. }
  162. }
  163. // check if the output file already exists and read it
  164. // insert all files which exist into the set of files
  165. cmsys::ifstream oldFilelist(filename.c_str());
  166. if (oldFilelist) {
  167. while (cmSystemTools::GetLineFromStream(oldFilelist, tmp)) {
  168. if (tmp[0] == '/') {
  169. continue;
  170. }
  171. std::string completePath = projectDir + tmp;
  172. if (cmSystemTools::FileExists(completePath.c_str())) {
  173. files.insert(tmp);
  174. }
  175. }
  176. oldFilelist.close();
  177. }
  178. // now write the new filename
  179. cmGeneratedFileStream fout(filename.c_str());
  180. if (!fout) {
  181. return false;
  182. }
  183. fileToOpen = "";
  184. for (std::set<std::string>::const_iterator it = files.begin();
  185. it != files.end(); it++) {
  186. // get the full path to the file
  187. tmp = cmSystemTools::CollapseFullPath(*it, projectDir.c_str());
  188. // just select the first source file
  189. if (fileToOpen.empty()) {
  190. std::string ext = cmSystemTools::GetFilenameExtension(tmp);
  191. if ((ext == ".c") || (ext == ".cc") || (ext == ".cpp") ||
  192. (ext == ".cxx") || (ext == ".C") || (ext == ".h") ||
  193. (ext == ".hpp")) {
  194. fileToOpen = tmp;
  195. }
  196. }
  197. // make it relative to the project dir
  198. cmSystemTools::ReplaceString(tmp, projectDir.c_str(), "");
  199. // only put relative paths
  200. if (!tmp.empty() && tmp[0] != '/') {
  201. fout << tmp << "\n";
  202. }
  203. }
  204. return true;
  205. }
  206. /* create the project file, if it already exists, merge it with the
  207. existing one, otherwise create a new one */
  208. void cmGlobalKdevelopGenerator::CreateProjectFile(
  209. const std::string& outputDir, const std::string& projectDir,
  210. const std::string& projectname, const std::string& executable,
  211. const std::string& cmakeFilePattern, const std::string& fileToOpen)
  212. {
  213. this->Blacklist.clear();
  214. std::string filename = outputDir + "/";
  215. filename += projectname + ".kdevelop";
  216. std::string sessionFilename = outputDir + "/";
  217. sessionFilename += projectname + ".kdevses";
  218. if (cmSystemTools::FileExists(filename.c_str())) {
  219. this->MergeProjectFiles(outputDir, projectDir, filename, executable,
  220. cmakeFilePattern, fileToOpen, sessionFilename);
  221. } else {
  222. // add all subdirectories which are cmake build directories to the
  223. // kdevelop blacklist so they are not monitored for added or removed files
  224. // since this is handled by adding files to the cmake files
  225. cmsys::Directory d;
  226. if (d.Load(projectDir)) {
  227. size_t numf = d.GetNumberOfFiles();
  228. for (unsigned int i = 0; i < numf; i++) {
  229. std::string nextFile = d.GetFile(i);
  230. if ((nextFile != ".") && (nextFile != "..")) {
  231. std::string tmp = projectDir;
  232. tmp += "/";
  233. tmp += nextFile;
  234. if (cmSystemTools::FileIsDirectory(tmp)) {
  235. tmp += "/CMakeCache.txt";
  236. if ((nextFile == "CMakeFiles") ||
  237. (cmSystemTools::FileExists(tmp.c_str()))) {
  238. this->Blacklist.push_back(nextFile);
  239. }
  240. }
  241. }
  242. }
  243. }
  244. this->CreateNewProjectFile(outputDir, projectDir, filename, executable,
  245. cmakeFilePattern, fileToOpen, sessionFilename);
  246. }
  247. }
  248. void cmGlobalKdevelopGenerator::MergeProjectFiles(
  249. const std::string& outputDir, const std::string& projectDir,
  250. const std::string& filename, const std::string& executable,
  251. const std::string& cmakeFilePattern, const std::string& fileToOpen,
  252. const std::string& sessionFilename)
  253. {
  254. cmsys::ifstream oldProjectFile(filename.c_str());
  255. if (!oldProjectFile) {
  256. this->CreateNewProjectFile(outputDir, projectDir, filename, executable,
  257. cmakeFilePattern, fileToOpen, sessionFilename);
  258. return;
  259. }
  260. /* Read the existing project file (line by line), copy all lines
  261. into the new project file, except the ones which can be reliably
  262. set from contents of the CMakeLists.txt */
  263. std::string tmp;
  264. std::vector<std::string> lines;
  265. while (cmSystemTools::GetLineFromStream(oldProjectFile, tmp)) {
  266. lines.push_back(tmp);
  267. }
  268. oldProjectFile.close();
  269. cmGeneratedFileStream fout(filename.c_str());
  270. if (!fout) {
  271. return;
  272. }
  273. for (std::vector<std::string>::const_iterator it = lines.begin();
  274. it != lines.end(); it++) {
  275. const char* line = (*it).c_str();
  276. // skip these tags as they are always replaced
  277. if ((strstr(line, "<projectdirectory>") != CM_NULLPTR) ||
  278. (strstr(line, "<projectmanagement>") != CM_NULLPTR) ||
  279. (strstr(line, "<absoluteprojectpath>") != CM_NULLPTR) ||
  280. (strstr(line, "<filelistdirectory>") != CM_NULLPTR) ||
  281. (strstr(line, "<buildtool>") != CM_NULLPTR) ||
  282. (strstr(line, "<builddir>") != CM_NULLPTR)) {
  283. continue;
  284. }
  285. // output the line from the file if it is not one of the above tags
  286. fout << *it << "\n";
  287. // if this is the <general> tag output the stuff that goes in the
  288. // general tag
  289. if (strstr(line, "<general>")) {
  290. fout << " <projectmanagement>KDevCustomProject</projectmanagement>\n";
  291. fout << " <projectdirectory>" << projectDir
  292. << "</projectdirectory>\n"; // this one is important
  293. fout << " <absoluteprojectpath>true</absoluteprojectpath>\n";
  294. // and this one
  295. }
  296. // inside kdevcustomproject the <filelistdirectory> must be put
  297. if (strstr(line, "<kdevcustomproject>")) {
  298. fout << " <filelistdirectory>" << outputDir
  299. << "</filelistdirectory>\n";
  300. }
  301. // buildtool and builddir go inside <build>
  302. if (strstr(line, "<build>")) {
  303. fout << " <buildtool>make</buildtool>\n";
  304. fout << " <builddir>" << outputDir << "</builddir>\n";
  305. }
  306. }
  307. }
  308. void cmGlobalKdevelopGenerator::CreateNewProjectFile(
  309. const std::string& outputDir, const std::string& projectDir,
  310. const std::string& filename, const std::string& executable,
  311. const std::string& cmakeFilePattern, const std::string& fileToOpen,
  312. const std::string& sessionFilename)
  313. {
  314. cmGeneratedFileStream fout(filename.c_str());
  315. if (!fout) {
  316. return;
  317. }
  318. cmXMLWriter xml(fout);
  319. // check for a version control system
  320. bool hasSvn = cmSystemTools::FileExists((projectDir + "/.svn").c_str());
  321. bool hasCvs = cmSystemTools::FileExists((projectDir + "/CVS").c_str());
  322. bool enableCxx = (this->GlobalGenerator->GetLanguageEnabled("C") ||
  323. this->GlobalGenerator->GetLanguageEnabled("CXX"));
  324. bool enableFortran = this->GlobalGenerator->GetLanguageEnabled("Fortran");
  325. std::string primaryLanguage = "C++";
  326. if (enableFortran && !enableCxx) {
  327. primaryLanguage = "Fortran77";
  328. }
  329. xml.StartDocument();
  330. xml.StartElement("kdevelop");
  331. xml.StartElement("general");
  332. xml.Element("author", "");
  333. xml.Element("email", "");
  334. xml.Element("version", "$VERSION$");
  335. xml.Element("projectmanagement", "KDevCustomProject");
  336. xml.Element("primarylanguage", primaryLanguage);
  337. xml.Element("ignoreparts");
  338. xml.Element("projectdirectory", projectDir); // this one is important
  339. xml.Element("absoluteprojectpath", "true"); // and this one
  340. // setup additional languages
  341. xml.StartElement("secondaryLanguages");
  342. if (enableFortran && enableCxx) {
  343. xml.Element("language", "Fortran");
  344. }
  345. if (enableCxx) {
  346. xml.Element("language", "C");
  347. }
  348. xml.EndElement();
  349. if (hasSvn) {
  350. xml.Element("versioncontrol", "kdevsubversion");
  351. } else if (hasCvs) {
  352. xml.Element("versioncontrol", "kdevcvsservice");
  353. }
  354. xml.EndElement(); // general
  355. xml.StartElement("kdevcustomproject");
  356. xml.Element("filelistdirectory", outputDir);
  357. xml.StartElement("run");
  358. xml.Element("mainprogram", executable);
  359. xml.Element("directoryradio", "custom");
  360. xml.Element("customdirectory", outputDir);
  361. xml.Element("programargs", "");
  362. xml.Element("terminal", "false");
  363. xml.Element("autocompile", "true");
  364. xml.Element("envvars");
  365. xml.EndElement();
  366. xml.StartElement("build");
  367. xml.Element("buildtool", "make"); // this one is important
  368. xml.Element("builddir", outputDir); // and this one
  369. xml.EndElement();
  370. xml.StartElement("make");
  371. xml.Element("abortonerror", "false");
  372. xml.Element("numberofjobs", 1);
  373. xml.Element("dontact", "false");
  374. xml.Element("makebin", this->GlobalGenerator->GetLocalGenerators()[0]
  375. ->GetMakefile()
  376. ->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"));
  377. xml.Element("selectedenvironment", "default");
  378. xml.StartElement("environments");
  379. xml.StartElement("default");
  380. xml.StartElement("envvar");
  381. xml.Attribute("value", 1);
  382. xml.Attribute("name", "VERBOSE");
  383. xml.EndElement();
  384. xml.StartElement("envvar");
  385. xml.Attribute("value", 1);
  386. xml.Attribute("name", "CMAKE_NO_VERBOSE");
  387. xml.EndElement();
  388. xml.EndElement(); // default
  389. xml.EndElement(); // environments
  390. xml.EndElement(); // make
  391. xml.StartElement("blacklist");
  392. for (std::vector<std::string>::const_iterator dirIt =
  393. this->Blacklist.begin();
  394. dirIt != this->Blacklist.end(); ++dirIt) {
  395. xml.Element("path", *dirIt);
  396. }
  397. xml.EndElement();
  398. xml.EndElement(); // kdevcustomproject
  399. xml.StartElement("kdevfilecreate");
  400. xml.Element("filetypes");
  401. xml.StartElement("useglobaltypes");
  402. xml.StartElement("type");
  403. xml.Attribute("ext", "ui");
  404. xml.EndElement();
  405. xml.StartElement("type");
  406. xml.Attribute("ext", "cpp");
  407. xml.EndElement();
  408. xml.StartElement("type");
  409. xml.Attribute("ext", "h");
  410. xml.EndElement();
  411. xml.EndElement(); // useglobaltypes
  412. xml.EndElement(); // kdevfilecreate
  413. xml.StartElement("kdevdoctreeview");
  414. xml.StartElement("projectdoc");
  415. xml.Element("userdocDir", "html/");
  416. xml.Element("apidocDir", "html/");
  417. xml.EndElement(); // projectdoc
  418. xml.Element("ignoreqt_xml");
  419. xml.Element("ignoredoxygen");
  420. xml.Element("ignorekdocs");
  421. xml.Element("ignoretocs");
  422. xml.Element("ignoredevhelp");
  423. xml.EndElement(); // kdevdoctreeview;
  424. if (enableCxx) {
  425. xml.StartElement("cppsupportpart");
  426. xml.StartElement("filetemplates");
  427. xml.Element("interfacesuffix", ".h");
  428. xml.Element("implementationsuffix", ".cpp");
  429. xml.EndElement(); // filetemplates
  430. xml.EndElement(); // cppsupportpart
  431. xml.StartElement("kdevcppsupport");
  432. xml.StartElement("codecompletion");
  433. xml.Element("includeGlobalFunctions", "true");
  434. xml.Element("includeTypes", "true");
  435. xml.Element("includeEnums", "true");
  436. xml.Element("includeTypedefs", "false");
  437. xml.Element("automaticCodeCompletion", "true");
  438. xml.Element("automaticArgumentsHint", "true");
  439. xml.Element("automaticHeaderCompletion", "true");
  440. xml.Element("codeCompletionDelay", 250);
  441. xml.Element("argumentsHintDelay", 400);
  442. xml.Element("headerCompletionDelay", 250);
  443. xml.EndElement(); // codecompletion
  444. xml.Element("references");
  445. xml.EndElement(); // kdevcppsupport;
  446. }
  447. if (enableFortran) {
  448. xml.StartElement("kdevfortransupport");
  449. xml.StartElement("ftnchek");
  450. xml.Element("division", "false");
  451. xml.Element("extern", "false");
  452. xml.Element("declare", "false");
  453. xml.Element("pure", "false");
  454. xml.Element("argumentsall", "false");
  455. xml.Element("commonall", "false");
  456. xml.Element("truncationall", "false");
  457. xml.Element("usageall", "false");
  458. xml.Element("f77all", "false");
  459. xml.Element("portabilityall", "false");
  460. xml.Element("argumentsonly");
  461. xml.Element("commononly");
  462. xml.Element("truncationonly");
  463. xml.Element("usageonly");
  464. xml.Element("f77only");
  465. xml.Element("portabilityonly");
  466. xml.EndElement(); // ftnchek
  467. xml.EndElement(); // kdevfortransupport;
  468. }
  469. // set up file groups. maybe this can be used with the CMake SOURCE_GROUP()
  470. // command
  471. xml.StartElement("kdevfileview");
  472. xml.StartElement("groups");
  473. xml.StartElement("group");
  474. xml.Attribute("pattern", cmakeFilePattern);
  475. xml.Attribute("name", "CMake");
  476. xml.EndElement();
  477. if (enableCxx) {
  478. xml.StartElement("group");
  479. xml.Attribute("pattern", "*.h;*.hxx;*.hpp");
  480. xml.Attribute("name", "Header");
  481. xml.EndElement();
  482. xml.StartElement("group");
  483. xml.Attribute("pattern", "*.c");
  484. xml.Attribute("name", "C Sources");
  485. xml.EndElement();
  486. xml.StartElement("group");
  487. xml.Attribute("pattern", "*.cpp;*.C;*.cxx;*.cc");
  488. xml.Attribute("name", "C++ Sources");
  489. xml.EndElement();
  490. }
  491. if (enableFortran) {
  492. xml.StartElement("group");
  493. xml.Attribute("pattern",
  494. "*.f;*.F;*.f77;*.F77;*.f90;*.F90;*.for;*.f95;*.F95");
  495. xml.Attribute("name", "Fortran Sources");
  496. xml.EndElement();
  497. }
  498. xml.StartElement("group");
  499. xml.Attribute("pattern", "*.ui");
  500. xml.Attribute("name", "Qt Designer files");
  501. xml.EndElement();
  502. xml.Element("hidenonprojectfiles", "true");
  503. xml.EndElement(); // groups
  504. xml.StartElement("tree");
  505. xml.Element("hidepatterns", "*.o,*.lo,CVS,*~,cmake*");
  506. xml.Element("hidenonprojectfiles", "true");
  507. xml.EndElement(); // tree
  508. xml.EndElement(); // kdevfileview
  509. xml.EndElement(); // kdevelop;
  510. xml.EndDocument();
  511. if (sessionFilename.empty()) {
  512. return;
  513. }
  514. // and a session file, so that kdevelop opens a file if it opens the
  515. // project the first time
  516. cmGeneratedFileStream devses(sessionFilename.c_str());
  517. if (!devses) {
  518. return;
  519. }
  520. cmXMLWriter sesxml(devses);
  521. sesxml.StartDocument("UTF-8");
  522. sesxml.Doctype("KDevPrjSession");
  523. sesxml.StartElement("KDevPrjSession");
  524. sesxml.StartElement("DocsAndViews");
  525. sesxml.Attribute("NumberOfDocuments", 1);
  526. sesxml.StartElement("Doc0");
  527. sesxml.Attribute("NumberOfViews", 1);
  528. sesxml.Attribute("URL", "file://" + fileToOpen);
  529. sesxml.StartElement("View0");
  530. sesxml.Attribute("line", 0);
  531. sesxml.Attribute("Type", "Source");
  532. sesxml.EndElement(); // View0
  533. sesxml.EndElement(); // Doc0
  534. sesxml.EndElement(); // DocsAndViews
  535. sesxml.EndElement(); // KDevPrjSession;
  536. }