resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmExtraCodeBlocksGenerator.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 "cmExtraCodeBlocksGenerator.h"
4
5 #include <map>
6 #include <memory>
7 #include <ostream>
8 #include <set>
9 #include <utility>
10
11 #include <cmext/algorithm>
12
13 #include "cmAlgorithms.h"
14 #include "cmGeneratedFileStream.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalGenerator.h"
17 #include "cmLocalGenerator.h"
18 #include "cmMakefile.h"
19 #include "cmRange.h"
20 #include "cmSourceFile.h"
21 #include "cmStateTypes.h"
22 #include "cmStringAlgorithms.h"
23 #include "cmSystemTools.h"
24 #include "cmValue.h"
25 #include "cmXMLWriter.h"
26 #include "cmake.h"
27
28 /* Some useful URLs:
29 Homepage:
30 http://www.codeblocks.org
31
32 File format docs:
33 http://wiki.codeblocks.org/index.php?title=File_formats_description
34 http://wiki.codeblocks.org/index.php?title=Workspace_file
35 http://wiki.codeblocks.org/index.php?title=Project_file
36
37 Discussion:
38 http://forums.codeblocks.org/index.php/topic,6789.0.html
39 */
40
41 cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() = default;
42
43 cmExternalMakefileProjectGeneratorFactory*
44 cmExtraCodeBlocksGenerator::GetFactory()
45 {
46   static cmExternalMakefileProjectGeneratorSimpleFactory<
47     cmExtraCodeBlocksGenerator>
48     factory("CodeBlocks", "Generates CodeBlocks project files.");
49
50   if (factory.GetSupportedGlobalGenerators().empty()) {
51 #if defined(_WIN32)
52     factory.AddSupportedGlobalGenerator("MinGW Makefiles");
53     factory.AddSupportedGlobalGenerator("NMake Makefiles");
54     factory.AddSupportedGlobalGenerator("NMake Makefiles JOM");
55 // disable until somebody actually tests it:
56 // this->AddSupportedGlobalGenerator("MSYS Makefiles");
57 #endif
58     factory.AddSupportedGlobalGenerator("Ninja");
59     factory.AddSupportedGlobalGenerator("Unix Makefiles");
60   }
61
62   return &factory;
63 }
64
65 void cmExtraCodeBlocksGenerator::Generate()
66 {
67   // for each sub project in the project create a codeblocks project
68   for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
69     // create a project file
70     this->CreateProjectFile(it.second);
71   }
72 }
73
74 /* create the project file */
75 void cmExtraCodeBlocksGenerator::CreateProjectFile(
76   const std::vector<cmLocalGenerator*>& lgs)
77 {
78   std::string outputDir = lgs[0]->GetCurrentBinaryDirectory();
79   std::string projectName = lgs[0]->GetProjectName();
80
81   std::string filename = cmStrCat(outputDir, '/', projectName, ".cbp");
82   std::string sessionFilename =
83     cmStrCat(outputDir, '/', projectName, ".layout");
84
85   this->CreateNewProjectFile(lgs, filename);
86 }
87
88 /* Tree is used to create a "Virtual Folder" in CodeBlocks, in which all
89  CMake files this project depends on will be put. This means additionally
90  to the "Sources" and "Headers" virtual folders of CodeBlocks, there will
91  now also be a "CMake Files" virtual folder.
92  Patch by Daniel Teske <daniel.teske AT nokia.com> (which use C::B project
93  files in QtCreator).*/
94 struct Tree
95 {
96   std::string path; // only one component of the path
97   std::vector<Tree> folders;
98   std::set<std::string> files;
99   void InsertPath(const std::vector<std::string>& split,
100                   std::vector<std::string>::size_type start,
101                   const std::string& fileName);
102   void BuildVirtualFolder(cmXMLWriter& xml) const;
103   void BuildVirtualFolderImpl(std::string& virtualFolders,
104                               const std::string& prefix) const;
105   void BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const;
106   void BuildUnitImpl(cmXMLWriter& xml, const std::string& virtualFolderPath,
107                      const std::string& fsPath) const;
108 };
109
110 void Tree::InsertPath(const std::vector<std::string>& split,
111                       std::vector<std::string>::size_type start,
112                       const std::string& fileName)
113 {
114   if (start == split.size()) {
115     this->files.insert(fileName);
116     return;
117   }
118   for (Tree& folder : this->folders) {
119     if (folder.path == split[start]) {
120       if (start + 1 < split.size()) {
121         folder.InsertPath(split, start + 1, fileName);
122         return;
123       }
124       // last part of split
125       folder.files.insert(fileName);
126       return;
127     }
128   }
129   // Not found in folders, thus insert
130   Tree newFolder;
131   newFolder.path = split[start];
132   if (start + 1 < split.size()) {
133     newFolder.InsertPath(split, start + 1, fileName);
134     this->folders.push_back(newFolder);
135     return;
136   }
137   // last part of split
138   newFolder.files.insert(fileName);
139   this->folders.push_back(newFolder);
140 }
141
142 void Tree::BuildVirtualFolder(cmXMLWriter& xml) const
143 {
144   xml.StartElement("Option");
145   std::string virtualFolders = "CMake Files\\;";
146   for (Tree const& folder : this->folders) {
147     folder.BuildVirtualFolderImpl(virtualFolders, "");
148   }
149   xml.Attribute("virtualFolders", virtualFolders);
150   xml.EndElement();
151 }
152
153 void Tree::BuildVirtualFolderImpl(std::string& virtualFolders,
154                                   const std::string& prefix) const
155 {
156   virtualFolders += "CMake Files\\" + prefix + this->path + "\\;";
157   for (Tree const& folder : this->folders) {
158     folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\");
159   }
160 }
161
162 void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const
163 {
164   for (std::string const& f : this->files) {
165     xml.StartElement("Unit");
166     xml.Attribute("filename", fsPath + f);
167
168     xml.StartElement("Option");
169     xml.Attribute("virtualFolder", "CMake Files\\");
170     xml.EndElement();
171
172     xml.EndElement();
173   }
174   for (Tree const& folder : this->folders) {
175     folder.BuildUnitImpl(xml, "", fsPath);
176   }
177 }
178
179 void Tree::BuildUnitImpl(cmXMLWriter& xml,
180                          const std::string& virtualFolderPath,
181                          const std::string& fsPath) const
182 {
183   for (std::string const& f : this->files) {
184     xml.StartElement("Unit");
185     xml.Attribute("filename", cmStrCat(fsPath, this->path, "/", f));
186
187     xml.StartElement("Option");
188     xml.Attribute(
189       "virtualFolder",
190       cmStrCat("CMake Files\\", virtualFolderPath, this->path, "\\"));
191     xml.EndElement();
192
193     xml.EndElement();
194   }
195   for (Tree const& folder : this->folders) {
196     folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, this->path, "\\"),
197                          cmStrCat(fsPath, this->path, "/"));
198   }
199 }
200
201 void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
202   const std::vector<cmLocalGenerator*>& lgs, const std::string& filename)
203 {
204   const cmMakefile* mf = lgs[0]->GetMakefile();
205   cmGeneratedFileStream fout(filename);
206   if (!fout) {
207     return;
208   }
209
210   Tree tree;
211
212   // build tree of virtual folders
213   for (auto const& it : this->GlobalGenerator->GetProjectMap()) {
214     // Collect all files
215     std::vector<std::string> listFiles;
216     for (cmLocalGenerator* lg : it.second) {
217       cm::append(listFiles, lg->GetMakefile()->GetListFiles());
218     }
219
220     // Convert
221     for (std::string const& listFile : listFiles) {
222       // don't put cmake's own files into the project (#12110):
223       if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) {
224         continue;
225       }
226
227       const std::string& relative = cmSystemTools::RelativePath(
228         it.second[0]->GetSourceDirectory(), listFile);
229       std::vector<std::string> split;
230       cmSystemTools::SplitPath(relative, split, false);
231       // Split filename from path
232       std::string fileName = *(split.end() - 1);
233       split.erase(split.end() - 1, split.end());
234
235       // We don't want paths with CMakeFiles in them
236       // or do we?
237       // In speedcrunch those where purely internal
238       //
239       // Also we can disable external (outside the project) files by setting ON
240       // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable.
241       const bool excludeExternal = it.second[0]->GetMakefile()->IsOn(
242         "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
243       if (!split.empty() &&
244           (!excludeExternal || (relative.find("..") == std::string::npos)) &&
245           relative.find("CMakeFiles") == std::string::npos) {
246         tree.InsertPath(split, 1, fileName);
247       }
248     }
249   }
250
251   // figure out the compiler
252   std::string compiler = this->GetCBCompilerId(mf);
253   const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
254   const std::string& makeArgs =
255     mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
256
257   cmXMLWriter xml(fout);
258   xml.StartDocument();
259   xml.StartElement("CodeBlocks_project_file");
260
261   xml.StartElement("FileVersion");
262   xml.Attribute("major", 1);
263   xml.Attribute("minor", 6);
264   xml.EndElement();
265
266   xml.StartElement("Project");
267
268   xml.StartElement("Option");
269   xml.Attribute("title", lgs[0]->GetProjectName());
270   xml.EndElement();
271
272   xml.StartElement("Option");
273   xml.Attribute("makefile_is_custom", 1);
274   xml.EndElement();
275
276   xml.StartElement("Option");
277   xml.Attribute("compiler", compiler);
278   xml.EndElement();
279
280   // Now build a virtual tree
281   tree.BuildVirtualFolder(xml);
282
283   xml.StartElement("Build");
284
285   this->AppendTarget(xml, "all", nullptr, make, lgs[0], compiler, makeArgs);
286
287   // add all executable and library targets and some of the GLOBAL
288   // and UTILITY targets
289   for (cmLocalGenerator* lg : lgs) {
290     const auto& targets = lg->GetGeneratorTargets();
291     for (const auto& target : targets) {
292       std::string targetName = target->GetName();
293       switch (target->GetType()) {
294         case cmStateEnums::GLOBAL_TARGET: {
295           // Only add the global targets from CMAKE_BINARY_DIR,
296           // not from the subdirs
297           if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) {
298             this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
299                                makeArgs);
300           }
301         } break;
302         case cmStateEnums::UTILITY:
303           // Add all utility targets, except the Nightly/Continuous/
304           // Experimental-"sub"targets as e.g. NightlyStart
305           if ((cmHasLiteralPrefix(targetName, "Nightly") &&
306                (targetName != "Nightly")) ||
307               (cmHasLiteralPrefix(targetName, "Continuous") &&
308                (targetName != "Continuous")) ||
309               (cmHasLiteralPrefix(targetName, "Experimental") &&
310                (targetName != "Experimental"))) {
311             break;
312           }
313
314           this->AppendTarget(xml, targetName, nullptr, make, lg, compiler,
315                              makeArgs);
316           break;
317         case cmStateEnums::EXECUTABLE:
318         case cmStateEnums::STATIC_LIBRARY:
319         case cmStateEnums::SHARED_LIBRARY:
320         case cmStateEnums::MODULE_LIBRARY:
321         case cmStateEnums::OBJECT_LIBRARY: {
322           cmGeneratorTarget* gt = target.get();
323           this->AppendTarget(xml, targetName, gt, make, lg, compiler,
324                              makeArgs);
325           std::string fastTarget = cmStrCat(targetName, "/fast");
326           this->AppendTarget(xml, fastTarget, gt, make, lg, compiler,
327                              makeArgs);
328         } break;
329         default:
330           break;
331       }
332     }
333   }
334
335   xml.EndElement(); // Build
336
337   // Collect all used source files in the project.
338   // Keep a list of C/C++ source files which might have an accompanying header
339   // that should be looked for.
340   using all_files_map_t = std::map<std::string, CbpUnit>;
341   all_files_map_t allFiles;
342   std::vector<std::string> cFiles;
343
344   auto* cm = this->GlobalGenerator->GetCMakeInstance();
345
346   for (cmLocalGenerator* lg : lgs) {
347     cmMakefile* makefile = lg->GetMakefile();
348     const auto& targets = lg->GetGeneratorTargets();
349     for (const auto& target : targets) {
350       switch (target->GetType()) {
351         case cmStateEnums::EXECUTABLE:
352         case cmStateEnums::STATIC_LIBRARY:
353         case cmStateEnums::SHARED_LIBRARY:
354         case cmStateEnums::MODULE_LIBRARY:
355         case cmStateEnums::OBJECT_LIBRARY:
356         case cmStateEnums::UTILITY: // can have sources since 2.6.3
357         {
358           std::vector<cmSourceFile*> sources;
359           target->GetSourceFiles(
360             sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"));
361           for (cmSourceFile* s : sources) {
362             // don't add source files from UTILITY target which have the
363             // GENERATED property set:
364             if (target->GetType() == cmStateEnums::UTILITY &&
365                 s->GetIsGenerated()) {
366               continue;
367             }
368
369             // check whether it is a C/C++/CUDA/HIP implementation file
370             bool isCFile = false;
371             std::string lang = s->GetOrDetermineLanguage();
372             if (lang == "C" || lang == "CXX" || lang == "CUDA" ||
373                 lang == "HIP") {
374               std::string const& srcext = s->GetExtension();
375               isCFile = cm->IsACLikeSourceExtension(srcext);
376             }
377
378             std::string const& fullPath = s->ResolveFullPath();
379
380             // Check file position relative to project root dir.
381             const std::string relative =
382               cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath);
383             // Do not add this file if it has ".." in relative path and
384             // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
385             const bool excludeExternal = lg->GetMakefile()->IsOn(
386               "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
387             if (excludeExternal &&
388                 (relative.find("..") != std::string::npos)) {
389               continue;
390             }
391
392             if (isCFile) {
393               cFiles.push_back(fullPath);
394             }
395
396             CbpUnit& cbpUnit = allFiles[fullPath];
397             cbpUnit.Targets.push_back(target.get());
398           }
399         } break;
400         default:
401           break;
402       }
403     }
404   }
405
406   std::vector<std::string> const& headerExts =
407     this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions();
408
409   // The following loop tries to add header files matching to implementation
410   // files to the project. It does that by iterating over all
411   // C/C++ source files,
412   // replacing the file name extension with ".h" and checks whether such a
413   // file exists. If it does, it is inserted into the map of files.
414   // A very similar version of that code exists also in the CodeLite
415   // project generator.
416   for (std::string const& fileName : cFiles) {
417     std::string headerBasename =
418       cmStrCat(cmSystemTools::GetFilenamePath(fileName), '/',
419                cmSystemTools::GetFilenameWithoutExtension(fileName));
420
421     // check if there's a matching header around
422     for (std::string const& ext : headerExts) {
423       std::string hname = cmStrCat(headerBasename, '.', ext);
424       // if it's already in the set, don't check if it exists on disk
425       if (allFiles.find(hname) != allFiles.end()) {
426         break;
427       }
428
429       if (cmSystemTools::FileExists(hname)) {
430         allFiles[hname].Targets = allFiles[fileName].Targets;
431         break;
432       }
433     }
434   }
435
436   // insert all source files in the CodeBlocks project
437   for (auto const& s : allFiles) {
438     std::string const& unitFilename = s.first;
439     CbpUnit const& unit = s.second;
440
441     xml.StartElement("Unit");
442     xml.Attribute("filename", unitFilename);
443
444     for (cmGeneratorTarget const* tgt : unit.Targets) {
445       xml.StartElement("Option");
446       xml.Attribute("target", tgt->GetName());
447       xml.EndElement();
448     }
449
450     xml.EndElement();
451   }
452
453   // Add CMakeLists.txt
454   tree.BuildUnit(xml, mf->GetHomeDirectory() + "/");
455
456   xml.EndElement(); // Project
457   xml.EndElement(); // CodeBlocks_project_file
458   xml.EndDocument();
459 }
460
461 // Write a dummy file for OBJECT libraries, so C::B can reference some file
462 std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
463   cmLocalGenerator* lg, cmGeneratorTarget* target) const
464 {
465   // this file doesn't seem to be used by C::B in custom makefile mode,
466   // but we generate a unique file for each OBJECT library so in case
467   // C::B uses it in some way, the targets don't interfere with each other.
468   std::string filename = cmStrCat(lg->GetCurrentBinaryDirectory(), '/',
469                                   lg->GetTargetDirectory(target), '/',
470                                   target->GetName(), ".objlib");
471   cmGeneratedFileStream fout(filename);
472   if (fout) {
473     /* clang-format off */
474     fout << "# This is a dummy file for the OBJECT library "
475          << target->GetName()
476          << " for the CMake CodeBlocks project generator.\n"
477          << "# Don't edit, this file will be overwritten.\n";
478     /* clang-format on */
479   }
480   return filename;
481 }
482
483 // Generate the xml code for one target.
484 void cmExtraCodeBlocksGenerator::AppendTarget(
485   cmXMLWriter& xml, const std::string& targetName, cmGeneratorTarget* target,
486   const std::string& make, const cmLocalGenerator* lg,
487   const std::string& compiler, const std::string& makeFlags)
488 {
489   cmMakefile const* makefile = lg->GetMakefile();
490   std::string makefileName =
491     cmStrCat(lg->GetCurrentBinaryDirectory(), "/Makefile");
492
493   xml.StartElement("Target");
494   xml.Attribute("title", targetName);
495
496   if (target != nullptr) {
497     int cbTargetType = this->GetCBTargetType(target);
498     std::string workingDir = lg->GetCurrentBinaryDirectory();
499     if (target->GetType() == cmStateEnums::EXECUTABLE) {
500       // Determine the directory where the executable target is created, and
501       // set the working directory to this dir.
502       cmValue runtimeOutputDir =
503         makefile->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
504       if (runtimeOutputDir) {
505         workingDir = *runtimeOutputDir;
506       } else {
507         cmValue executableOutputDir =
508           makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH");
509         if (executableOutputDir) {
510           workingDir = *executableOutputDir;
511         }
512       }
513     }
514
515     std::string buildType = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
516     std::string location;
517     if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
518       location =
519         this->CreateDummyTargetFile(const_cast<cmLocalGenerator*>(lg), target);
520     } else {
521       location = target->GetLocation(buildType);
522     }
523
524     xml.StartElement("Option");
525     xml.Attribute("output", location);
526     xml.Attribute("prefix_auto", 0);
527     xml.Attribute("extension_auto", 0);
528     xml.EndElement();
529
530     xml.StartElement("Option");
531     xml.Attribute("working_dir", workingDir);
532     xml.EndElement();
533
534     xml.StartElement("Option");
535     xml.Attribute("object_output", "./");
536     xml.EndElement();
537
538     xml.StartElement("Option");
539     xml.Attribute("type", cbTargetType);
540     xml.EndElement();
541
542     xml.StartElement("Option");
543     xml.Attribute("compiler", compiler);
544     xml.EndElement();
545
546     xml.StartElement("Compiler");
547
548     // the compilerdefines for this target
549     std::vector<std::string> cdefs;
550     target->GetCompileDefinitions(cdefs, buildType, "C");
551
552     // Expand the list.
553     for (std::string const& d : cdefs) {
554       xml.StartElement("Add");
555       xml.Attribute("option", "-D" + d);
556       xml.EndElement();
557     }
558
559     // the include directories for this target
560     std::vector<std::string> allIncludeDirs;
561     {
562       std::vector<std::string> includes;
563       lg->GetIncludeDirectories(includes, target, "C", buildType);
564       cm::append(allIncludeDirs, includes);
565     }
566
567     std::string systemIncludeDirs = makefile->GetSafeDefinition(
568       "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
569     if (!systemIncludeDirs.empty()) {
570       cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
571     }
572
573     systemIncludeDirs = makefile->GetSafeDefinition(
574       "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
575     if (!systemIncludeDirs.empty()) {
576       cm::append(allIncludeDirs, cmExpandedList(systemIncludeDirs));
577     }
578
579     auto end = cmRemoveDuplicates(allIncludeDirs);
580
581     for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) {
582       xml.StartElement("Add");
583       xml.Attribute("directory", str);
584       xml.EndElement();
585     }
586
587     xml.EndElement(); // Compiler
588   } else              // e.g. all and the GLOBAL and UTILITY targets
589   {
590     xml.StartElement("Option");
591     xml.Attribute("working_dir", lg->GetCurrentBinaryDirectory());
592     xml.EndElement();
593
594     xml.StartElement("Option");
595     xml.Attribute("type", 4);
596     xml.EndElement();
597   }
598
599   xml.StartElement("MakeCommands");
600
601   xml.StartElement("Build");
602   xml.Attribute(
603     "command",
604     this->BuildMakeCommand(make, makefileName, targetName, makeFlags));
605   xml.EndElement();
606
607   xml.StartElement("CompileFile");
608   xml.Attribute(
609     "command",
610     this->BuildMakeCommand(make, makefileName, "\"$file\"", makeFlags));
611   xml.EndElement();
612
613   xml.StartElement("Clean");
614   xml.Attribute(
615     "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
616   xml.EndElement();
617
618   xml.StartElement("DistClean");
619   xml.Attribute(
620     "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags));
621   xml.EndElement();
622
623   xml.EndElement(); // MakeCommands
624   xml.EndElement(); // Target
625 }
626
627 // Translate the cmake compiler id into the CodeBlocks compiler id
628 std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf)
629 {
630   // allow the user to overwrite the detected compiler
631   std::string userCompiler =
632     mf->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID");
633   if (!userCompiler.empty()) {
634     return userCompiler;
635   }
636
637   // figure out which language to use
638   // for now care only for C, C++, and Fortran
639
640   // projects with C/C++ and Fortran are handled as C/C++ projects
641   bool pureFortran = false;
642   std::string compilerIdVar;
643   if (this->GlobalGenerator->GetLanguageEnabled("CXX")) {
644     compilerIdVar = "CMAKE_CXX_COMPILER_ID";
645   } else if (this->GlobalGenerator->GetLanguageEnabled("C")) {
646     compilerIdVar = "CMAKE_C_COMPILER_ID";
647   } else if (this->GlobalGenerator->GetLanguageEnabled("Fortran")) {
648     compilerIdVar = "CMAKE_Fortran_COMPILER_ID";
649     pureFortran = true;
650   }
651
652   std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar);
653   std::string compiler = "gcc"; // default to gcc
654   if (compilerId == "MSVC") {
655     if (mf->IsDefinitionSet("MSVC10")) {
656       compiler = "msvc10";
657     } else {
658       compiler = "msvc8";
659     }
660   } else if (compilerId == "Borland") {
661     compiler = "bcc";
662   } else if (compilerId == "SDCC") {
663     compiler = "sdcc";
664   } else if (compilerId == "Intel") {
665     if (pureFortran && mf->IsDefinitionSet("WIN32")) {
666       compiler = "ifcwin"; // Intel Fortran for Windows (known by cbFortran)
667     } else {
668       compiler = "icc";
669     }
670   } else if (compilerId == "Watcom" || compilerId == "OpenWatcom") {
671     compiler = "ow";
672   } else if (compilerId == "Clang") {
673     compiler = "clang";
674   } else if (compilerId == "PGI") {
675     if (pureFortran) {
676       compiler = "pgifortran";
677     } else {
678       compiler = "pgi"; // does not exist as default in CodeBlocks 16.01
679     }
680   } else if (compilerId == "LCC") {
681     if (pureFortran) {
682       compiler = "lfortran";
683     } else {
684       compiler = "lcc";
685     }
686   } else if (compilerId == "GNU") {
687     if (pureFortran) {
688       compiler = "gfortran";
689     } else {
690       compiler = "gcc";
691     }
692   }
693   return compiler;
694 }
695
696 // Translate the cmake target type into the CodeBlocks target type id
697 int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target)
698 {
699   switch (target->GetType()) {
700     case cmStateEnums::EXECUTABLE:
701       if ((target->IsWin32Executable(
702             target->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) ||
703           (target->GetPropertyAsBool("MACOSX_BUNDLE"))) {
704         return 0;
705       }
706       return 1;
707     case cmStateEnums::STATIC_LIBRARY:
708     case cmStateEnums::OBJECT_LIBRARY:
709       return 2;
710     case cmStateEnums::SHARED_LIBRARY:
711     case cmStateEnums::MODULE_LIBRARY:
712       return 3;
713     default:
714       return 4;
715   }
716 }
717
718 // Create the command line for building the given target using the selected
719 // make
720 std::string cmExtraCodeBlocksGenerator::BuildMakeCommand(
721   const std::string& make, const std::string& makefile,
722   const std::string& target, const std::string& makeFlags)
723 {
724   std::string command = make;
725   if (!makeFlags.empty()) {
726     command += " ";
727     command += makeFlags;
728   }
729
730   std::string generator = this->GlobalGenerator->GetName();
731   if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") {
732     // For Windows ConvertToOutputPath already adds quotes when required.
733     // These need to be escaped, see
734     // https://gitlab.kitware.com/cmake/cmake/-/issues/13952
735     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
736     command += " /NOLOGO /f ";
737     command += makefileName;
738     command += " VERBOSE=1 ";
739     command += target;
740   } else if (generator == "MinGW Makefiles") {
741     // no escaping of spaces in this case, see
742     // https://gitlab.kitware.com/cmake/cmake/-/issues/10014
743     std::string const& makefileName = makefile;
744     command += " -f \"";
745     command += makefileName;
746     command += "\" ";
747     command += " VERBOSE=1 ";
748     command += target;
749   } else if (generator == "Ninja") {
750     command += " -v ";
751     command += target;
752   } else {
753     std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile);
754     command += " -f \"";
755     command += makefileName;
756     command += "\" ";
757     command += " VERBOSE=1 ";
758     command += target;
759   }
760   return command;
761 }