Coverage Report

Created: 2026-10-28 06:38

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