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 "cmExtraCodeLiteGenerator.h"
4 
5 #include <cstring>
6 #include <map>
7 #include <memory>
8 #include <set>
9 #include <sstream>
10 #include <utility>
11 
12 #include "cmsys/SystemInformation.hxx"
13 
14 #include "cmGeneratedFileStream.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalGenerator.h"
17 #include "cmLocalGenerator.h"
18 #include "cmMakefile.h"
19 #include "cmSourceFile.h"
20 #include "cmStateTypes.h"
21 #include "cmStringAlgorithms.h"
22 #include "cmSystemTools.h"
23 #include "cmXMLWriter.h"
24 #include "cmake.h"
25 
cmExtraCodeLiteGenerator()26 cmExtraCodeLiteGenerator::cmExtraCodeLiteGenerator()
27   : ConfigName("NoConfig")
28 {
29 }
30 
31 cmExternalMakefileProjectGeneratorFactory*
GetFactory()32 cmExtraCodeLiteGenerator::GetFactory()
33 {
34   static cmExternalMakefileProjectGeneratorSimpleFactory<
35     cmExtraCodeLiteGenerator>
36     factory("CodeLite", "Generates CodeLite project files.");
37 
38   if (factory.GetSupportedGlobalGenerators().empty()) {
39 #if defined(_WIN32)
40     factory.AddSupportedGlobalGenerator("MinGW Makefiles");
41     factory.AddSupportedGlobalGenerator("NMake Makefiles");
42 #endif
43     factory.AddSupportedGlobalGenerator("Ninja");
44     factory.AddSupportedGlobalGenerator("Unix Makefiles");
45   }
46 
47   return &factory;
48 }
49 
Generate()50 void cmExtraCodeLiteGenerator::Generate()
51 {
52   // Hold root tree information for creating the workspace
53   std::string workspaceProjectName;
54   std::string workspaceOutputDir;
55   std::string workspaceFileName;
56   std::string workspaceSourcePath;
57 
58   const std::map<std::string, std::vector<cmLocalGenerator*>>& projectMap =
59     this->GlobalGenerator->GetProjectMap();
60 
61   // loop projects and locate the root project.
62   // and extract the information for creating the worspace
63   // root makefile
64   for (auto const& it : projectMap) {
65     cmLocalGenerator* lg = it.second[0];
66     const cmMakefile* mf = lg->GetMakefile();
67     this->ConfigName = this->GetConfigurationName(mf);
68 
69     if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
70       workspaceOutputDir = lg->GetCurrentBinaryDirectory();
71       workspaceProjectName = lg->GetProjectName();
72       workspaceSourcePath = lg->GetSourceDirectory();
73       workspaceFileName =
74         cmStrCat(workspaceOutputDir, '/', workspaceProjectName, ".workspace");
75       this->WorkspacePath = lg->GetCurrentBinaryDirectory();
76       break;
77     }
78   }
79 
80   cmGeneratedFileStream fout(workspaceFileName);
81   cmXMLWriter xml(fout);
82 
83   xml.StartDocument("utf-8");
84   xml.StartElement("CodeLite_Workspace");
85   xml.Attribute("Name", workspaceProjectName);
86 
87   bool const targetsAreProjects =
88     this->GlobalGenerator->GlobalSettingIsOn("CMAKE_CODELITE_USE_TARGETS");
89 
90   std::vector<std::string> ProjectNames;
91   if (targetsAreProjects) {
92     ProjectNames = this->CreateProjectsByTarget(&xml);
93   } else {
94     ProjectNames = this->CreateProjectsByProjectMaps(&xml);
95   }
96 
97   xml.StartElement("BuildMatrix");
98   xml.StartElement("WorkspaceConfiguration");
99   xml.Attribute("Name", this->ConfigName);
100   xml.Attribute("Selected", "yes");
101 
102   for (std::string const& it : ProjectNames) {
103     xml.StartElement("Project");
104     xml.Attribute("Name", it);
105     xml.Attribute("ConfigName", this->ConfigName);
106     xml.EndElement();
107   }
108 
109   xml.EndElement(); // WorkspaceConfiguration
110   xml.EndElement(); // BuildMatrix
111   xml.EndElement(); // CodeLite_Workspace
112 }
113 
114 // Create projects where targets are the projects
CreateProjectsByTarget(cmXMLWriter * xml)115 std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByTarget(
116   cmXMLWriter* xml)
117 {
118   std::vector<std::string> retval;
119   // for each target in the workspace create a codelite project
120   const auto& lgs = this->GlobalGenerator->GetLocalGenerators();
121   for (const auto& lg : lgs) {
122     for (const auto& lt : lg->GetGeneratorTargets()) {
123       cmStateEnums::TargetType type = lt->GetType();
124       std::string const& outputDir = lg->GetCurrentBinaryDirectory();
125       std::string targetName = lt->GetName();
126       std::string filename = cmStrCat(outputDir, "/", targetName, ".project");
127       retval.push_back(targetName);
128       // Make the project file relative to the workspace
129       std::string relafilename =
130         cmSystemTools::RelativePath(this->WorkspacePath, filename);
131       std::string visualname = targetName;
132       switch (type) {
133         case cmStateEnums::SHARED_LIBRARY:
134         case cmStateEnums::STATIC_LIBRARY:
135         case cmStateEnums::MODULE_LIBRARY:
136           visualname = cmStrCat("lib", visualname);
137           CM_FALLTHROUGH;
138         case cmStateEnums::EXECUTABLE:
139           xml->StartElement("Project");
140           xml->Attribute("Name", visualname);
141           xml->Attribute("Path", relafilename);
142           xml->Attribute("Active", "No");
143           xml->EndElement();
144 
145           this->CreateNewProjectFile(lt.get(), filename);
146           break;
147         default:
148           break;
149       }
150     }
151   }
152   return retval;
153 }
154 
155 // The "older way of doing it.
CreateProjectsByProjectMaps(cmXMLWriter * xml)156 std::vector<std::string> cmExtraCodeLiteGenerator::CreateProjectsByProjectMaps(
157   cmXMLWriter* xml)
158 {
159   std::vector<std::string> retval;
160   // for each sub project in the workspace create a codelite project
161   for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
162 
163     std::string const& outputDir = it.second[0]->GetCurrentBinaryDirectory();
164     std::string projectName = it.second[0]->GetProjectName();
165     retval.push_back(projectName);
166     std::string filename = cmStrCat(outputDir, "/", projectName, ".project");
167 
168     // Make the project file relative to the workspace
169     filename = cmSystemTools::RelativePath(this->WorkspacePath, filename);
170 
171     // create a project file
172     this->CreateProjectFile(it.second);
173     xml->StartElement("Project");
174     xml->Attribute("Name", projectName);
175     xml->Attribute("Path", filename);
176     xml->Attribute("Active", "No");
177     xml->EndElement();
178   }
179   return retval;
180 }
181 
182 /* create the project file */
CreateProjectFile(const std::vector<cmLocalGenerator * > & lgs)183 void cmExtraCodeLiteGenerator::CreateProjectFile(
184   const std::vector<cmLocalGenerator*>& lgs)
185 {
186   std::string const& outputDir = lgs[0]->GetCurrentBinaryDirectory();
187   std::string projectName = lgs[0]->GetProjectName();
188   std::string filename = outputDir + "/";
189 
190   filename += projectName + ".project";
191   this->CreateNewProjectFile(lgs, filename);
192 }
193 
CollectSourceFiles(const cmMakefile * makefile,const cmGeneratorTarget * gt,std::map<std::string,cmSourceFile * > & cFiles,std::set<std::string> & otherFiles)194 std::string cmExtraCodeLiteGenerator::CollectSourceFiles(
195   const cmMakefile* makefile, const cmGeneratorTarget* gt,
196   std::map<std::string, cmSourceFile*>& cFiles,
197   std::set<std::string>& otherFiles)
198 {
199   std::string projectType;
200   switch (gt->GetType()) {
201     case cmStateEnums::EXECUTABLE: {
202       projectType = "Executable";
203     } break;
204     case cmStateEnums::STATIC_LIBRARY: {
205       projectType = "Static Library";
206     } break;
207     case cmStateEnums::SHARED_LIBRARY:
208     case cmStateEnums::MODULE_LIBRARY: {
209       projectType = "Dynamic Library";
210     } break;
211     default:
212       break;
213   }
214 
215   switch (gt->GetType()) {
216     case cmStateEnums::EXECUTABLE:
217     case cmStateEnums::STATIC_LIBRARY:
218     case cmStateEnums::SHARED_LIBRARY:
219     case cmStateEnums::MODULE_LIBRARY: {
220       cmake const* cm = makefile->GetCMakeInstance();
221       std::vector<cmSourceFile*> sources;
222       gt->GetSourceFiles(sources,
223                          makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
224       for (cmSourceFile* s : sources) {
225         std::string const& fullPath = s->ResolveFullPath();
226         std::string const& extLower =
227           cmSystemTools::LowerCase(s->GetExtension());
228         // check whether it is a source or a include file
229         // then put it accordingly into one of the two containers
230         if (cm->IsAKnownSourceExtension(extLower)) {
231           cFiles[fullPath] = s;
232         } else {
233           otherFiles.insert(fullPath);
234         }
235       }
236     } break;
237     default:
238       break;
239   }
240   return projectType;
241 }
242 
CreateNewProjectFile(const std::vector<cmLocalGenerator * > & lgs,const std::string & filename)243 void cmExtraCodeLiteGenerator::CreateNewProjectFile(
244   const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
245 {
246   const cmMakefile* mf = lgs[0]->GetMakefile();
247   cmGeneratedFileStream fout(filename);
248   if (!fout) {
249     return;
250   }
251   cmXMLWriter xml(fout);
252 
253   ////////////////////////////////////
254   xml.StartDocument("utf-8");
255   xml.StartElement("CodeLite_Project");
256   xml.Attribute("Name", lgs[0]->GetProjectName());
257   xml.Attribute("InternalType", "");
258 
259   std::string projectType;
260 
261   // Collect all used source files in the project
262   // Sort them into two containers, one for C/C++ implementation files
263   // which may have an accompanying header, one for all other files
264   std::map<std::string, cmSourceFile*> cFiles;
265   std::set<std::string> otherFiles;
266 
267   for (cmLocalGenerator* lg : lgs) {
268     cmMakefile* makefile = lg->GetMakefile();
269     for (const auto& target : lg->GetGeneratorTargets()) {
270       projectType =
271         this->CollectSourceFiles(makefile, target.get(), cFiles, otherFiles);
272     }
273   }
274 
275   // Get the project path ( we need it later to convert files to
276   // their relative path)
277   std::string projectPath = cmSystemTools::GetFilenamePath(filename);
278 
279   this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
280                                    projectType, "");
281 
282   xml.EndElement(); // CodeLite_Project
283 }
284 
FindMatchingHeaderfiles(std::map<std::string,cmSourceFile * > & cFiles,std::set<std::string> & otherFiles)285 void cmExtraCodeLiteGenerator::FindMatchingHeaderfiles(
286   std::map<std::string, cmSourceFile*>& cFiles,
287   std::set<std::string>& otherFiles)
288 {
289 
290   const std::vector<std::string>& headerExts =
291     this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
292 
293   // The following loop tries to add header files matching to implementation
294   // files to the project. It does that by iterating over all source files,
295   // replacing the file name extension with ".h" and checks whether such a
296   // file exists. If it does, it is inserted into the map of files.
297   // A very similar version of that code exists also in the CodeBlocks
298   // project generator.
299   for (auto const& sit : cFiles) {
300     std::string headerBasename =
301       cmStrCat(cmSystemTools::GetFilenamePath(sit.first), '/',
302                cmSystemTools::GetFilenameWithoutExtension(sit.first));
303 
304     // check if there's a matching header around
305     for (std::string const& ext : headerExts) {
306       std::string hname = cmStrCat(headerBasename, '.', ext);
307       // if it's already in the set, don't check if it exists on disk
308       auto headerIt = otherFiles.find(hname);
309       if (headerIt != otherFiles.end()) {
310         break;
311       }
312 
313       if (cmSystemTools::FileExists(hname)) {
314         otherFiles.insert(hname);
315         break;
316       }
317     }
318   }
319 }
320 
CreateFoldersAndFiles(std::set<std::string> & cFiles,cmXMLWriter & xml,const std::string & projectPath)321 void cmExtraCodeLiteGenerator::CreateFoldersAndFiles(
322   std::set<std::string>& cFiles, cmXMLWriter& xml,
323   const std::string& projectPath)
324 {
325   std::vector<std::string> tmp_path;
326   std::vector<std::string> components;
327   size_t numOfEndEl = 0;
328 
329   for (std::string const& cFile : cFiles) {
330     std::string frelapath = cmSystemTools::RelativePath(projectPath, cFile);
331     cmsys::SystemTools::SplitPath(frelapath, components, false);
332     components.pop_back(); // erase last member -> it is file, not folder
333     components.erase(components.begin()); // erase "root"
334 
335     size_t sizeOfSkip = 0;
336 
337     for (size_t i = 0; i < components.size(); ++i) {
338       // skip relative path
339       if (components[i] == ".." || components[i] == ".") {
340         sizeOfSkip++;
341         continue;
342       }
343 
344       // same folder
345       if (tmp_path.size() > i - sizeOfSkip &&
346           tmp_path[i - sizeOfSkip] == components[i]) {
347         continue;
348       }
349 
350       // delete "old" subfolders
351       if (tmp_path.size() > i - sizeOfSkip) {
352         numOfEndEl = tmp_path.size() - i + sizeOfSkip;
353         tmp_path.erase(tmp_path.end() - numOfEndEl, tmp_path.end());
354         for (; numOfEndEl--;) {
355           xml.EndElement();
356         }
357       }
358 
359       // add folder
360       xml.StartElement("VirtualDirectory");
361       xml.Attribute("Name", components[i]);
362       tmp_path.push_back(components[i]);
363     }
364 
365     // delete "old" subfolders
366     numOfEndEl = tmp_path.size() - components.size() + sizeOfSkip;
367     if (numOfEndEl) {
368       tmp_path.erase(tmp_path.end() - numOfEndEl, tmp_path.end());
369       for (; numOfEndEl--;) {
370         xml.EndElement();
371       }
372     }
373 
374     // add file
375     xml.StartElement("File");
376     xml.Attribute("Name", frelapath);
377     xml.EndElement();
378   }
379 
380   // end of folders
381   numOfEndEl = tmp_path.size();
382   for (; numOfEndEl--;) {
383     xml.EndElement();
384   }
385 }
386 
CreateFoldersAndFiles(std::map<std::string,cmSourceFile * > & cFiles,cmXMLWriter & xml,const std::string & projectPath)387 void cmExtraCodeLiteGenerator::CreateFoldersAndFiles(
388   std::map<std::string, cmSourceFile*>& cFiles, cmXMLWriter& xml,
389   const std::string& projectPath)
390 {
391   std::set<std::string> s;
392   for (auto const& it : cFiles) {
393     s.insert(it.first);
394   }
395   this->CreateFoldersAndFiles(s, xml, projectPath);
396 }
397 
CreateProjectSourceEntries(std::map<std::string,cmSourceFile * > & cFiles,std::set<std::string> & otherFiles,cmXMLWriter * _xml,const std::string & projectPath,const cmMakefile * mf,const std::string & projectType,const std::string & targetName)398 void cmExtraCodeLiteGenerator::CreateProjectSourceEntries(
399   std::map<std::string, cmSourceFile*>& cFiles,
400   std::set<std::string>& otherFiles, cmXMLWriter* _xml,
401   const std::string& projectPath, const cmMakefile* mf,
402   const std::string& projectType, const std::string& targetName)
403 {
404   cmXMLWriter& xml(*_xml);
405   this->FindMatchingHeaderfiles(cFiles, otherFiles);
406   // Create 2 virtual folders: src and include
407   // and place all the implementation files into the src
408   // folder, the rest goes to the include folder
409   xml.StartElement("VirtualDirectory");
410   xml.Attribute("Name", "src");
411 
412   // insert all source files in the codelite project
413   // first the C/C++ implementation files, then all others
414   this->CreateFoldersAndFiles(cFiles, xml, projectPath);
415   xml.EndElement(); // VirtualDirectory
416 
417   xml.StartElement("VirtualDirectory");
418   xml.Attribute("Name", "include");
419   this->CreateFoldersAndFiles(otherFiles, xml, projectPath);
420   xml.EndElement(); // VirtualDirectory
421 
422   // Get the number of CPUs. We use this information for the make -jN
423   // command
424   cmsys::SystemInformation info;
425   info.RunCPUCheck();
426 
427   this->CpuCount =
428     info.GetNumberOfLogicalCPU() * info.GetNumberOfPhysicalCPU();
429 
430   std::string codeliteCompilerName = this->GetCodeLiteCompilerName(mf);
431 
432   xml.StartElement("Settings");
433   xml.Attribute("Type", projectType);
434 
435   xml.StartElement("Configuration");
436   xml.Attribute("Name", this->ConfigName);
437   xml.Attribute("CompilerType", this->GetCodeLiteCompilerName(mf));
438   xml.Attribute("DebuggerType", "GNU gdb debugger");
439   xml.Attribute("Type", projectType);
440   xml.Attribute("BuildCmpWithGlobalSettings", "append");
441   xml.Attribute("BuildLnkWithGlobalSettings", "append");
442   xml.Attribute("BuildResWithGlobalSettings", "append");
443 
444   xml.StartElement("Compiler");
445   xml.Attribute("Options", "-g");
446   xml.Attribute("Required", "yes");
447   xml.Attribute("PreCompiledHeader", "");
448   xml.StartElement("IncludePath");
449   xml.Attribute("Value", ".");
450   xml.EndElement(); // IncludePath
451   xml.EndElement(); // Compiler
452 
453   xml.StartElement("Linker");
454   xml.Attribute("Options", "");
455   xml.Attribute("Required", "yes");
456   xml.EndElement(); // Linker
457 
458   xml.StartElement("ResourceCompiler");
459   xml.Attribute("Options", "");
460   xml.Attribute("Required", "no");
461   xml.EndElement(); // ResourceCompiler
462 
463   xml.StartElement("General");
464   std::string outputPath =
465     mf->GetSafeDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
466   if (outputPath.empty()) {
467     outputPath = mf->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
468   }
469   std::string relapath;
470   if (!outputPath.empty()) {
471     relapath = cmSystemTools::RelativePath(projectPath, outputPath);
472     xml.Attribute("OutputFile", relapath + "/$(ProjectName)");
473   } else {
474     xml.Attribute("OutputFile", "$(IntermediateDirectory)/$(ProjectName)");
475   }
476   xml.Attribute("IntermediateDirectory", "./");
477   xml.Attribute("Command", "./$(ProjectName)");
478   xml.Attribute("CommandArguments", "");
479   if (!outputPath.empty()) {
480     xml.Attribute("WorkingDirectory", relapath);
481   } else {
482     xml.Attribute("WorkingDirectory", "$(IntermediateDirectory)");
483   }
484   xml.Attribute("PauseExecWhenProcTerminates", "yes");
485   xml.EndElement(); // General
486 
487   xml.StartElement("Debugger");
488   xml.Attribute("IsRemote", "no");
489   xml.Attribute("RemoteHostName", "");
490   xml.Attribute("RemoteHostPort", "");
491   xml.Attribute("DebuggerPath", "");
492   xml.Element("PostConnectCommands");
493   xml.Element("StartupCommands");
494   xml.EndElement(); // Debugger
495 
496   xml.Element("PreBuild");
497   xml.Element("PostBuild");
498 
499   xml.StartElement("CustomBuild");
500   xml.Attribute("Enabled", "yes");
501   xml.Element("RebuildCommand", this->GetRebuildCommand(mf, targetName));
502   xml.Element("CleanCommand", this->GetCleanCommand(mf, targetName));
503   xml.Element("BuildCommand", this->GetBuildCommand(mf, targetName));
504   xml.Element("SingleFileCommand", this->GetSingleFileBuildCommand(mf));
505   xml.Element("PreprocessFileCommand");
506   xml.Element("WorkingDirectory", "$(WorkspacePath)");
507   xml.EndElement(); // CustomBuild
508 
509   xml.StartElement("AdditionalRules");
510   xml.Element("CustomPostBuild");
511   xml.Element("CustomPreBuild");
512   xml.EndElement(); // AdditionalRules
513 
514   xml.EndElement(); // Configuration
515   xml.StartElement("GlobalSettings");
516 
517   xml.StartElement("Compiler");
518   xml.Attribute("Options", "");
519   xml.StartElement("IncludePath");
520   xml.Attribute("Value", ".");
521   xml.EndElement(); // IncludePath
522   xml.EndElement(); // Compiler
523 
524   xml.StartElement("Linker");
525   xml.Attribute("Options", "");
526   xml.StartElement("LibraryPath");
527   xml.Attribute("Value", ".");
528   xml.EndElement(); // LibraryPath
529   xml.EndElement(); // Linker
530 
531   xml.StartElement("ResourceCompiler");
532   xml.Attribute("Options", "");
533   xml.EndElement(); // ResourceCompiler
534 
535   xml.EndElement(); // GlobalSettings
536   xml.EndElement(); // Settings
537 }
538 
CreateNewProjectFile(const cmGeneratorTarget * gt,const std::string & filename)539 void cmExtraCodeLiteGenerator::CreateNewProjectFile(
540   const cmGeneratorTarget* gt, const std::string& filename)
541 {
542   const cmMakefile* mf = gt->Makefile;
543   cmGeneratedFileStream fout(filename);
544   if (!fout) {
545     return;
546   }
547   cmXMLWriter xml(fout);
548 
549   ////////////////////////////////////
550   xml.StartDocument("utf-8");
551   xml.StartElement("CodeLite_Project");
552   std::string targetName = gt->GetName();
553   std::string visualname = targetName;
554   switch (gt->GetType()) {
555     case cmStateEnums::STATIC_LIBRARY:
556     case cmStateEnums::SHARED_LIBRARY:
557     case cmStateEnums::MODULE_LIBRARY:
558       visualname = "lib" + targetName;
559       break;
560     default:
561       break;
562   }
563   xml.Attribute("Name", visualname);
564   xml.Attribute("InternalType", "");
565 
566   // Collect all used source files in the project
567   // Sort them into two containers, one for C/C++ implementation files
568   // which may have an accompanying header, one for all other files
569   std::string projectType;
570 
571   std::map<std::string, cmSourceFile*> cFiles;
572   std::set<std::string> otherFiles;
573 
574   projectType = this->CollectSourceFiles(mf, gt, cFiles, otherFiles);
575 
576   // Get the project path ( we need it later to convert files to
577   // their relative path)
578   std::string projectPath = cmSystemTools::GetFilenamePath(filename);
579 
580   this->CreateProjectSourceEntries(cFiles, otherFiles, &xml, projectPath, mf,
581                                    projectType, targetName);
582 
583   xml.EndElement(); // CodeLite_Project
584 }
585 
GetCodeLiteCompilerName(const cmMakefile * mf) const586 std::string cmExtraCodeLiteGenerator::GetCodeLiteCompilerName(
587   const cmMakefile* mf) const
588 {
589   // figure out which language to use
590   // for now care only for C and C++
591   std::string compilerIdVar = "CMAKE_CXX_COMPILER_ID";
592   if (!this->GlobalGenerator->GetLanguageEnabled("CXX")) {
593     compilerIdVar = "CMAKE_C_COMPILER_ID";
594   }
595 
596   std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar);
597   std::string compiler = "gnu g++"; // default to g++
598 
599   // Since we need the compiler for parsing purposes only
600   // it does not matter if we use clang or clang++, same as
601   // "gnu gcc" vs "gnu g++"
602   if (compilerId == "MSVC") {
603     compiler = "VC++";
604   } else if (compilerId == "Clang") {
605     compiler = "clang++";
606   } else if (compilerId == "GNU") {
607     compiler = "gnu g++";
608   }
609   return compiler;
610 }
611 
GetConfigurationName(const cmMakefile * mf) const612 std::string cmExtraCodeLiteGenerator::GetConfigurationName(
613   const cmMakefile* mf) const
614 {
615   std::string confName = mf->GetSafeDefinition("CMAKE_BUILD_TYPE");
616   // Trim the configuration name from whitespaces (left and right)
617   confName.erase(0, confName.find_first_not_of(" \t\r\v\n"));
618   confName.erase(confName.find_last_not_of(" \t\r\v\n") + 1);
619   if (confName.empty()) {
620     confName = "NoConfig";
621   }
622   return confName;
623 }
624 
GetBuildCommand(const cmMakefile * mf,const std::string & targetName) const625 std::string cmExtraCodeLiteGenerator::GetBuildCommand(
626   const cmMakefile* mf, const std::string& targetName) const
627 {
628   const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
629   const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
630   std::string buildCommand = make; // Default
631   std::ostringstream ss;
632   if (generator == "NMake Makefiles" || generator == "Ninja") {
633     ss << make;
634   } else if (generator == "MinGW Makefiles" || generator == "Unix Makefiles") {
635     ss << make << " -f$(ProjectPath)/Makefile";
636     if (this->CpuCount > 0) {
637       ss << " -j " << this->CpuCount;
638     }
639   }
640   if (!targetName.empty()) {
641     ss << " " << targetName;
642   }
643   buildCommand = ss.str();
644   return buildCommand;
645 }
646 
GetCleanCommand(const cmMakefile * mf,const std::string & targetName) const647 std::string cmExtraCodeLiteGenerator::GetCleanCommand(
648   const cmMakefile* mf, const std::string& targetName) const
649 {
650   std::string generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
651   std::ostringstream ss;
652   std::string buildcommand = this->GetBuildCommand(mf, "");
653   if (!targetName.empty() && generator == "Ninja") {
654     ss << buildcommand << " -t clean " << targetName;
655   } else {
656     ss << buildcommand << " clean";
657   }
658   return ss.str();
659 }
660 
GetRebuildCommand(const cmMakefile * mf,const std::string & targetName) const661 std::string cmExtraCodeLiteGenerator::GetRebuildCommand(
662   const cmMakefile* mf, const std::string& targetName) const
663 {
664   return this->GetCleanCommand(mf, targetName) + " && " +
665     this->GetBuildCommand(mf, targetName);
666 }
667 
GetSingleFileBuildCommand(const cmMakefile * mf) const668 std::string cmExtraCodeLiteGenerator::GetSingleFileBuildCommand(
669   const cmMakefile* mf) const
670 {
671   std::string buildCommand;
672   const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
673   const std::string& generator = mf->GetSafeDefinition("CMAKE_GENERATOR");
674   if (generator == "Unix Makefiles" || generator == "MinGW Makefiles") {
675     std::ostringstream ss;
676 #if defined(_WIN32)
677     ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).obj";
678 #else
679     ss << make << " -f$(ProjectPath)/Makefile -B $(CurrentFileFullName).o";
680 #endif
681     buildCommand = ss.str();
682   }
683   return buildCommand;
684 }
685