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