cmExtraSublimeTextGenerator.cxx 17 KB

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