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"
11 #include <cmext/algorithm>
13 #include "cmAlgorithms.h"
14 #include "cmGeneratedFileStream.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalGenerator.h"
18 #include "cmLocalGenerator.h"
19 #include "cmMakefile.h"
21 #include "cmSourceFile.h"
22 #include "cmStateTypes.h"
23 #include "cmStringAlgorithms.h"
24 #include "cmSystemTools.h"
26 #include "cmXMLWriter.h"
31 http://www.codeblocks.org
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
39 http://forums.codeblocks.org/index.php/topic,6789.0.html
42 cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() = default;
44 cmExternalMakefileProjectGeneratorFactory
*
45 cmExtraCodeBlocksGenerator::GetFactory()
47 static cmExternalMakefileProjectGeneratorSimpleFactory
<
48 cmExtraCodeBlocksGenerator
>
49 factory("CodeBlocks", "Generates CodeBlocks project files (deprecated).");
51 if (factory
.GetSupportedGlobalGenerators().empty()) {
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");
59 factory
.AddSupportedGlobalGenerator("Ninja");
60 factory
.AddSupportedGlobalGenerator("Unix Makefiles");
66 void cmExtraCodeBlocksGenerator::Generate()
68 // for each sub project in the project create a codeblocks project
69 for (auto const& it
: this->GlobalGenerator
->GetProjectMap()) {
70 // create a project file
71 this->CreateProjectFile(it
.second
);
75 /* create the project file */
76 void cmExtraCodeBlocksGenerator::CreateProjectFile(
77 const std::vector
<cmLocalGenerator
*>& lgs
)
79 std::string outputDir
= lgs
[0]->GetCurrentBinaryDirectory();
80 std::string projectName
= lgs
[0]->GetProjectName();
82 std::string filename
= cmStrCat(outputDir
, '/', projectName
, ".cbp");
83 std::string sessionFilename
=
84 cmStrCat(outputDir
, '/', projectName
, ".layout");
86 this->CreateNewProjectFile(lgs
, filename
);
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).*/
97 std::string path
; // only one component of the path
98 std::vector
<Tree
> folders
;
99 std::set
<std::string
> files
;
100 void InsertPath(const std::vector
<std::string
>& split
,
101 std::vector
<std::string
>::size_type start
,
102 const std::string
& fileName
);
103 void BuildVirtualFolder(cmXMLWriter
& xml
) const;
104 void BuildVirtualFolderImpl(std::string
& virtualFolders
,
105 const std::string
& prefix
) const;
106 void BuildUnit(cmXMLWriter
& xml
, const std::string
& fsPath
) const;
107 void BuildUnitImpl(cmXMLWriter
& xml
, const std::string
& virtualFolderPath
,
108 const std::string
& fsPath
) const;
111 void Tree::InsertPath(const std::vector
<std::string
>& split
,
112 std::vector
<std::string
>::size_type start
,
113 const std::string
& fileName
)
115 if (start
== split
.size()) {
116 this->files
.insert(fileName
);
119 for (Tree
& folder
: this->folders
) {
120 if (folder
.path
== split
[start
]) {
121 if (start
+ 1 < split
.size()) {
122 folder
.InsertPath(split
, start
+ 1, fileName
);
125 // last part of split
126 folder
.files
.insert(fileName
);
130 // Not found in folders, thus insert
132 newFolder
.path
= split
[start
];
133 if (start
+ 1 < split
.size()) {
134 newFolder
.InsertPath(split
, start
+ 1, fileName
);
135 this->folders
.push_back(newFolder
);
138 // last part of split
139 newFolder
.files
.insert(fileName
);
140 this->folders
.push_back(newFolder
);
143 void Tree::BuildVirtualFolder(cmXMLWriter
& xml
) const
145 xml
.StartElement("Option");
146 std::string virtualFolders
= "CMake Files\\;";
147 for (Tree
const& folder
: this->folders
) {
148 folder
.BuildVirtualFolderImpl(virtualFolders
, "");
150 xml
.Attribute("virtualFolders", virtualFolders
);
154 void Tree::BuildVirtualFolderImpl(std::string
& virtualFolders
,
155 const std::string
& prefix
) const
157 virtualFolders
+= "CMake Files\\" + prefix
+ this->path
+ "\\;";
158 for (Tree
const& folder
: this->folders
) {
159 folder
.BuildVirtualFolderImpl(virtualFolders
, prefix
+ this->path
+ "\\");
163 void Tree::BuildUnit(cmXMLWriter
& xml
, const std::string
& fsPath
) const
165 for (std::string
const& f
: this->files
) {
166 xml
.StartElement("Unit");
167 xml
.Attribute("filename", fsPath
+ f
);
169 xml
.StartElement("Option");
170 xml
.Attribute("virtualFolder", "CMake Files\\");
175 for (Tree
const& folder
: this->folders
) {
176 folder
.BuildUnitImpl(xml
, "", fsPath
);
180 void Tree::BuildUnitImpl(cmXMLWriter
& xml
,
181 const std::string
& virtualFolderPath
,
182 const std::string
& fsPath
) const
184 for (std::string
const& f
: this->files
) {
185 xml
.StartElement("Unit");
186 xml
.Attribute("filename", cmStrCat(fsPath
, this->path
, "/", f
));
188 xml
.StartElement("Option");
191 cmStrCat("CMake Files\\", virtualFolderPath
, this->path
, "\\"));
196 for (Tree
const& folder
: this->folders
) {
197 folder
.BuildUnitImpl(xml
, cmStrCat(virtualFolderPath
, this->path
, "\\"),
198 cmStrCat(fsPath
, this->path
, "/"));
202 void cmExtraCodeBlocksGenerator::CreateNewProjectFile(
203 const std::vector
<cmLocalGenerator
*>& lgs
, const std::string
& filename
)
205 const cmMakefile
* mf
= lgs
[0]->GetMakefile();
206 cmGeneratedFileStream
fout(filename
);
213 // build tree of virtual folders
214 for (auto const& it
: this->GlobalGenerator
->GetProjectMap()) {
216 std::vector
<std::string
> listFiles
;
217 for (cmLocalGenerator
* lg
: it
.second
) {
218 cm::append(listFiles
, lg
->GetMakefile()->GetListFiles());
222 for (std::string
const& listFile
: listFiles
) {
223 // don't put cmake's own files into the project (#12110):
224 if (cmHasPrefix(listFile
, cmSystemTools::GetCMakeRoot())) {
228 const std::string
& relative
= cmSystemTools::RelativePath(
229 it
.second
[0]->GetSourceDirectory(), listFile
);
230 std::vector
<std::string
> split
;
231 cmSystemTools::SplitPath(relative
, split
, false);
232 // Split filename from path
233 std::string fileName
= *(split
.end() - 1);
234 split
.erase(split
.end() - 1, split
.end());
236 // We don't want paths with CMakeFiles in them
238 // In speedcrunch those where purely internal
240 // Also we can disable external (outside the project) files by setting ON
241 // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable.
242 const bool excludeExternal
= it
.second
[0]->GetMakefile()->IsOn(
243 "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
244 if (!split
.empty() &&
245 (!excludeExternal
|| (relative
.find("..") == std::string::npos
)) &&
246 relative
.find("CMakeFiles") == std::string::npos
) {
247 tree
.InsertPath(split
, 1, fileName
);
252 // figure out the compiler
253 std::string compiler
= this->GetCBCompilerId(mf
);
254 const std::string
& make
= mf
->GetRequiredDefinition("CMAKE_MAKE_PROGRAM");
255 const std::string
& makeArgs
=
256 mf
->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS");
258 cmXMLWriter
xml(fout
);
260 xml
.StartElement("CodeBlocks_project_file");
262 xml
.StartElement("FileVersion");
263 xml
.Attribute("major", 1);
264 xml
.Attribute("minor", 6);
267 xml
.StartElement("Project");
269 xml
.StartElement("Option");
270 xml
.Attribute("title", lgs
[0]->GetProjectName());
273 xml
.StartElement("Option");
274 xml
.Attribute("makefile_is_custom", 1);
277 xml
.StartElement("Option");
278 xml
.Attribute("compiler", compiler
);
281 // Now build a virtual tree
282 tree
.BuildVirtualFolder(xml
);
284 xml
.StartElement("Build");
286 this->AppendTarget(xml
, "all", nullptr, make
, lgs
[0], compiler
, makeArgs
);
288 // add all executable and library targets and some of the GLOBAL
289 // and UTILITY targets
290 for (cmLocalGenerator
* lg
: lgs
) {
291 const auto& targets
= lg
->GetGeneratorTargets();
292 for (const auto& target
: targets
) {
293 std::string targetName
= target
->GetName();
294 switch (target
->GetType()) {
295 case cmStateEnums::GLOBAL_TARGET
: {
296 // Only add the global targets from CMAKE_BINARY_DIR,
297 // not from the subdirs
298 if (lg
->GetCurrentBinaryDirectory() == lg
->GetBinaryDirectory()) {
299 this->AppendTarget(xml
, targetName
, nullptr, make
, lg
, compiler
,
303 case cmStateEnums::UTILITY
:
304 // Add all utility targets, except the Nightly/Continuous/
305 // Experimental-"sub"targets as e.g. NightlyStart
306 if ((cmHasLiteralPrefix(targetName
, "Nightly") &&
307 (targetName
!= "Nightly")) ||
308 (cmHasLiteralPrefix(targetName
, "Continuous") &&
309 (targetName
!= "Continuous")) ||
310 (cmHasLiteralPrefix(targetName
, "Experimental") &&
311 (targetName
!= "Experimental"))) {
315 this->AppendTarget(xml
, targetName
, nullptr, make
, lg
, compiler
,
318 case cmStateEnums::EXECUTABLE
:
319 case cmStateEnums::STATIC_LIBRARY
:
320 case cmStateEnums::SHARED_LIBRARY
:
321 case cmStateEnums::MODULE_LIBRARY
:
322 case cmStateEnums::OBJECT_LIBRARY
: {
323 cmGeneratorTarget
* gt
= target
.get();
324 this->AppendTarget(xml
, targetName
, gt
, make
, lg
, compiler
,
326 std::string fastTarget
= cmStrCat(targetName
, "/fast");
327 this->AppendTarget(xml
, fastTarget
, gt
, make
, lg
, compiler
,
336 xml
.EndElement(); // Build
338 // Collect all used source files in the project.
339 // Keep a list of C/C++ source files which might have an accompanying header
340 // that should be looked for.
341 using all_files_map_t
= std::map
<std::string
, CbpUnit
>;
342 all_files_map_t allFiles
;
343 std::vector
<std::string
> cFiles
;
345 auto* cm
= this->GlobalGenerator
->GetCMakeInstance();
347 for (cmLocalGenerator
* lg
: lgs
) {
348 cmMakefile
* makefile
= lg
->GetMakefile();
349 const auto& targets
= lg
->GetGeneratorTargets();
350 for (const auto& target
: targets
) {
351 switch (target
->GetType()) {
352 case cmStateEnums::EXECUTABLE
:
353 case cmStateEnums::STATIC_LIBRARY
:
354 case cmStateEnums::SHARED_LIBRARY
:
355 case cmStateEnums::MODULE_LIBRARY
:
356 case cmStateEnums::OBJECT_LIBRARY
:
357 case cmStateEnums::UTILITY
: // can have sources since 2.6.3
359 std::vector
<cmSourceFile
*> sources
;
360 target
->GetSourceFiles(
361 sources
, makefile
->GetSafeDefinition("CMAKE_BUILD_TYPE"));
362 for (cmSourceFile
* s
: sources
) {
363 // don't add source files from UTILITY target which have the
364 // GENERATED property set:
365 if (target
->GetType() == cmStateEnums::UTILITY
&&
366 s
->GetIsGenerated()) {
370 // check whether it is a C/C++/CUDA/HIP implementation file
371 bool isCFile
= false;
372 std::string lang
= s
->GetOrDetermineLanguage();
373 if (lang
== "C" || lang
== "CXX" || lang
== "CUDA" ||
375 std::string
const& srcext
= s
->GetExtension();
376 isCFile
= cm
->IsACLikeSourceExtension(srcext
);
379 std::string
const& fullPath
= s
->ResolveFullPath();
381 // Check file position relative to project root dir.
382 const std::string relative
=
383 cmSystemTools::RelativePath(lg
->GetSourceDirectory(), fullPath
);
384 // Do not add this file if it has ".." in relative path and
385 // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on.
386 const bool excludeExternal
= lg
->GetMakefile()->IsOn(
387 "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES");
388 if (excludeExternal
&&
389 (relative
.find("..") != std::string::npos
)) {
394 cFiles
.push_back(fullPath
);
397 CbpUnit
& cbpUnit
= allFiles
[fullPath
];
398 cbpUnit
.Targets
.push_back(target
.get());
407 std::vector
<std::string
> const& headerExts
=
408 this->GlobalGenerator
->GetCMakeInstance()->GetHeaderExtensions();
410 // The following loop tries to add header files matching to implementation
411 // files to the project. It does that by iterating over all
412 // C/C++ source files,
413 // replacing the file name extension with ".h" and checks whether such a
414 // file exists. If it does, it is inserted into the map of files.
415 // A very similar version of that code exists also in the CodeLite
416 // project generator.
417 for (std::string
const& fileName
: cFiles
) {
418 std::string headerBasename
=
419 cmStrCat(cmSystemTools::GetFilenamePath(fileName
), '/',
420 cmSystemTools::GetFilenameWithoutExtension(fileName
));
422 // check if there's a matching header around
423 for (std::string
const& ext
: headerExts
) {
424 std::string hname
= cmStrCat(headerBasename
, '.', ext
);
425 // if it's already in the set, don't check if it exists on disk
426 if (allFiles
.find(hname
) != allFiles
.end()) {
430 if (cmSystemTools::FileExists(hname
)) {
431 allFiles
[hname
].Targets
= allFiles
[fileName
].Targets
;
437 // insert all source files in the CodeBlocks project
438 for (auto const& s
: allFiles
) {
439 std::string
const& unitFilename
= s
.first
;
440 CbpUnit
const& unit
= s
.second
;
442 xml
.StartElement("Unit");
443 xml
.Attribute("filename", unitFilename
);
445 for (cmGeneratorTarget
const* tgt
: unit
.Targets
) {
446 xml
.StartElement("Option");
447 xml
.Attribute("target", tgt
->GetName());
454 // Add CMakeLists.txt
455 tree
.BuildUnit(xml
, mf
->GetHomeDirectory() + "/");
457 xml
.EndElement(); // Project
458 xml
.EndElement(); // CodeBlocks_project_file
462 // Write a dummy file for OBJECT libraries, so C::B can reference some file
463 std::string
cmExtraCodeBlocksGenerator::CreateDummyTargetFile(
464 cmLocalGenerator
* lg
, cmGeneratorTarget
* target
) const
466 // this file doesn't seem to be used by C::B in custom makefile mode,
467 // but we generate a unique file for each OBJECT library so in case
468 // C::B uses it in some way, the targets don't interfere with each other.
469 std::string filename
= cmStrCat(lg
->GetCurrentBinaryDirectory(), '/',
470 lg
->GetTargetDirectory(target
), '/',
471 target
->GetName(), ".objlib");
472 cmGeneratedFileStream
fout(filename
);
474 /* clang-format off */
475 fout
<< "# This is a dummy file for the OBJECT library "
477 << " for the CMake CodeBlocks project generator.\n"
478 << "# Don't edit, this file will be overwritten.\n";
479 /* clang-format on */
484 // Generate the xml code for one target.
485 void cmExtraCodeBlocksGenerator::AppendTarget(
486 cmXMLWriter
& xml
, const std::string
& targetName
, cmGeneratorTarget
* target
,
487 const std::string
& make
, const cmLocalGenerator
* lg
,
488 const std::string
& compiler
, const std::string
& makeFlags
)
490 cmMakefile
const* makefile
= lg
->GetMakefile();
491 std::string makefileName
=
492 cmStrCat(lg
->GetCurrentBinaryDirectory(), "/Makefile");
494 xml
.StartElement("Target");
495 xml
.Attribute("title", targetName
);
497 if (target
!= nullptr) {
498 int cbTargetType
= this->GetCBTargetType(target
);
499 std::string workingDir
= lg
->GetCurrentBinaryDirectory();
500 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 cmValue runtimeOutputDir
=
504 makefile
->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY");
505 if (runtimeOutputDir
) {
506 workingDir
= *runtimeOutputDir
;
508 cmValue executableOutputDir
=
509 makefile
->GetDefinition("EXECUTABLE_OUTPUT_PATH");
510 if (executableOutputDir
) {
511 workingDir
= *executableOutputDir
;
516 std::string buildType
= makefile
->GetSafeDefinition("CMAKE_BUILD_TYPE");
517 std::string location
;
518 if (target
->GetType() == cmStateEnums::OBJECT_LIBRARY
) {
520 this->CreateDummyTargetFile(const_cast<cmLocalGenerator
*>(lg
), target
);
522 location
= target
->GetLocation(buildType
);
525 xml
.StartElement("Option");
526 xml
.Attribute("output", location
);
527 xml
.Attribute("prefix_auto", 0);
528 xml
.Attribute("extension_auto", 0);
531 xml
.StartElement("Option");
532 xml
.Attribute("working_dir", workingDir
);
535 xml
.StartElement("Option");
536 xml
.Attribute("object_output", "./");
539 xml
.StartElement("Option");
540 xml
.Attribute("type", cbTargetType
);
543 xml
.StartElement("Option");
544 xml
.Attribute("compiler", compiler
);
547 xml
.StartElement("Compiler");
549 // the compilerdefines for this target
550 std::vector
<std::string
> cdefs
;
551 target
->GetCompileDefinitions(cdefs
, buildType
, "C");
554 for (std::string
const& d
: cdefs
) {
555 xml
.StartElement("Add");
556 xml
.Attribute("option", "-D" + d
);
560 // the include directories for this target
561 std::vector
<std::string
> allIncludeDirs
;
563 std::vector
<std::string
> includes
;
564 lg
->GetIncludeDirectories(includes
, target
, "C", buildType
);
565 cm::append(allIncludeDirs
, includes
);
568 std::string systemIncludeDirs
= makefile
->GetSafeDefinition(
569 "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS");
570 if (!systemIncludeDirs
.empty()) {
571 cm::append(allIncludeDirs
, cmList
{ systemIncludeDirs
});
574 systemIncludeDirs
= makefile
->GetSafeDefinition(
575 "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS");
576 if (!systemIncludeDirs
.empty()) {
577 cm::append(allIncludeDirs
, cmList
{ systemIncludeDirs
});
580 auto end
= cmRemoveDuplicates(allIncludeDirs
);
582 for (std::string
const& str
: cmMakeRange(allIncludeDirs
.cbegin(), end
)) {
583 xml
.StartElement("Add");
584 xml
.Attribute("directory", str
);
588 xml
.EndElement(); // Compiler
589 } else // e.g. all and the GLOBAL and UTILITY targets
591 xml
.StartElement("Option");
592 xml
.Attribute("working_dir", lg
->GetCurrentBinaryDirectory());
595 xml
.StartElement("Option");
596 xml
.Attribute("type", 4);
600 xml
.StartElement("MakeCommands");
602 xml
.StartElement("Build");
605 this->BuildMakeCommand(make
, makefileName
, targetName
, makeFlags
));
608 xml
.StartElement("CompileFile");
611 this->BuildMakeCommand(make
, makefileName
, "\"$file\"", makeFlags
));
614 xml
.StartElement("Clean");
616 "command", this->BuildMakeCommand(make
, makefileName
, "clean", makeFlags
));
619 xml
.StartElement("DistClean");
621 "command", this->BuildMakeCommand(make
, makefileName
, "clean", makeFlags
));
624 xml
.EndElement(); // MakeCommands
625 xml
.EndElement(); // Target
628 // Translate the cmake compiler id into the CodeBlocks compiler id
629 std::string
cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile
* mf
)
631 // allow the user to overwrite the detected compiler
632 std::string userCompiler
=
633 mf
->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID");
634 if (!userCompiler
.empty()) {
638 // figure out which language to use
639 // for now care only for C, C++, and Fortran
641 // projects with C/C++ and Fortran are handled as C/C++ projects
642 bool pureFortran
= false;
643 std::string compilerIdVar
;
644 if (this->GlobalGenerator
->GetLanguageEnabled("CXX")) {
645 compilerIdVar
= "CMAKE_CXX_COMPILER_ID";
646 } else if (this->GlobalGenerator
->GetLanguageEnabled("C")) {
647 compilerIdVar
= "CMAKE_C_COMPILER_ID";
648 } else if (this->GlobalGenerator
->GetLanguageEnabled("Fortran")) {
649 compilerIdVar
= "CMAKE_Fortran_COMPILER_ID";
653 std::string
const& compilerId
= mf
->GetSafeDefinition(compilerIdVar
);
654 std::string compiler
= "gcc"; // default to gcc
655 if (compilerId
== "MSVC") {
656 if (mf
->IsDefinitionSet("MSVC10")) {
661 } else if (compilerId
== "Borland") {
663 } else if (compilerId
== "SDCC") {
665 } else if (compilerId
== "Intel") {
666 if (pureFortran
&& mf
->IsDefinitionSet("WIN32")) {
667 compiler
= "ifcwin"; // Intel Fortran for Windows (known by cbFortran)
671 } else if (compilerId
== "Watcom" || compilerId
== "OpenWatcom") {
673 } else if (compilerId
== "Clang") {
675 } else if (compilerId
== "PGI") {
677 compiler
= "pgifortran";
679 compiler
= "pgi"; // does not exist as default in CodeBlocks 16.01
681 } else if (compilerId
== "LCC") {
683 compiler
= "lfortran";
687 } else if (compilerId
== "GNU") {
689 compiler
= "gfortran";
697 // Translate the cmake target type into the CodeBlocks target type id
698 int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget
* target
)
700 switch (target
->GetType()) {
701 case cmStateEnums::EXECUTABLE
:
702 if ((target
->IsWin32Executable(
703 target
->Makefile
->GetSafeDefinition("CMAKE_BUILD_TYPE"))) ||
704 (target
->GetPropertyAsBool("MACOSX_BUNDLE"))) {
708 case cmStateEnums::STATIC_LIBRARY
:
709 case cmStateEnums::OBJECT_LIBRARY
:
711 case cmStateEnums::SHARED_LIBRARY
:
712 case cmStateEnums::MODULE_LIBRARY
:
719 // Create the command line for building the given target using the selected
721 std::string
cmExtraCodeBlocksGenerator::BuildMakeCommand(
722 const std::string
& make
, const std::string
& makefile
,
723 const std::string
& target
, const std::string
& makeFlags
)
725 std::string command
= make
;
726 if (!makeFlags
.empty()) {
728 command
+= makeFlags
;
731 std::string generator
= this->GlobalGenerator
->GetName();
732 if (generator
== "NMake Makefiles" || generator
== "NMake Makefiles JOM") {
733 // For Windows ConvertToOutputPath already adds quotes when required.
734 // These need to be escaped, see
735 // https://gitlab.kitware.com/cmake/cmake/-/issues/13952
736 std::string makefileName
= cmSystemTools::ConvertToOutputPath(makefile
);
737 command
+= " /NOLOGO /f ";
738 command
+= makefileName
;
739 command
+= " VERBOSE=1 ";
741 } else if (generator
== "MinGW Makefiles") {
742 // no escaping of spaces in this case, see
743 // https://gitlab.kitware.com/cmake/cmake/-/issues/10014
744 std::string
const& makefileName
= makefile
;
746 command
+= makefileName
;
748 command
+= " VERBOSE=1 ";
750 } else if (generator
== "Ninja") {
754 std::string makefileName
= cmSystemTools::ConvertToOutputPath(makefile
);
756 command
+= makefileName
;
758 command
+= " VERBOSE=1 ";