cmExtraKateGenerator.cxx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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 "cmExtraKateGenerator.h"
  4. #include <cstring>
  5. #include <memory>
  6. #include <ostream>
  7. #include <set>
  8. #include <vector>
  9. #include "cmCMakePath.h"
  10. #include "cmGeneratedFileStream.h"
  11. #include "cmGeneratorTarget.h"
  12. #include "cmGlobalGenerator.h"
  13. #include "cmLocalGenerator.h"
  14. #include "cmMakefile.h"
  15. #include "cmSourceFile.h"
  16. #include "cmStateTypes.h"
  17. #include "cmStringAlgorithms.h"
  18. #include "cmSystemTools.h"
  19. #include "cmValue.h"
  20. cmExtraKateGenerator::cmExtraKateGenerator() = default;
  21. cmExternalMakefileProjectGeneratorFactory* cmExtraKateGenerator::GetFactory()
  22. {
  23. static cmExternalMakefileProjectGeneratorSimpleFactory<cmExtraKateGenerator>
  24. factory("Kate", "Generates Kate project files (deprecated).");
  25. if (factory.GetSupportedGlobalGenerators().empty()) {
  26. #if defined(_WIN32)
  27. factory.AddSupportedGlobalGenerator("MinGW Makefiles");
  28. factory.AddSupportedGlobalGenerator("NMake Makefiles");
  29. // disable until somebody actually tests it:
  30. // factory.AddSupportedGlobalGenerator("MSYS Makefiles");
  31. #endif
  32. factory.AddSupportedGlobalGenerator("Ninja");
  33. factory.AddSupportedGlobalGenerator("Unix Makefiles");
  34. }
  35. return &factory;
  36. }
  37. void cmExtraKateGenerator::Generate()
  38. {
  39. const auto& lg = this->GlobalGenerator->GetLocalGenerators()[0];
  40. const cmMakefile* mf = lg->GetMakefile();
  41. this->ProjectName = this->GenerateProjectName(
  42. lg->GetProjectName(), mf->GetSafeDefinition("CMAKE_BUILD_TYPE"),
  43. this->GetPathBasename(lg->GetBinaryDirectory()));
  44. this->UseNinja = (this->GlobalGenerator->GetName() == "Ninja");
  45. this->CreateKateProjectFile(*lg);
  46. this->CreateDummyKateProjectFile(*lg);
  47. }
  48. void cmExtraKateGenerator::CreateKateProjectFile(
  49. const cmLocalGenerator& lg) const
  50. {
  51. std::string filename = cmStrCat(lg.GetBinaryDirectory(), "/.kateproject");
  52. cmGeneratedFileStream fout(filename);
  53. if (!fout) {
  54. return;
  55. }
  56. /* clang-format off */
  57. fout <<
  58. "{\n"
  59. "\t\"name\": \"" << this->ProjectName << "\",\n"
  60. "\t\"directory\": \"" << lg.GetSourceDirectory() << "\",\n"
  61. "\t\"files\": [ { " << this->GenerateFilesString(lg) << "} ],\n";
  62. /* clang-format on */
  63. this->WriteTargets(lg, fout);
  64. fout << "}\n";
  65. }
  66. void cmExtraKateGenerator::WriteTargets(const cmLocalGenerator& lg,
  67. cmGeneratedFileStream& fout) const
  68. {
  69. cmMakefile const* mf = lg.GetMakefile();
  70. const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
  71. const std::string& makeArgs =
  72. mf->GetSafeDefinition("CMAKE_KATE_MAKE_ARGUMENTS");
  73. std::string const& homeOutputDir = lg.GetBinaryDirectory();
  74. /* clang-format off */
  75. fout <<
  76. "\t\"build\": {\n"
  77. "\t\t\"directory\": \"" << homeOutputDir << "\",\n"
  78. "\t\t\"default_target\": \"all\",\n"
  79. "\t\t\"clean_target\": \"clean\",\n";
  80. /* clang-format on */
  81. // build, clean and quick are for the build plugin kate <= 4.12:
  82. fout << "\t\t\"build\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
  83. << makeArgs << " "
  84. << "all\",\n";
  85. fout << "\t\t\"clean\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
  86. << makeArgs << " "
  87. << "clean\",\n";
  88. fout << "\t\t\"quick\": \"" << make << " -C \\\"" << homeOutputDir << "\\\" "
  89. << makeArgs << " "
  90. << "install\",\n";
  91. // this is for kate >= 4.13:
  92. fout << "\t\t\"targets\":[\n";
  93. this->AppendTarget(fout, "all", make, makeArgs, homeOutputDir,
  94. homeOutputDir);
  95. this->AppendTarget(fout, "clean", make, makeArgs, homeOutputDir,
  96. homeOutputDir);
  97. // add all executable and library targets and some of the GLOBAL
  98. // and UTILITY targets
  99. for (const auto& localGen : this->GlobalGenerator->GetLocalGenerators()) {
  100. const auto& targets = localGen->GetGeneratorTargets();
  101. std::string currentDir = localGen->GetCurrentBinaryDirectory();
  102. bool topLevel = (currentDir == localGen->GetBinaryDirectory());
  103. for (const auto& target : targets) {
  104. std::string const& targetName = target->GetName();
  105. switch (target->GetType()) {
  106. case cmStateEnums::GLOBAL_TARGET: {
  107. bool insertTarget = false;
  108. // Only add the global targets from CMAKE_BINARY_DIR,
  109. // not from the subdirs
  110. if (topLevel) {
  111. insertTarget = true;
  112. // only add the "edit_cache" target if it's not ccmake, because
  113. // this will not work within the IDE
  114. if (targetName == "edit_cache") {
  115. cmValue editCommand =
  116. localGen->GetMakefile()->GetDefinition("CMAKE_EDIT_COMMAND");
  117. if (!editCommand ||
  118. strstr(editCommand->c_str(), "ccmake") != nullptr) {
  119. insertTarget = false;
  120. }
  121. }
  122. }
  123. if (insertTarget) {
  124. this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
  125. homeOutputDir);
  126. }
  127. } break;
  128. case cmStateEnums::UTILITY:
  129. // Add all utility targets, except the Nightly/Continuous/
  130. // Experimental-"sub"targets as e.g. NightlyStart
  131. if ((cmHasLiteralPrefix(targetName, "Nightly") &&
  132. (targetName != "Nightly")) ||
  133. (cmHasLiteralPrefix(targetName, "Continuous") &&
  134. (targetName != "Continuous")) ||
  135. (cmHasLiteralPrefix(targetName, "Experimental") &&
  136. (targetName != "Experimental"))) {
  137. break;
  138. }
  139. this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
  140. homeOutputDir);
  141. break;
  142. case cmStateEnums::EXECUTABLE:
  143. case cmStateEnums::STATIC_LIBRARY:
  144. case cmStateEnums::SHARED_LIBRARY:
  145. case cmStateEnums::MODULE_LIBRARY:
  146. case cmStateEnums::OBJECT_LIBRARY: {
  147. this->AppendTarget(fout, targetName, make, makeArgs, currentDir,
  148. homeOutputDir);
  149. std::string fastTarget = cmStrCat(targetName, "/fast");
  150. this->AppendTarget(fout, fastTarget, make, makeArgs, currentDir,
  151. homeOutputDir);
  152. } break;
  153. default:
  154. break;
  155. }
  156. }
  157. // insert rules for compiling, preprocessing and assembling individual
  158. // files
  159. std::vector<std::string> objectFileTargets;
  160. localGen->GetIndividualFileTargets(objectFileTargets);
  161. for (std::string const& f : objectFileTargets) {
  162. this->AppendTarget(fout, f, make, makeArgs, currentDir, homeOutputDir);
  163. }
  164. }
  165. fout << "\t] }\n";
  166. }
  167. void cmExtraKateGenerator::AppendTarget(cmGeneratedFileStream& fout,
  168. const std::string& target,
  169. const std::string& make,
  170. const std::string& makeArgs,
  171. const std::string& path,
  172. const std::string& homeOutputDir) const
  173. {
  174. static char JsonSep = ' ';
  175. fout << "\t\t\t" << JsonSep << R"({"name":")" << target
  176. << "\", "
  177. "\"build_cmd\":\""
  178. << make << " -C \\\"" << (this->UseNinja ? homeOutputDir : path)
  179. << "\\\" " << makeArgs << " " << target << "\"}\n";
  180. JsonSep = ',';
  181. }
  182. void cmExtraKateGenerator::CreateDummyKateProjectFile(
  183. const cmLocalGenerator& lg) const
  184. {
  185. std::string filename =
  186. cmStrCat(lg.GetBinaryDirectory(), '/', this->ProjectName, ".kateproject");
  187. cmGeneratedFileStream fout(filename);
  188. if (!fout) {
  189. return;
  190. }
  191. fout << "#Generated by " << cmSystemTools::GetCMakeCommand()
  192. << ", do not edit.\n";
  193. }
  194. std::string cmExtraKateGenerator::GenerateFilesString(
  195. const cmLocalGenerator& lg) const
  196. {
  197. const cmMakefile* mf = lg.GetMakefile();
  198. std::string mode =
  199. cmSystemTools::UpperCase(mf->GetSafeDefinition("CMAKE_KATE_FILES_MODE"));
  200. static const std::string gitString = "\"git\": 1 ";
  201. static const std::string svnString = "\"svn\": 1 ";
  202. static const std::string hgString = "\"hg\": 1 ";
  203. static const std::string fossilString = "\"fossil\": 1 ";
  204. if (mode == "SVN") {
  205. return svnString;
  206. }
  207. if (mode == "GIT") {
  208. return gitString;
  209. }
  210. if (mode == "HG") {
  211. return hgString;
  212. }
  213. if (mode == "FOSSIL") {
  214. return fossilString;
  215. }
  216. // check for the VCS files except when "forced" to "FILES" mode:
  217. if (mode != "LIST") {
  218. cmCMakePath startDir(lg.GetSourceDirectory(), cmCMakePath::auto_format);
  219. // move the directories up to the root directory to see whether we are in
  220. // a subdir of a svn, git, hg or fossil checkout
  221. for (;;) {
  222. std::string s = startDir.String() + "/.git";
  223. if (cmSystemTools::FileExists(s)) {
  224. return gitString;
  225. }
  226. s = startDir.String() + "/.svn";
  227. if (cmSystemTools::FileExists(s)) {
  228. return svnString;
  229. }
  230. s = startDir.String() + "/.hg";
  231. if (cmSystemTools::FileExists(s)) {
  232. return hgString;
  233. }
  234. s = startDir.String() + "/.fslckout";
  235. if (cmSystemTools::FileExists(s)) {
  236. return fossilString;
  237. }
  238. if (!startDir.HasRelativePath()) { // have we reached the root dir ?
  239. break;
  240. }
  241. startDir = startDir.GetParentPath();
  242. }
  243. }
  244. std::set<std::string> files;
  245. std::string tmp;
  246. const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
  247. for (const auto& lgen : lgs) {
  248. cmMakefile* makefile = lgen->GetMakefile();
  249. const std::vector<std::string>& listFiles = makefile->GetListFiles();
  250. for (std::string const& listFile : listFiles) {
  251. if (listFile.find("/CMakeFiles/") == std::string::npos) {
  252. files.insert(listFile);
  253. }
  254. }
  255. for (const auto& sf : makefile->GetSourceFiles()) {
  256. if (sf->GetIsGenerated()) {
  257. continue;
  258. }
  259. tmp = sf->ResolveFullPath();
  260. files.insert(tmp);
  261. }
  262. }
  263. const char* sep = "";
  264. tmp = "\"list\": [";
  265. for (std::string const& f : files) {
  266. tmp += sep;
  267. tmp += " \"";
  268. tmp += f;
  269. tmp += "\"";
  270. sep = ",";
  271. }
  272. tmp += "] ";
  273. return tmp;
  274. }
  275. std::string cmExtraKateGenerator::GenerateProjectName(
  276. const std::string& name, const std::string& type,
  277. const std::string& path) const
  278. {
  279. return name + (type.empty() ? "" : "-") + type + '@' + path;
  280. }
  281. std::string cmExtraKateGenerator::GetPathBasename(
  282. const std::string& path) const
  283. {
  284. std::string outputBasename = path;
  285. while (!outputBasename.empty() &&
  286. (outputBasename.back() == '/' || outputBasename.back() == '\\')) {
  287. outputBasename.resize(outputBasename.size() - 1);
  288. }
  289. std::string::size_type loc = outputBasename.find_last_of("/\\");
  290. if (loc != std::string::npos) {
  291. outputBasename = outputBasename.substr(loc + 1);
  292. }
  293. return outputBasename;
  294. }