cmTransformDepfile.cxx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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 "cmTransformDepfile.h"
  4. #include <functional>
  5. #include <string>
  6. #include <type_traits>
  7. #include <utility>
  8. #include <vector>
  9. #include <cm/optional>
  10. #include "cmsys/FStream.hxx"
  11. #include "cmGccDepfileReader.h"
  12. #include "cmGccDepfileReaderTypes.h"
  13. #include "cmGlobalGenerator.h"
  14. #include "cmLocalGenerator.h"
  15. #include "cmSystemTools.h"
  16. namespace {
  17. void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename)
  18. {
  19. for (auto c : filename) {
  20. switch (c) {
  21. case ' ':
  22. fout << "\\ ";
  23. break;
  24. case '\\':
  25. fout << "\\\\";
  26. break;
  27. default:
  28. fout << c;
  29. break;
  30. }
  31. }
  32. }
  33. void WriteDepfile(cmDepfileFormat format, cmsys::ofstream& fout,
  34. const cmLocalGenerator& lg,
  35. const cmGccDepfileContent& content)
  36. {
  37. const auto& binDir = lg.GetBinaryDirectory();
  38. std::function<std::string(const std::string&)> formatPath =
  39. [&lg, &binDir](const std::string& path) -> std::string {
  40. return lg.MaybeConvertToRelativePath(binDir, path);
  41. };
  42. if (lg.GetGlobalGenerator()->GetName() == "Xcode") {
  43. // full paths must be preserved for Xcode compliance
  44. formatPath = [](const std::string& path) -> std::string { return path; };
  45. }
  46. for (auto const& dep : content) {
  47. bool first = true;
  48. for (auto const& rule : dep.rules) {
  49. if (!first) {
  50. fout << " \\\n ";
  51. }
  52. first = false;
  53. WriteFilenameGcc(fout, formatPath(rule));
  54. }
  55. fout << ':';
  56. for (auto const& path : dep.paths) {
  57. fout << " \\\n ";
  58. WriteFilenameGcc(fout, formatPath(path));
  59. }
  60. fout << '\n';
  61. }
  62. if (format == cmDepfileFormat::MakeDepfile) {
  63. // In this case, phony targets must be added for all dependencies
  64. fout << "\n";
  65. for (auto const& dep : content) {
  66. for (auto const& path : dep.paths) {
  67. fout << "\n";
  68. WriteFilenameGcc(fout, formatPath(path));
  69. fout << ":\n";
  70. }
  71. }
  72. }
  73. }
  74. // tlog format : always windows paths on Windows regardless the generator
  75. std::string ConvertToTLogOutputPath(const std::string& path)
  76. {
  77. #if defined(_WIN32) && !defined(__CYGWIN__)
  78. return cmSystemTools::ConvertToWindowsOutputPath(path);
  79. #else
  80. return cmSystemTools::ConvertToOutputPath(path);
  81. #endif
  82. }
  83. void WriteVsTlog(cmsys::ofstream& fout, const cmLocalGenerator& lg,
  84. const cmGccDepfileContent& content)
  85. {
  86. const auto& binDir = lg.GetBinaryDirectory();
  87. for (auto const& dep : content) {
  88. fout << '^';
  89. bool first = true;
  90. for (auto const& rule : dep.rules) {
  91. if (!first) {
  92. fout << '|';
  93. }
  94. first = false;
  95. fout << ConvertToTLogOutputPath(
  96. lg.MaybeConvertToRelativePath(binDir, rule));
  97. }
  98. fout << "\r\n";
  99. for (auto const& path : dep.paths) {
  100. fout << ConvertToTLogOutputPath(
  101. lg.MaybeConvertToRelativePath(binDir, path))
  102. << "\r\n";
  103. }
  104. }
  105. }
  106. }
  107. bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
  108. const std::string& infile, const std::string& outfile)
  109. {
  110. cmGccDepfileContent content;
  111. if (cmSystemTools::FileExists(infile)) {
  112. auto result =
  113. cmReadGccDepfile(infile.c_str(), lg.GetCurrentBinaryDirectory());
  114. if (!result) {
  115. return false;
  116. }
  117. content = *std::move(result);
  118. }
  119. cmsys::ofstream fout(outfile.c_str());
  120. if (!fout) {
  121. return false;
  122. }
  123. switch (format) {
  124. case cmDepfileFormat::GccDepfile:
  125. case cmDepfileFormat::MakeDepfile:
  126. WriteDepfile(format, fout, lg, content);
  127. break;
  128. case cmDepfileFormat::VsTlog:
  129. WriteVsTlog(fout, lg, content);
  130. break;
  131. }
  132. return true;
  133. }