You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
14 KiB

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  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 "cmExtraSublimeTextGenerator.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 <cmsys/RegularExpression.hxx>
  13. #include <ostream>
  14. #include <set>
  15. #include <string.h>
  16. #include <utility>
  17. /*
  18. Sublime Text 2 Generator
  19. Author: Morné Chamberlain
  20. This generator was initially based off of the CodeBlocks generator.
  21. Some useful URLs:
  22. Homepage:
  23. http://www.sublimetext.com/
  24. File format docs:
  25. http://www.sublimetext.com/docs/2/projects.html
  26. http://sublimetext.info/docs/en/reference/build_systems.html
  27. */
  28. cmExternalMakefileProjectGeneratorFactory*
  29. cmExtraSublimeTextGenerator::GetFactory()
  30. {
  31. static cmExternalMakefileProjectGeneratorSimpleFactory<
  32. cmExtraSublimeTextGenerator>
  33. factory("Sublime Text 2", "Generates Sublime Text 2 project files.");
  34. if (factory.GetSupportedGlobalGenerators().empty()) {
  35. #if defined(_WIN32)
  36. factory.AddSupportedGlobalGenerator("MinGW Makefiles");
  37. factory.AddSupportedGlobalGenerator("NMake Makefiles");
  38. // disable until somebody actually tests it:
  39. // factory.AddSupportedGlobalGenerator("MSYS Makefiles");
  40. #endif
  41. factory.AddSupportedGlobalGenerator("Ninja");
  42. factory.AddSupportedGlobalGenerator("Unix Makefiles");
  43. }
  44. return &factory;
  45. }
  46. cmExtraSublimeTextGenerator::cmExtraSublimeTextGenerator()
  47. : cmExternalMakefileProjectGenerator()
  48. {
  49. this->ExcludeBuildFolder = false;
  50. }
  51. void cmExtraSublimeTextGenerator::Generate()
  52. {
  53. this->ExcludeBuildFolder = this->GlobalGenerator->GlobalSettingIsOn(
  54. "CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE");
  55. this->EnvSettings = this->GlobalGenerator->GetSafeGlobalSetting(
  56. "CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS");
  57. // for each sub project in the project create a sublime text 2 project
  58. for (std::map<std::string, std::vector<cmLocalGenerator*> >::const_iterator
  59. it = this->GlobalGenerator->GetProjectMap().begin();
  60. it != this->GlobalGenerator->GetProjectMap().end(); ++it) {
  61. // create a project file
  62. this->CreateProjectFile(it->second);
  63. }
  64. }
  65. void cmExtraSublimeTextGenerator::CreateProjectFile(
  66. const std::vector<cmLocalGenerator*>& lgs)
  67. {
  68. std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
  69. std::string projectName = lgs[0]->GetProjectName();
  70. const std::string filename =
  71. outputDir + "/" + projectName + ".sublime-project";
  72. this->CreateNewProjectFile(lgs, filename);
  73. }
  74. void cmExtraSublimeTextGenerator::CreateNewProjectFile(
  75. const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
  76. {
  77. const cmMakefile* mf = lgs[0]->GetMakefile();
  78. cmGeneratedFileStream fout(filename.c_str());
  79. if (!fout) {
  80. return;
  81. }
  82. const std::string& sourceRootRelativeToOutput = cmSystemTools::RelativePath(
  83. lgs[0]->GetBinaryDirectory(), lgs[0]->GetSourceDirectory());
  84. // Write the folder entries to the project file
  85. fout << "{\n";
  86. fout << "\t\"folders\":\n\t[\n\t";
  87. if (!sourceRootRelativeToOutput.empty()) {
  88. fout << "\t{\n\t\t\t\"path\": \"" << sourceRootRelativeToOutput << "\"";
  89. const std::string& outputRelativeToSourceRoot =
  90. cmSystemTools::RelativePath(lgs[0]->GetSourceDirectory(),
  91. lgs[0]->GetBinaryDirectory());
  92. if ((!outputRelativeToSourceRoot.empty()) &&
  93. ((outputRelativeToSourceRoot.length() < 3) ||
  94. (outputRelativeToSourceRoot.substr(0, 3) != "../"))) {
  95. if (this->ExcludeBuildFolder) {
  96. fout << ",\n\t\t\t\"folder_exclude_patterns\": [\""
  97. << outputRelativeToSourceRoot << "\"]";
  98. }
  99. }
  100. } else {
  101. fout << "\t{\n\t\t\t\"path\": \"./\"";
  102. }
  103. fout << "\n\t\t}";
  104. // End of the folders section
  105. fout << "\n\t]";
  106. // Write the beginning of the build systems section to the project file
  107. fout << ",\n\t\"build_systems\":\n\t[\n\t";
  108. // Set of include directories over all targets (sublime text/sublimeclang
  109. // doesn't currently support these settings per build system, only project
  110. // wide
  111. MapSourceFileFlags sourceFileFlags;
  112. AppendAllTargets(lgs, mf, fout, sourceFileFlags);
  113. // End of build_systems
  114. fout << "\n\t]";
  115. std::string systemName = mf->GetSafeDefinition("CMAKE_SYSTEM_NAME");
  116. std::vector<std::string> tokens;
  117. cmSystemTools::ExpandListArgument(this->EnvSettings, tokens);
  118. if (!this->EnvSettings.empty()) {
  119. fout << ",";
  120. fout << "\n\t\"env\":";
  121. fout << "\n\t{";
  122. fout << "\n\t\t" << systemName << ":";
  123. fout << "\n\t\t{";
  124. for (std::vector<std::string>::iterator i = tokens.begin();
  125. i != tokens.end(); ++i) {
  126. size_t const pos = i->find_first_of('=');
  127. if (pos != std::string::npos) {
  128. std::string varName = i->substr(0, pos);
  129. std::string varValue = i->substr(pos + 1);
  130. fout << "\n\t\t\t\"" << varName << "\":\"" << varValue << "\"";
  131. } else {
  132. std::ostringstream e;
  133. e << "Could not parse Env Vars specified in "
  134. "\"CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS\""
  135. << ", corrupted string " << *i;
  136. mf->IssueMessage(cmake::FATAL_ERROR, e.str());
  137. }
  138. }
  139. fout << "\n\t\t}";
  140. fout << "\n\t}";
  141. }
  142. fout << "\n}";
  143. }
  144. void cmExtraSublimeTextGenerator::AppendAllTargets(
  145. const std::vector<cmLocalGenerator*>& lgs, const cmMakefile* mf,
  146. cmGeneratedFileStream& fout, MapSourceFileFlags& sourceFileFlags)
  147. {
  148. std::string make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
  149. std::string compiler = "";
  150. if (!lgs.empty()) {
  151. this->AppendTarget(fout, "all", lgs[0], CM_NULLPTR, make.c_str(), mf,
  152. compiler.c_str(), sourceFileFlags, true);
  153. this->AppendTarget(fout, "clean", lgs[0], CM_NULLPTR, make.c_str(), mf,
  154. compiler.c_str(), sourceFileFlags, false);
  155. }
  156. // add all executable and library targets and some of the GLOBAL
  157. // and UTILITY targets
  158. for (std::vector<cmLocalGenerator*>::const_iterator lg = lgs.begin();
  159. lg != lgs.end(); lg++) {
  160. cmMakefile* makefile = (*lg)->GetMakefile();
  161. std::vector<cmGeneratorTarget*> targets = (*lg)->GetGeneratorTargets();
  162. for (std::vector<cmGeneratorTarget*>::iterator ti = targets.begin();
  163. ti != targets.end(); ti++) {
  164. std::string targetName = (*ti)->GetName();
  165. switch ((*ti)->GetType()) {
  166. case cmStateEnums::GLOBAL_TARGET: {
  167. // Only add the global targets from CMAKE_BINARY_DIR,
  168. // not from the subdirs
  169. if (strcmp((*lg)->GetCurrentBinaryDirectory(),
  170. (*lg)->GetBinaryDirectory()) == 0) {
  171. this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
  172. makefile, compiler.c_str(), sourceFileFlags,
  173. false);
  174. }
  175. } break;
  176. case cmStateEnums::UTILITY:
  177. // Add all utility targets, except the Nightly/Continuous/
  178. // Experimental-"sub"targets as e.g. NightlyStart
  179. if (((targetName.find("Nightly") == 0) &&
  180. (targetName != "Nightly")) ||
  181. ((targetName.find("Continuous") == 0) &&
  182. (targetName != "Continuous")) ||
  183. ((targetName.find("Experimental") == 0) &&
  184. (targetName != "Experimental"))) {
  185. break;
  186. }
  187. this->AppendTarget(fout, targetName, *lg, CM_NULLPTR, make.c_str(),
  188. makefile, compiler.c_str(), sourceFileFlags,
  189. false);
  190. break;
  191. case cmStateEnums::EXECUTABLE:
  192. case cmStateEnums::STATIC_LIBRARY:
  193. case cmStateEnums::SHARED_LIBRARY:
  194. case cmStateEnums::MODULE_LIBRARY:
  195. case cmStateEnums::OBJECT_LIBRARY: {
  196. this->AppendTarget(fout, targetName, *lg, *ti, make.c_str(),
  197. makefile, compiler.c_str(), sourceFileFlags,
  198. false);
  199. std::string fastTarget = targetName;
  200. fastTarget += "/fast";
  201. this->AppendTarget(fout, fastTarget, *lg, *ti, make.c_str(),
  202. makefile, compiler.c_str(), sourceFileFlags,
  203. false);
  204. } break;
  205. default:
  206. break;
  207. }
  208. }
  209. }
  210. }
  211. void cmExtraSublimeTextGenerator::AppendTarget(
  212. cmGeneratedFileStream& fout, const std::string& targetName,
  213. cmLocalGenerator* lg, cmGeneratorTarget* target, const char* make,
  214. const cmMakefile* makefile, const char* /*compiler*/,
  215. MapSourceFileFlags& sourceFileFlags, bool firstTarget)
  216. {
  217. if (target != CM_NULLPTR) {
  218. std::vector<cmSourceFile*> sourceFiles;
  219. target->GetSourceFiles(sourceFiles,
  220. makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
  221. std::vector<cmSourceFile*>::const_iterator sourceFilesEnd =
  222. sourceFiles.end();
  223. for (std::vector<cmSourceFile*>::const_iterator iter = sourceFiles.begin();
  224. iter != sourceFilesEnd; ++iter) {
  225. cmSourceFile* sourceFile = *iter;
  226. MapSourceFileFlags::iterator sourceFileFlagsIter =
  227. sourceFileFlags.find(sourceFile->GetFullPath());
  228. if (sourceFileFlagsIter == sourceFileFlags.end()) {
  229. sourceFileFlagsIter =
  230. sourceFileFlags
  231. .insert(MapSourceFileFlags::value_type(sourceFile->GetFullPath(),
  232. std::vector<std::string>()))
  233. .first;
  234. }
  235. std::vector<std::string>& flags = sourceFileFlagsIter->second;
  236. std::string flagsString = this->ComputeFlagsForObject(*iter, lg, target);
  237. std::string definesString = this->ComputeDefines(*iter, lg, target);
  238. flags.clear();
  239. cmsys::RegularExpression flagRegex;
  240. // Regular expression to extract compiler flags from a string
  241. // https://gist.github.com/3944250
  242. const char* regexString =
  243. "(^|[ ])-[DIOUWfgs][^= ]+(=\\\"[^\"]+\\\"|=[^\"][^ ]+)?";
  244. flagRegex.compile(regexString);
  245. std::string workString = flagsString + " " + definesString;
  246. while (flagRegex.find(workString)) {
  247. std::string::size_type start = flagRegex.start();
  248. if (workString[start] == ' ') {
  249. start++;
  250. }
  251. flags.push_back(workString.substr(start, flagRegex.end() - start));
  252. if (flagRegex.end() < workString.size()) {
  253. workString = workString.substr(flagRegex.end());
  254. } else {
  255. workString = "";
  256. }
  257. }
  258. }
  259. }
  260. // Ninja uses ninja.build files (look for a way to get the output file name
  261. // from cmMakefile or something)
  262. std::string makefileName;
  263. if (this->GlobalGenerator->GetName() == "Ninja") {
  264. makefileName = "build.ninja";
  265. } else {
  266. makefileName = "Makefile";
  267. }
  268. if (!firstTarget) {
  269. fout << ",\n\t";
  270. }
  271. fout << "\t{\n\t\t\t\"name\": \"" << lg->GetProjectName() << " - "
  272. << targetName << "\",\n";
  273. fout << "\t\t\t\"cmd\": ["
  274. << this->BuildMakeCommand(make, makefileName.c_str(), targetName)
  275. << "],\n";
  276. fout << "\t\t\t\"working_dir\": \"${project_path}\",\n";
  277. fout << "\t\t\t\"file_regex\": \""
  278. "^(..[^:]*)(?::|\\\\()([0-9]+)(?::|\\\\))(?:([0-9]+):)?\\\\s*(.*)"
  279. "\"\n";
  280. fout << "\t\t}";
  281. }
  282. // Create the command line for building the given target using the selected
  283. // make
  284. std::string cmExtraSublimeTextGenerator::BuildMakeCommand(
  285. const std::string& make, const char* makefile, const std::string& target)
  286. {
  287. std::string command = "\"";
  288. command += make + "\"";
  289. std::string generator = this->GlobalGenerator->GetName();
  290. if (generator == "NMake Makefiles") {
  291. std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  292. command += ", \"/NOLOGO\", \"/f\", \"";
  293. command += makefileName + "\"";
  294. command += ", \"VERBOSE=1\", \"";
  295. command += target;
  296. command += "\"";
  297. } else if (generator == "Ninja") {
  298. std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  299. command += ", \"-f\", \"";
  300. command += makefileName + "\"";
  301. command += ", \"-v\", \"";
  302. command += target;
  303. command += "\"";
  304. } else {
  305. std::string makefileName;
  306. if (generator == "MinGW Makefiles") {
  307. // no escaping of spaces in this case, see
  308. // https://gitlab.kitware.com/cmake/cmake/issues/10014
  309. makefileName = makefile;
  310. } else {
  311. makefileName = cmSystemTools::ConvertToOutputPath(makefile);
  312. }
  313. command += ", \"-f\", \"";
  314. command += makefileName + "\"";
  315. command += ", \"VERBOSE=1\", \"";
  316. command += target;
  317. command += "\"";
  318. }
  319. return command;
  320. }
  321. // TODO: Most of the code is picked up from the Ninja generator, refactor it.
  322. std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject(
  323. cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* gtgt)
  324. {
  325. std::string flags;
  326. std::string language = source->GetLanguage();
  327. if (language.empty()) {
  328. language = "C";
  329. }
  330. std::string const& config =
  331. lg->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
  332. lg->GetTargetCompileFlags(gtgt, config, language, flags);
  333. // Add include directory flags.
  334. {
  335. std::vector<std::string> includes;
  336. lg->GetIncludeDirectories(includes, gtgt, language, config);
  337. std::string includeFlags = lg->GetIncludeFlags(includes, gtgt, language,
  338. true); // full include paths
  339. lg->AppendFlags(flags, includeFlags);
  340. }
  341. // Add source file specific flags.
  342. lg->AppendFlags(flags, source->GetProperty("COMPILE_FLAGS"));
  343. return flags;
  344. }
  345. // TODO: Refactor with
  346. // void cmMakefileTargetGenerator::WriteTargetLanguageFlags().
  347. std::string cmExtraSublimeTextGenerator::ComputeDefines(
  348. cmSourceFile* source, cmLocalGenerator* lg, cmGeneratorTarget* target)
  349. {
  350. std::set<std::string> defines;
  351. cmMakefile* makefile = lg->GetMakefile();
  352. const std::string& language = source->GetLanguage();
  353. const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
  354. // Add the export symbol definition for shared library objects.
  355. if (const char* exportMacro = target->GetExportMacro()) {
  356. lg->AppendDefines(defines, exportMacro);
  357. }
  358. // Add preprocessor definitions for this target and configuration.
  359. lg->AddCompileDefinitions(defines, target, config, language);
  360. lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS"));
  361. {
  362. std::string defPropName = "COMPILE_DEFINITIONS_";
  363. defPropName += cmSystemTools::UpperCase(config);
  364. lg->AppendDefines(defines, source->GetProperty(defPropName));
  365. }
  366. std::string definesString;
  367. lg->JoinDefines(defines, definesString, language);
  368. return definesString;
  369. }