cmExtraSublimeTextGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2004-2009 Kitware, Inc.
  4. Copyright 2004 Alexander Neundorf ([email protected])
  5. Distributed under the OSI-approved BSD License (the "License");
  6. see accompanying file Copyright.txt for details.
  7. This software is distributed WITHOUT ANY WARRANTY; without even the
  8. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. See the License for more information.
  10. ============================================================================*/
  11. #include "cmExtraSublimeTextGenerator.h"
  12. #include "cmGlobalUnixMakefileGenerator3.h"
  13. #include "cmLocalUnixMakefileGenerator3.h"
  14. #include "cmMakefile.h"
  15. #include "cmake.h"
  16. #include "cmSourceFile.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmTarget.h"
  19. #include "cmSystemTools.h"
  20. #include "cmXMLSafe.h"
  21. #include <cmsys/SystemTools.hxx>
  22. /*
  23. Sublime Text 2 Generator
  24. Author: Morné Chamberlain
  25. This generator was initially based off of the CodeBlocks generator.
  26. Some useful URLs:
  27. Homepage:
  28. http://www.sublimetext.com/
  29. File format docs:
  30. http://www.sublimetext.com/docs/2/projects.html
  31. http://sublimetext.info/docs/en/reference/build_systems.html
  32. */
  33. //----------------------------------------------------------------------------
  34. void cmExtraSublimeTextGenerator
  35. ::GetDocumentation(cmDocumentationEntry& entry, const char*) const
  36. {
  37. entry.Name = this->GetName();
  38. entry.Brief = "Generates Sublime Text 2 project files.";
  39. entry.Full =
  40. "Project files for Sublime Text 2 will be created in the top directory "
  41. "and in every subdirectory which features a CMakeLists.txt file "
  42. "containing a PROJECT() call. "
  43. "Additionally Makefiles (or build.ninja files) are generated into the "
  44. "build tree. The appropriate make program can build the project through "
  45. "the default make target. A \"make install\" target is also provided.";
  46. }
  47. cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
  48. :cmExternalMakefileProjectGenerator()
  49. {
  50. #if defined(_WIN32)
  51. this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
  52. this->SupportedGlobalGenerators.push_back("NMake Makefiles");
  53. // disable until somebody actually tests it:
  54. // this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
  55. #endif
  56. this->SupportedGlobalGenerators.push_back("Ninja");
  57. this->SupportedGlobalGenerators.push_back("Unix Makefiles");
  58. }
  59. void cmExtraSublimeTextGenerator::Generate()
  60. {
  61. // for each sub project in the project create a sublime text 2 project
  62. for (std::map<cmStdString, std::vector<cmLocalGenerator*> >::const_iterator
  63. it = this->GlobalGenerator->GetProjectMap().begin();
  64. it!= this->GlobalGenerator->GetProjectMap().end();
  65. ++it)
  66. {
  67. // create a project file
  68. this->CreateProjectFile(it->second);
  69. }
  70. }
  71. void cmExtraSublimeTextGenerator::CreateProjectFile(
  72. const std::vector<cmLocalGenerator*>& lgs)
  73. {
  74. const cmMakefile* mf=lgs[0]->GetMakefile();
  75. std::string outputDir=mf->GetStartOutputDirectory();
  76. std::string projectName=mf->GetProjectName();
  77. std::string filename=outputDir+"/";
  78. filename+=projectName+".sublime-project";
  79. this->CreateNewProjectFile(lgs, filename);
  80. }
  81. void cmExtraSublimeTextGenerator
  82. ::CreateNewProjectFile(const std::vector<cmLocalGenerator*>& lgs,
  83. const std::string& filename)
  84. {
  85. const cmMakefile* mf=lgs[0]->GetMakefile();
  86. cmGeneratedFileStream fout(filename.c_str());
  87. if(!fout)
  88. {
  89. return;
  90. }
  91. const std::string &sourceRootRelativeToOutput = cmSystemTools::RelativePath(
  92. mf->GetHomeOutputDirectory(),
  93. mf->GetHomeDirectory());
  94. // Write the folder entries to the project file
  95. fout << "{\n";
  96. fout << "\t\"folders\":\n\t[\n\t";
  97. if (!sourceRootRelativeToOutput.empty())
  98. {
  99. fout << "\t{\n\t\t\t\"path\": \"" << sourceRootRelativeToOutput << "\"";
  100. const std::string &outputRelativeToSourceRoot =
  101. cmSystemTools::RelativePath(mf->GetHomeDirectory(),
  102. mf->GetHomeOutputDirectory());
  103. if ((!outputRelativeToSourceRoot.empty()) &&
  104. ((outputRelativeToSourceRoot.length() < 3) ||
  105. (outputRelativeToSourceRoot.substr(0, 3) != "../")))
  106. {
  107. fout << ",\n\t\t\t\"folder_exclude_patterns\": [\"" <<
  108. outputRelativeToSourceRoot << "\"]";
  109. }
  110. }
  111. else
  112. {
  113. fout << "\t{\n\t\t\t\"path\": \"./\"";
  114. }
  115. fout << "\n\t\t}";
  116. // End of the folders section
  117. fout << "\n\t]";
  118. // Write the beginning of the build systems section to the project file
  119. fout << ",\n\t\"build_systems\":\n\t[\n\t";
  120. // Set of include directories over all targets (sublime text/sublimeclang
  121. // doesn't currently support these settings per build system, only project
  122. // wide
  123. MapSourceFileFlags sourceFileFlags;
  124. AppendAllTargets(lgs, mf, fout, sourceFileFlags);
  125. // End of build_systems
  126. fout << "\n\t]";
  127. // Write the settings section with sublimeclang options
  128. fout << ",\n\t\"settings\":\n\t{\n\t";
  129. // Check if the CMAKE_SUBLIMECLANG_DISABLED flag has been set. If it has
  130. // disable sublimeclang for this project.
  131. const char* sublimeclangDisabledValue =
  132. mf->GetSafeDefinition("CMAKE_SUBLIMECLANG_DISABLED");
  133. bool sublimeclangEnabled = cmSystemTools::IsOff(sublimeclangDisabledValue);
  134. // Per project sublimeclang settings override default and user settings,
  135. // so we only write the sublimeclang_enabled setting to the project file
  136. // if it is set to be disabled.
  137. if (!sublimeclangEnabled)
  138. {
  139. fout << "\t\"sublimeclang_enabled\": false,\n\t";
  140. }
  141. std::string outputDir = mf->GetStartOutputDirectory();
  142. std::string projectName = mf->GetProjectName();
  143. std::string sublimeClangOptionsFilename = outputDir+"/";
  144. sublimeClangOptionsFilename += projectName + ".sublimeclang-options";
  145. fout << "\t\"sublimeclang_options_file\": \"" << sublimeClangOptionsFilename
  146. << "\"\n\t";
  147. // End of the settings section
  148. fout << "}\n";
  149. // End of file
  150. fout << "}";
  151. this->WriteSublimeClangOptionsFile(sourceFileFlags,
  152. sublimeClangOptionsFilename);
  153. }
  154. void cmExtraSublimeTextGenerator::
  155. WriteSublimeClangOptionsFile(const MapSourceFileFlags& sourceFileFlags,
  156. const std::string& filename)
  157. {
  158. cmGeneratedFileStream fout(filename.c_str());
  159. if(!fout)
  160. {
  161. return;
  162. }
  163. fout << "{\n";
  164. MapSourceFileFlags::const_iterator sourceFileFlagsEnd =
  165. sourceFileFlags.end();
  166. int totalFiles = sourceFileFlags.size();
  167. int fileIndex = 0;
  168. for (MapSourceFileFlags::const_iterator iter = sourceFileFlags.begin();
  169. iter != sourceFileFlagsEnd; ++iter)
  170. {
  171. const std::string& sourceFilePath = iter->first;
  172. const std::vector<std::string>& flags = iter->second;
  173. fout << "\t\"" << sourceFilePath << "\":\n\t[\n\t";
  174. std::vector<std::string>::const_iterator flagsEnd = flags.end();
  175. for (std::vector<std::string>::const_iterator flagsIter = flags.begin();
  176. flagsIter != flagsEnd; ++flagsIter)
  177. {
  178. fout << "\t\"" << *flagsIter << "\"";
  179. if (flagsIter + 1 != flagsEnd)
  180. {
  181. fout << ",";
  182. }
  183. fout << "\n\t";
  184. }
  185. fout << "]";
  186. if (fileIndex < totalFiles - 1)
  187. {
  188. fout << ",";
  189. }
  190. fout << "\n";
  191. fileIndex++;
  192. }
  193. fout << "}\n";
  194. }
  195. void cmExtraSublimeTextGenerator::
  196. AppendAllTargets(const std::vector<cmLocalGenerator*>& lgs,
  197. const cmMakefile* mf,
  198. cmGeneratedFileStream& fout,
  199. MapSourceFileFlags& sourceFileFlags)
  200. {
  201. std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
  202. std::string compiler = "";
  203. if (!lgs.empty())
  204. {
  205. this->AppendTarget(fout, "all", lgs[0], 0, make.c_str(), mf,
  206. compiler.c_str(), sourceFileFlags, true);
  207. this->AppendTarget(fout, "clean", lgs[0], 0, make.c_str(), mf,
  208. compiler.c_str(), sourceFileFlags, false);
  209. }
  210. // add all executable and library targets and some of the GLOBAL
  211. // and UTILITY targets
  212. for (std::vector<cmLocalGenerator*>::const_iterator lg=lgs.begin();
  213. lg!=lgs.end(); lg++)
  214. {
  215. cmMakefile* makefile=(*lg)->GetMakefile();
  216. cmTargets& targets=makefile->GetTargets();
  217. for (cmTargets::iterator ti = targets.begin();
  218. ti != targets.end(); ti++)
  219. {
  220. switch(ti->second.GetType())
  221. {
  222. case cmTarget::GLOBAL_TARGET:
  223. {
  224. bool insertTarget = false;
  225. // Only add the global targets from CMAKE_BINARY_DIR,
  226. // not from the subdirs
  227. if (strcmp(makefile->GetStartOutputDirectory(),
  228. makefile->GetHomeOutputDirectory())==0)
  229. {
  230. insertTarget = true;
  231. // only add the "edit_cache" target if it's not ccmake, because
  232. // this will not work within the IDE
  233. if (ti->first == "edit_cache")
  234. {
  235. const char* editCommand = makefile->GetDefinition
  236. ("CMAKE_EDIT_COMMAND");
  237. if (editCommand == 0)
  238. {
  239. insertTarget = false;
  240. }
  241. else if (strstr(editCommand, "ccmake")!=NULL)
  242. {
  243. insertTarget = false;
  244. }
  245. }
  246. }
  247. if (insertTarget)
  248. {
  249. this->AppendTarget(fout, ti->first.c_str(), *lg, 0,
  250. make.c_str(), makefile, compiler.c_str(),
  251. sourceFileFlags, false);
  252. }
  253. }
  254. break;
  255. case cmTarget::UTILITY:
  256. // Add all utility targets, except the Nightly/Continuous/
  257. // Experimental-"sub"targets as e.g. NightlyStart
  258. if (((ti->first.find("Nightly")==0) &&(ti->first!="Nightly"))
  259. || ((ti->first.find("Continuous")==0)&&(ti->first!="Continuous"))
  260. || ((ti->first.find("Experimental")==0)
  261. && (ti->first!="Experimental")))
  262. {
  263. break;
  264. }
  265. this->AppendTarget(fout, ti->first.c_str(), *lg, 0,
  266. make.c_str(), makefile, compiler.c_str(),
  267. sourceFileFlags, false);
  268. break;
  269. case cmTarget::EXECUTABLE:
  270. case cmTarget::STATIC_LIBRARY:
  271. case cmTarget::SHARED_LIBRARY:
  272. case cmTarget::MODULE_LIBRARY:
  273. case cmTarget::OBJECT_LIBRARY:
  274. {
  275. this->AppendTarget(fout, ti->first.c_str(), *lg, &ti->second,
  276. make.c_str(), makefile, compiler.c_str(),
  277. sourceFileFlags, false);
  278. std::string fastTarget = ti->first;
  279. fastTarget += "/fast";
  280. this->AppendTarget(fout, fastTarget.c_str(), *lg, &ti->second,
  281. make.c_str(), makefile, compiler.c_str(),
  282. sourceFileFlags, false);
  283. }
  284. break;
  285. default:
  286. break;
  287. }
  288. }
  289. }
  290. }
  291. void cmExtraSublimeTextGenerator::
  292. AppendTarget(cmGeneratedFileStream& fout,
  293. const char* targetName,
  294. cmLocalGenerator* lg,
  295. cmTarget* target,
  296. const char* make,
  297. const cmMakefile* makefile,
  298. const char* compiler,
  299. MapSourceFileFlags& sourceFileFlags,
  300. bool firstTarget)
  301. {
  302. if (target != 0)
  303. {
  304. cmGeneratorTarget *gtgt = this->GlobalGenerator
  305. ->GetGeneratorTarget(target);
  306. std::vector<cmSourceFile*> const& sourceFiles = target->GetSourceFiles();
  307. std::vector<cmSourceFile*>::const_iterator sourceFilesEnd =
  308. sourceFiles.end();
  309. for (std::vector<cmSourceFile*>::const_iterator iter =
  310. sourceFiles.begin(); iter != sourceFilesEnd; ++iter)
  311. {
  312. cmSourceFile* sourceFile = *iter;
  313. MapSourceFileFlags::iterator sourceFileFlagsIter =
  314. sourceFileFlags.find(sourceFile->GetFullPath());
  315. if (sourceFileFlagsIter == sourceFileFlags.end())
  316. {
  317. sourceFileFlagsIter =
  318. sourceFileFlags.insert(MapSourceFileFlags::value_type(
  319. sourceFile->GetFullPath(), std::vector<std::string>())).first;
  320. }
  321. std::vector<std::string>& flags = sourceFileFlagsIter->second;
  322. std::string flagsString =
  323. this->ComputeFlagsForObject(*iter, lg, target, gtgt);
  324. std::string definesString =
  325. this->ComputeDefines(*iter, lg, target, gtgt);
  326. flags.clear();
  327. cmsys::RegularExpression flagRegex;
  328. // https://gist.github.com/3944250
  329. const char* regexString =
  330. "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
  331. flagRegex.compile(regexString);
  332. std::string workString = flagsString + " " + definesString;
  333. while (flagRegex.find(workString))
  334. {
  335. std::string::size_type start = flagRegex.start();
  336. if (workString[start] == ' ')
  337. {
  338. start++;
  339. }
  340. flags.push_back(workString.substr(start,
  341. flagRegex.end() - start));
  342. if (flagRegex.end() < workString.size())
  343. {
  344. workString = workString.substr(flagRegex.end());
  345. }
  346. else
  347. {
  348. workString = "";
  349. }
  350. }
  351. }
  352. }
  353. // Ninja uses ninja.build files (look for a way to get the output file name
  354. // from cmMakefile or something)
  355. std::string makefileName;
  356. if (strcmp(this->GlobalGenerator->GetName(), "Ninja")==0)
  357. {
  358. makefileName = "build.ninja";
  359. }
  360. else
  361. {
  362. makefileName = "Makefile";
  363. }
  364. if (!firstTarget)
  365. {
  366. fout << ",\n\t";
  367. }
  368. fout << "\t{\n\t\t\t\"name\": \"" << makefile->GetProjectName() << " - " <<
  369. targetName << "\",\n";
  370. fout << "\t\t\t\"cmd\": [" <<
  371. this->BuildMakeCommand(make, makefileName.c_str(), targetName) <<
  372. "],\n";
  373. fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
  374. fout << "\t\t\t\"file_regex\": \"^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$\"\n";
  375. fout << "\t\t}";
  376. }
  377. // Create the command line for building the given target using the selected
  378. // make
  379. std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
  380. const std::string& make, const char* makefile, const char* target)
  381. {
  382. std::string command = "\"";
  383. command += make + "\"";
  384. if (strcmp(this->GlobalGenerator->GetName(), "NMake Makefiles")==0)
  385. {
  386. std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  387. command += ", \"/NOLOGO\", \"/f\", \"";
  388. command += makefileName + "\"";
  389. command += ", \"VERBOSE=1\", \"";
  390. command += target;
  391. command += "\"";
  392. }
  393. else if (strcmp(this->GlobalGenerator->GetName(), "Ninja")==0)
  394. {
  395. std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  396. command += ", \"-f\", \"";
  397. command += makefileName + "\"";
  398. command += ", \"-v\", \"";
  399. command += target;
  400. command += "\"";
  401. }
  402. else
  403. {
  404. std::string makefileName;
  405. if (strcmp(this->GlobalGenerator->GetName(), "MinGW Makefiles")==0)
  406. {
  407. // no escaping of spaces in this case, see
  408. // http://public.kitware.com/Bug/view.php?id=10014
  409. makefileName = makefile;
  410. }
  411. else
  412. {
  413. makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  414. }
  415. command += ", \"-f\", \"";
  416. command += makefileName + "\"";
  417. command += ", \"VERBOSE=1\", \"";
  418. command += target;
  419. command += "\"";
  420. }
  421. return command;
  422. }
  423. // TODO: Most of the code is picked up from the Ninja generator, refactor it.
  424. std::string
  425. cmExtraSublimeTextGenerator::ComputeFlagsForObject(cmSourceFile* source,
  426. cmLocalGenerator* lg,
  427. cmTarget *target,
  428. cmGeneratorTarget* gtgt)
  429. {
  430. std::string flags;
  431. cmMakefile *makefile = lg->GetMakefile();
  432. const char* language = source->GetLanguage();
  433. if (language == NULL)
  434. {
  435. language = "C";
  436. }
  437. const char* config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
  438. // Add language-specific flags.
  439. lg->AddLanguageFlags(flags, language, config);
  440. lg->AddArchitectureFlags(flags, gtgt, language, config);
  441. // TODO: Fortran support.
  442. // // Fortran-specific flags computed for this target.
  443. // if(*l == "Fortran")
  444. // {
  445. // this->AddFortranFlags(flags);
  446. // }
  447. // Add shared-library flags if needed.
  448. lg->AddCMP0018Flags(flags, target, language);
  449. // Add include directory flags.
  450. {
  451. std::vector<std::string> includes;
  452. lg->GetIncludeDirectories(includes, gtgt, language, config);
  453. std::string includeFlags =
  454. lg->GetIncludeFlags(includes, language, true); // full include paths
  455. lg->AppendFlags(flags, includeFlags.c_str());
  456. }
  457. // Append old-style preprocessor definition flags.
  458. lg->AppendFlags(flags, makefile->GetDefineFlags());
  459. // Add target-specific flags.
  460. if(gtgt->GetProperty("COMPILE_FLAGS"))
  461. {
  462. std::string langIncludeExpr = "CMAKE_";
  463. langIncludeExpr += language;
  464. langIncludeExpr += "_FLAG_REGEX";
  465. const char* regex = makefile->GetDefinition(langIncludeExpr.c_str());
  466. if(regex)
  467. {
  468. cmsys::RegularExpression r(regex);
  469. std::vector<std::string> args;
  470. cmSystemTools::
  471. ParseWindowsCommandLine(gtgt->GetProperty("COMPILE_FLAGS"), args);
  472. for(std::vector<std::string>::iterator i = args.begin();
  473. i != args.end(); ++i)
  474. {
  475. if(r.find(i->c_str()))
  476. {
  477. lg->AppendFlags(flags, i->c_str());
  478. }
  479. }
  480. }
  481. else
  482. {
  483. lg->AppendFlags(flags, gtgt->GetProperty("COMPILE_FLAGS"));
  484. }
  485. }
  486. // Add source file specific flags.
  487. lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS"));
  488. // TODO: Handle Apple frameworks.
  489. return flags;
  490. }
  491. // TODO: Refactor with
  492. // void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
  493. std::string
  494. cmExtraSublimeTextGenerator::
  495. ComputeDefines(cmSourceFile *source, cmLocalGenerator* lg, cmTarget *target,
  496. cmGeneratorTarget* gtgt)
  497. {
  498. std::set<std::string> defines;
  499. cmMakefile *makefile = lg->GetMakefile();
  500. const char* language = source->GetLanguage();
  501. if (language == NULL)
  502. {
  503. language = "";
  504. }
  505. const char* config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
  506. // Add the export symbol definition for shared library objects.
  507. if(const char* exportMacro = target->GetExportMacro())
  508. {
  509. lg->AppendDefines(defines, exportMacro);
  510. }
  511. // Add preprocessor definitions for this target and configuration.
  512. lg->AppendDefines(defines, gtgt->GetCompileDefinitions());
  513. lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
  514. {
  515. std::string defPropName = "COMPILE_DEFINITIONS_";
  516. defPropName += cmSystemTools::UpperCase(config);
  517. lg->AppendDefines(defines, gtgt->GetCompileDefinitions(config));
  518. lg->AppendDefines(defines, source->GetProperty(defPropName.c_str()));
  519. }
  520. std::string definesString;
  521. lg->JoinDefines(defines, definesString, language);
  522. return definesString;
  523. }