resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmTransformDepfile.cxx
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
5 #include <algorithm>
6 #include <functional>
7 #include <string>
8 #include <type_traits>
9 #include <utility>
10 #include <vector>
11
12 #include <cm/optional>
13
14 #include "cmsys/FStream.hxx"
15
16 #include "cmGccDepfileReader.h"
17 #include "cmGccDepfileReaderTypes.h"
18 #include "cmGlobalGenerator.h"
19 #include "cmLocalGenerator.h"
20 #include "cmSystemTools.h"
21
22 namespace {
23 void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename)
24 {
25   for (auto c : filename) {
26     switch (c) {
27       case ' ':
28         fout << "\\ ";
29         break;
30       case '\\':
31         fout << "\\\\";
32         break;
33       default:
34         fout << c;
35         break;
36     }
37   }
38 }
39
40 void WriteDepfile(cmDepfileFormat format, cmsys::ofstream& fout,
41                   const cmLocalGenerator& lg,
42                   const cmGccDepfileContent& content)
43 {
44   std::function<std::string(const std::string&)> formatPath =
45     [&lg](const std::string& path) -> std::string {
46     return lg.MaybeRelativeToTopBinDir(path);
47   };
48   if (lg.GetGlobalGenerator()->GetName() == "Xcode") {
49     // full paths must be preserved for Xcode compliance
50     formatPath = [](const std::string& path) -> std::string { return path; };
51   }
52
53   for (auto const& dep : content) {
54     bool first = true;
55     for (auto const& rule : dep.rules) {
56       if (!first) {
57         fout << " \\\n  ";
58       }
59       first = false;
60       WriteFilenameGcc(fout, formatPath(rule));
61     }
62     fout << ':';
63     for (auto const& path : dep.paths) {
64       fout << " \\\n  ";
65       WriteFilenameGcc(fout, formatPath(path));
66     }
67     fout << '\n';
68   }
69
70   if (format == cmDepfileFormat::MakeDepfile) {
71     // In this case, phony targets must be added for all dependencies
72     fout << "\n";
73     for (auto const& dep : content) {
74       for (auto const& path : dep.paths) {
75         fout << "\n";
76         WriteFilenameGcc(fout, formatPath(path));
77         fout << ":\n";
78       }
79     }
80   }
81 }
82
83 void WriteMSBuildAdditionalInputs(cmsys::ofstream& fout,
84                                   cmLocalGenerator const& lg,
85                                   cmGccDepfileContent const& content)
86 {
87   if (content.empty()) {
88     return;
89   }
90
91   // Write a UTF-8 BOM so MSBuild knows the encoding when reading the file.
92   static const char utf8bom[] = { static_cast<char>(0xEF),
93                                   static_cast<char>(0xBB),
94                                   static_cast<char>(0xBF) };
95   fout.write(utf8bom, sizeof(utf8bom));
96
97   // Write the format expected by MSBuild CustomBuild AdditionalInputs.
98   const char* sep = "";
99   for (const auto& c : content) {
100     for (std::string path : c.paths) {
101       if (!cmSystemTools::FileIsFullPath(path)) {
102         path = cmSystemTools::CollapseFullPath(path,
103                                                lg.GetCurrentBinaryDirectory());
104       }
105       std::replace(path.begin(), path.end(), '/', '\\');
106       fout << sep << path;
107       sep = ";";
108     }
109   }
110   fout << "\n";
111 }
112 }
113
114 bool cmTransformDepfile(cmDepfileFormat format, const cmLocalGenerator& lg,
115                         const std::string& infile, const std::string& outfile)
116 {
117   cmGccDepfileContent content;
118   if (cmSystemTools::FileExists(infile)) {
119     auto result =
120       cmReadGccDepfile(infile.c_str(), lg.GetCurrentBinaryDirectory());
121     if (!result) {
122       return false;
123     }
124     content = *std::move(result);
125   }
126
127   cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(outfile));
128   cmsys::ofstream fout(outfile.c_str());
129   if (!fout) {
130     return false;
131   }
132   switch (format) {
133     case cmDepfileFormat::GccDepfile:
134     case cmDepfileFormat::MakeDepfile:
135       WriteDepfile(format, fout, lg, content);
136       break;
137     case cmDepfileFormat::MSBuildAdditionalInputs:
138       WriteMSBuildAdditionalInputs(fout, lg, content);
139       break;
140   }
141   return true;
142 }