Coverage Report

Created: 2026-02-09 06:05

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