| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file Copyright.txt or https://cmake.org/licensing for details. */ | |
| #include "cmExtraCodeBlocksGenerator.h" | |
| #include <map> | |
| #include <memory> | |
| #include <ostream> | |
| #include <set> | |
| #include <utility> | |
| #include <cmext/algorithm> | |
| #include "cmAlgorithms.h" | |
| #include "cmGeneratedFileStream.h" | |
| #include "cmGeneratorTarget.h" | |
| #include "cmGlobalGenerator.h" | |
| #include "cmList.h" | |
| #include "cmLocalGenerator.h" | |
| #include "cmMakefile.h" | |
| #include "cmRange.h" | |
| #include "cmSourceFile.h" | |
| #include "cmStateTypes.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| #include "cmValue.h" | |
| #include "cmXMLWriter.h" | |
| #include "cmake.h" | |
| /* Some useful URLs: | |
| Homepage: | |
| http://www.codeblocks.org | |
| File format docs: | |
| http://wiki.codeblocks.org/index.php?title=File_formats_description | |
| http://wiki.codeblocks.org/index.php?title=Workspace_file | |
| http://wiki.codeblocks.org/index.php?title=Project_file | |
| Discussion: | |
| http://forums.codeblocks.org/index.php/topic,6789.0.html | |
| */ | |
| cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator() = default; | |
| cmExternalMakefileProjectGeneratorFactory* | |
| cmExtraCodeBlocksGenerator::GetFactory() | |
| { | |
| static cmExternalMakefileProjectGeneratorSimpleFactory< | |
| cmExtraCodeBlocksGenerator> | |
| factory("CodeBlocks", "Generates CodeBlocks project files (deprecated)."); | |
| if (factory.GetSupportedGlobalGenerators().empty()) { | |
| #if defined(_WIN32) | |
| factory.AddSupportedGlobalGenerator("MinGW Makefiles"); | |
| factory.AddSupportedGlobalGenerator("NMake Makefiles"); | |
| factory.AddSupportedGlobalGenerator("NMake Makefiles JOM"); | |
| // disable until somebody actually tests it: | |
| // this->AddSupportedGlobalGenerator("MSYS Makefiles"); | |
| #endif | |
| factory.AddSupportedGlobalGenerator("Ninja"); | |
| factory.AddSupportedGlobalGenerator("Unix Makefiles"); | |
| } | |
| return &factory; | |
| } | |
| void cmExtraCodeBlocksGenerator::Generate() | |
| { | |
| // for each sub project in the project create a codeblocks project | |
| for (auto const& it : this->GlobalGenerator->GetProjectMap()) { | |
| // create a project file | |
| this->CreateProjectFile(it.second); | |
| } | |
| } | |
| /* create the project file */ | |
| void cmExtraCodeBlocksGenerator::CreateProjectFile( | |
| const std::vector<cmLocalGenerator*>& lgs) | |
| { | |
| std::string outputDir = lgs[0]->GetCurrentBinaryDirectory(); | |
| std::string projectName = lgs[0]->GetProjectName(); | |
| std::string filename = cmStrCat(outputDir, '/', projectName, ".cbp"); | |
| std::string sessionFilename = | |
| cmStrCat(outputDir, '/', projectName, ".layout"); | |
| this->CreateNewProjectFile(lgs, filename); | |
| } | |
| /* Tree is used to create a "Virtual Folder" in CodeBlocks, in which all | |
| CMake files this project depends on will be put. This means additionally | |
| to the "Sources" and "Headers" virtual folders of CodeBlocks, there will | |
| now also be a "CMake Files" virtual folder. | |
| Patch by Daniel Teske <daniel.teske AT nokia.com> (which use C::B project | |
| files in QtCreator).*/ | |
| struct Tree | |
| { | |
| std::string path; // only one component of the path | |
| std::vector<Tree> folders; | |
| std::set<std::string> files; | |
| void InsertPath(const std::vector<std::string>& split, | |
| std::vector<std::string>::size_type start, | |
| const std::string& fileName); | |
| void BuildVirtualFolder(cmXMLWriter& xml) const; | |
| void BuildVirtualFolderImpl(std::string& virtualFolders, | |
| const std::string& prefix) const; | |
| void BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const; | |
| void BuildUnitImpl(cmXMLWriter& xml, const std::string& virtualFolderPath, | |
| const std::string& fsPath) const; | |
| }; | |
| void Tree::InsertPath(const std::vector<std::string>& split, | |
| std::vector<std::string>::size_type start, | |
| const std::string& fileName) | |
| { | |
| if (start == split.size()) { | |
| this->files.insert(fileName); | |
| return; | |
| } | |
| for (Tree& folder : this->folders) { | |
| if (folder.path == split[start]) { | |
| if (start + 1 < split.size()) { | |
| folder.InsertPath(split, start + 1, fileName); | |
| return; | |
| } | |
| // last part of split | |
| folder.files.insert(fileName); | |
| return; | |
| } | |
| } | |
| // Not found in folders, thus insert | |
| Tree newFolder; | |
| newFolder.path = split[start]; | |
| if (start + 1 < split.size()) { | |
| newFolder.InsertPath(split, start + 1, fileName); | |
| this->folders.push_back(newFolder); | |
| return; | |
| } | |
| // last part of split | |
| newFolder.files.insert(fileName); | |
| this->folders.push_back(newFolder); | |
| } | |
| void Tree::BuildVirtualFolder(cmXMLWriter& xml) const | |
| { | |
| xml.StartElement("Option"); | |
| std::string virtualFolders = "CMake Files\\;"; | |
| for (Tree const& folder : this->folders) { | |
| folder.BuildVirtualFolderImpl(virtualFolders, ""); | |
| } | |
| xml.Attribute("virtualFolders", virtualFolders); | |
| xml.EndElement(); | |
| } | |
| void Tree::BuildVirtualFolderImpl(std::string& virtualFolders, | |
| const std::string& prefix) const | |
| { | |
| virtualFolders += "CMake Files\\" + prefix + this->path + "\\;"; | |
| for (Tree const& folder : this->folders) { | |
| folder.BuildVirtualFolderImpl(virtualFolders, prefix + this->path + "\\"); | |
| } | |
| } | |
| void Tree::BuildUnit(cmXMLWriter& xml, const std::string& fsPath) const | |
| { | |
| for (std::string const& f : this->files) { | |
| xml.StartElement("Unit"); | |
| xml.Attribute("filename", fsPath + f); | |
| xml.StartElement("Option"); | |
| xml.Attribute("virtualFolder", "CMake Files\\"); | |
| xml.EndElement(); | |
| xml.EndElement(); | |
| } | |
| for (Tree const& folder : this->folders) { | |
| folder.BuildUnitImpl(xml, "", fsPath); | |
| } | |
| } | |
| void Tree::BuildUnitImpl(cmXMLWriter& xml, | |
| const std::string& virtualFolderPath, | |
| const std::string& fsPath) const | |
| { | |
| for (std::string const& f : this->files) { | |
| xml.StartElement("Unit"); | |
| xml.Attribute("filename", cmStrCat(fsPath, this->path, "/", f)); | |
| xml.StartElement("Option"); | |
| xml.Attribute( | |
| "virtualFolder", | |
| cmStrCat("CMake Files\\", virtualFolderPath, this->path, "\\")); | |
| xml.EndElement(); | |
| xml.EndElement(); | |
| } | |
| for (Tree const& folder : this->folders) { | |
| folder.BuildUnitImpl(xml, cmStrCat(virtualFolderPath, this->path, "\\"), | |
| cmStrCat(fsPath, this->path, "/")); | |
| } | |
| } | |
| void cmExtraCodeBlocksGenerator::CreateNewProjectFile( | |
| const std::vector<cmLocalGenerator*>& lgs, const std::string& filename) | |
| { | |
| const cmMakefile* mf = lgs[0]->GetMakefile(); | |
| cmGeneratedFileStream fout(filename); | |
| if (!fout) { | |
| return; | |
| } | |
| Tree tree; | |
| // build tree of virtual folders | |
| for (auto const& it : this->GlobalGenerator->GetProjectMap()) { | |
| // Collect all files | |
| std::vector<std::string> listFiles; | |
| for (cmLocalGenerator* lg : it.second) { | |
| cm::append(listFiles, lg->GetMakefile()->GetListFiles()); | |
| } | |
| // Convert | |
| for (std::string const& listFile : listFiles) { | |
| // don't put cmake's own files into the project (#12110): | |
| if (cmHasPrefix(listFile, cmSystemTools::GetCMakeRoot())) { | |
| continue; | |
| } | |
| const std::string& relative = cmSystemTools::RelativePath( | |
| it.second[0]->GetSourceDirectory(), listFile); | |
| std::vector<std::string> split; | |
| cmSystemTools::SplitPath(relative, split, false); | |
| // Split filename from path | |
| std::string fileName = *(split.end() - 1); | |
| split.erase(split.end() - 1, split.end()); | |
| // We don't want paths with CMakeFiles in them | |
| // or do we? | |
| // In speedcrunch those where purely internal | |
| // | |
| // Also we can disable external (outside the project) files by setting ON | |
| // CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable. | |
| const bool excludeExternal = it.second[0]->GetMakefile()->IsOn( | |
| "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"); | |
| if (!split.empty() && | |
| (!excludeExternal || (relative.find("..") == std::string::npos)) && | |
| relative.find("CMakeFiles") == std::string::npos) { | |
| tree.InsertPath(split, 1, fileName); | |
| } | |
| } | |
| } | |
| // figure out the compiler | |
| std::string compiler = this->GetCBCompilerId(mf); | |
| const std::string& make = mf->GetRequiredDefinition("CMAKE_MAKE_PROGRAM"); | |
| const std::string& makeArgs = | |
| mf->GetSafeDefinition("CMAKE_CODEBLOCKS_MAKE_ARGUMENTS"); | |
| cmXMLWriter xml(fout); | |
| xml.StartDocument(); | |
| xml.StartElement("CodeBlocks_project_file"); | |
| xml.StartElement("FileVersion"); | |
| xml.Attribute("major", 1); | |
| xml.Attribute("minor", 6); | |
| xml.EndElement(); | |
| xml.StartElement("Project"); | |
| xml.StartElement("Option"); | |
| xml.Attribute("title", lgs[0]->GetProjectName()); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("makefile_is_custom", 1); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("compiler", compiler); | |
| xml.EndElement(); | |
| // Now build a virtual tree | |
| tree.BuildVirtualFolder(xml); | |
| xml.StartElement("Build"); | |
| this->AppendTarget(xml, "all", nullptr, make, lgs[0], compiler, makeArgs); | |
| // add all executable and library targets and some of the GLOBAL | |
| // and UTILITY targets | |
| for (cmLocalGenerator* lg : lgs) { | |
| const auto& targets = lg->GetGeneratorTargets(); | |
| for (const auto& target : targets) { | |
| std::string targetName = target->GetName(); | |
| switch (target->GetType()) { | |
| case cmStateEnums::GLOBAL_TARGET: { | |
| // Only add the global targets from CMAKE_BINARY_DIR, | |
| // not from the subdirs | |
| if (lg->GetCurrentBinaryDirectory() == lg->GetBinaryDirectory()) { | |
| this->AppendTarget(xml, targetName, nullptr, make, lg, compiler, | |
| makeArgs); | |
| } | |
| } break; | |
| case cmStateEnums::UTILITY: | |
| // Add all utility targets, except the Nightly/Continuous/ | |
| // Experimental-"sub"targets as e.g. NightlyStart | |
| if ((cmHasLiteralPrefix(targetName, "Nightly") && | |
| (targetName != "Nightly")) || | |
| (cmHasLiteralPrefix(targetName, "Continuous") && | |
| (targetName != "Continuous")) || | |
| (cmHasLiteralPrefix(targetName, "Experimental") && | |
| (targetName != "Experimental"))) { | |
| break; | |
| } | |
| this->AppendTarget(xml, targetName, nullptr, make, lg, compiler, | |
| makeArgs); | |
| break; | |
| case cmStateEnums::EXECUTABLE: | |
| case cmStateEnums::STATIC_LIBRARY: | |
| case cmStateEnums::SHARED_LIBRARY: | |
| case cmStateEnums::MODULE_LIBRARY: | |
| case cmStateEnums::OBJECT_LIBRARY: { | |
| cmGeneratorTarget* gt = target.get(); | |
| this->AppendTarget(xml, targetName, gt, make, lg, compiler, | |
| makeArgs); | |
| std::string fastTarget = cmStrCat(targetName, "/fast"); | |
| this->AppendTarget(xml, fastTarget, gt, make, lg, compiler, | |
| makeArgs); | |
| } break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| xml.EndElement(); // Build | |
| // Collect all used source files in the project. | |
| // Keep a list of C/C++ source files which might have an accompanying header | |
| // that should be looked for. | |
| using all_files_map_t = std::map<std::string, CbpUnit>; | |
| all_files_map_t allFiles; | |
| std::vector<std::string> cFiles; | |
| auto* cm = this->GlobalGenerator->GetCMakeInstance(); | |
| for (cmLocalGenerator* lg : lgs) { | |
| cmMakefile* makefile = lg->GetMakefile(); | |
| const auto& targets = lg->GetGeneratorTargets(); | |
| for (const auto& target : targets) { | |
| switch (target->GetType()) { | |
| case cmStateEnums::EXECUTABLE: | |
| case cmStateEnums::STATIC_LIBRARY: | |
| case cmStateEnums::SHARED_LIBRARY: | |
| case cmStateEnums::MODULE_LIBRARY: | |
| case cmStateEnums::OBJECT_LIBRARY: | |
| case cmStateEnums::UTILITY: // can have sources since 2.6.3 | |
| { | |
| std::vector<cmSourceFile*> sources; | |
| target->GetSourceFiles( | |
| sources, makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); | |
| for (cmSourceFile* s : sources) { | |
| // don't add source files from UTILITY target which have the | |
| // GENERATED property set: | |
| if (target->GetType() == cmStateEnums::UTILITY && | |
| s->GetIsGenerated()) { | |
| continue; | |
| } | |
| // check whether it is a C/C++/CUDA/HIP implementation file | |
| bool isCFile = false; | |
| std::string lang = s->GetOrDetermineLanguage(); | |
| if (lang == "C" || lang == "CXX" || lang == "CUDA" || | |
| lang == "HIP") { | |
| std::string const& srcext = s->GetExtension(); | |
| isCFile = cm->IsACLikeSourceExtension(srcext); | |
| } | |
| std::string const& fullPath = s->ResolveFullPath(); | |
| // Check file position relative to project root dir. | |
| const std::string relative = | |
| cmSystemTools::RelativePath(lg->GetSourceDirectory(), fullPath); | |
| // Do not add this file if it has ".." in relative path and | |
| // if CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES variable is on. | |
| const bool excludeExternal = lg->GetMakefile()->IsOn( | |
| "CMAKE_CODEBLOCKS_EXCLUDE_EXTERNAL_FILES"); | |
| if (excludeExternal && | |
| (relative.find("..") != std::string::npos)) { | |
| continue; | |
| } | |
| if (isCFile) { | |
| cFiles.push_back(fullPath); | |
| } | |
| CbpUnit& cbpUnit = allFiles[fullPath]; | |
| cbpUnit.Targets.push_back(target.get()); | |
| } | |
| } break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| std::vector<std::string> const& headerExts = | |
| this->GlobalGenerator->GetCMakeInstance()->GetHeaderExtensions(); | |
| // The following loop tries to add header files matching to implementation | |
| // files to the project. It does that by iterating over all | |
| // C/C++ source files, | |
| // replacing the file name extension with ".h" and checks whether such a | |
| // file exists. If it does, it is inserted into the map of files. | |
| // A very similar version of that code exists also in the CodeLite | |
| // project generator. | |
| for (std::string const& fileName : cFiles) { | |
| std::string headerBasename = | |
| cmStrCat(cmSystemTools::GetFilenamePath(fileName), '/', | |
| cmSystemTools::GetFilenameWithoutExtension(fileName)); | |
| // check if there's a matching header around | |
| for (std::string const& ext : headerExts) { | |
| std::string hname = cmStrCat(headerBasename, '.', ext); | |
| // if it's already in the set, don't check if it exists on disk | |
| if (allFiles.find(hname) != allFiles.end()) { | |
| break; | |
| } | |
| if (cmSystemTools::FileExists(hname)) { | |
| allFiles[hname].Targets = allFiles[fileName].Targets; | |
| break; | |
| } | |
| } | |
| } | |
| // insert all source files in the CodeBlocks project | |
| for (auto const& s : allFiles) { | |
| std::string const& unitFilename = s.first; | |
| CbpUnit const& unit = s.second; | |
| xml.StartElement("Unit"); | |
| xml.Attribute("filename", unitFilename); | |
| for (cmGeneratorTarget const* tgt : unit.Targets) { | |
| xml.StartElement("Option"); | |
| xml.Attribute("target", tgt->GetName()); | |
| xml.EndElement(); | |
| } | |
| xml.EndElement(); | |
| } | |
| // Add CMakeLists.txt | |
| tree.BuildUnit(xml, mf->GetHomeDirectory() + "/"); | |
| xml.EndElement(); // Project | |
| xml.EndElement(); // CodeBlocks_project_file | |
| xml.EndDocument(); | |
| } | |
| // Write a dummy file for OBJECT libraries, so C::B can reference some file | |
| std::string cmExtraCodeBlocksGenerator::CreateDummyTargetFile( | |
| cmLocalGenerator* lg, cmGeneratorTarget* target) const | |
| { | |
| // this file doesn't seem to be used by C::B in custom makefile mode, | |
| // but we generate a unique file for each OBJECT library so in case | |
| // C::B uses it in some way, the targets don't interfere with each other. | |
| std::string filename = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', | |
| lg->GetTargetDirectory(target), '/', | |
| target->GetName(), ".objlib"); | |
| cmGeneratedFileStream fout(filename); | |
| if (fout) { | |
| /* clang-format off */ | |
| fout << "# This is a dummy file for the OBJECT library " | |
| << target->GetName() | |
| << " for the CMake CodeBlocks project generator.\n" | |
| << "# Don't edit, this file will be overwritten.\n"; | |
| /* clang-format on */ | |
| } | |
| return filename; | |
| } | |
| // Generate the xml code for one target. | |
| void cmExtraCodeBlocksGenerator::AppendTarget( | |
| cmXMLWriter& xml, const std::string& targetName, cmGeneratorTarget* target, | |
| const std::string& make, const cmLocalGenerator* lg, | |
| const std::string& compiler, const std::string& makeFlags) | |
| { | |
| cmMakefile const* makefile = lg->GetMakefile(); | |
| std::string makefileName = | |
| cmStrCat(lg->GetCurrentBinaryDirectory(), "/Makefile"); | |
| xml.StartElement("Target"); | |
| xml.Attribute("title", targetName); | |
| if (target != nullptr) { | |
| int cbTargetType = this->GetCBTargetType(target); | |
| std::string workingDir = lg->GetCurrentBinaryDirectory(); | |
| if (target->GetType() == cmStateEnums::EXECUTABLE) { | |
| // Determine the directory where the executable target is created, and | |
| // set the working directory to this dir. | |
| cmValue runtimeOutputDir = | |
| makefile->GetDefinition("CMAKE_RUNTIME_OUTPUT_DIRECTORY"); | |
| if (runtimeOutputDir) { | |
| workingDir = *runtimeOutputDir; | |
| } else { | |
| cmValue executableOutputDir = | |
| makefile->GetDefinition("EXECUTABLE_OUTPUT_PATH"); | |
| if (executableOutputDir) { | |
| workingDir = *executableOutputDir; | |
| } | |
| } | |
| } | |
| std::string buildType = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); | |
| std::string location; | |
| if (target->GetType() == cmStateEnums::OBJECT_LIBRARY) { | |
| location = | |
| this->CreateDummyTargetFile(const_cast<cmLocalGenerator*>(lg), target); | |
| } else { | |
| location = target->GetLocation(buildType); | |
| } | |
| xml.StartElement("Option"); | |
| xml.Attribute("output", location); | |
| xml.Attribute("prefix_auto", 0); | |
| xml.Attribute("extension_auto", 0); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("working_dir", workingDir); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("object_output", "./"); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("type", cbTargetType); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("compiler", compiler); | |
| xml.EndElement(); | |
| xml.StartElement("Compiler"); | |
| // the compilerdefines for this target | |
| std::vector<std::string> cdefs; | |
| target->GetCompileDefinitions(cdefs, buildType, "C"); | |
| // Expand the list. | |
| for (std::string const& d : cdefs) { | |
| xml.StartElement("Add"); | |
| xml.Attribute("option", "-D" + d); | |
| xml.EndElement(); | |
| } | |
| // the include directories for this target | |
| std::vector<std::string> allIncludeDirs; | |
| { | |
| std::vector<std::string> includes; | |
| lg->GetIncludeDirectories(includes, target, "C", buildType); | |
| cm::append(allIncludeDirs, includes); | |
| } | |
| std::string systemIncludeDirs = makefile->GetSafeDefinition( | |
| "CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS"); | |
| if (!systemIncludeDirs.empty()) { | |
| cm::append(allIncludeDirs, cmList{ systemIncludeDirs }); | |
| } | |
| systemIncludeDirs = makefile->GetSafeDefinition( | |
| "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); | |
| if (!systemIncludeDirs.empty()) { | |
| cm::append(allIncludeDirs, cmList{ systemIncludeDirs }); | |
| } | |
| auto end = cmRemoveDuplicates(allIncludeDirs); | |
| for (std::string const& str : cmMakeRange(allIncludeDirs.cbegin(), end)) { | |
| xml.StartElement("Add"); | |
| xml.Attribute("directory", str); | |
| xml.EndElement(); | |
| } | |
| xml.EndElement(); // Compiler | |
| } else // e.g. all and the GLOBAL and UTILITY targets | |
| { | |
| xml.StartElement("Option"); | |
| xml.Attribute("working_dir", lg->GetCurrentBinaryDirectory()); | |
| xml.EndElement(); | |
| xml.StartElement("Option"); | |
| xml.Attribute("type", 4); | |
| xml.EndElement(); | |
| } | |
| xml.StartElement("MakeCommands"); | |
| xml.StartElement("Build"); | |
| xml.Attribute( | |
| "command", | |
| this->BuildMakeCommand(make, makefileName, targetName, makeFlags)); | |
| xml.EndElement(); | |
| xml.StartElement("CompileFile"); | |
| xml.Attribute( | |
| "command", | |
| this->BuildMakeCommand(make, makefileName, "\"$file\"", makeFlags)); | |
| xml.EndElement(); | |
| xml.StartElement("Clean"); | |
| xml.Attribute( | |
| "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags)); | |
| xml.EndElement(); | |
| xml.StartElement("DistClean"); | |
| xml.Attribute( | |
| "command", this->BuildMakeCommand(make, makefileName, "clean", makeFlags)); | |
| xml.EndElement(); | |
| xml.EndElement(); // MakeCommands | |
| xml.EndElement(); // Target | |
| } | |
| // Translate the cmake compiler id into the CodeBlocks compiler id | |
| std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) | |
| { | |
| // allow the user to overwrite the detected compiler | |
| std::string userCompiler = | |
| mf->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID"); | |
| if (!userCompiler.empty()) { | |
| return userCompiler; | |
| } | |
| // figure out which language to use | |
| // for now care only for C, C++, and Fortran | |
| // projects with C/C++ and Fortran are handled as C/C++ projects | |
| bool pureFortran = false; | |
| std::string compilerIdVar; | |
| if (this->GlobalGenerator->GetLanguageEnabled("CXX")) { | |
| compilerIdVar = "CMAKE_CXX_COMPILER_ID"; | |
| } else if (this->GlobalGenerator->GetLanguageEnabled("C")) { | |
| compilerIdVar = "CMAKE_C_COMPILER_ID"; | |
| } else if (this->GlobalGenerator->GetLanguageEnabled("Fortran")) { | |
| compilerIdVar = "CMAKE_Fortran_COMPILER_ID"; | |
| pureFortran = true; | |
| } | |
| std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar); | |
| std::string compiler = "gcc"; // default to gcc | |
| if (compilerId == "MSVC") { | |
| if (mf->IsDefinitionSet("MSVC10")) { | |
| compiler = "msvc10"; | |
| } else { | |
| compiler = "msvc8"; | |
| } | |
| } else if (compilerId == "Borland") { | |
| compiler = "bcc"; | |
| } else if (compilerId == "SDCC") { | |
| compiler = "sdcc"; | |
| } else if (compilerId == "Intel") { | |
| if (pureFortran && mf->IsDefinitionSet("WIN32")) { | |
| compiler = "ifcwin"; // Intel Fortran for Windows (known by cbFortran) | |
| } else { | |
| compiler = "icc"; | |
| } | |
| } else if (compilerId == "Watcom" || compilerId == "OpenWatcom") { | |
| compiler = "ow"; | |
| } else if (compilerId == "Clang") { | |
| compiler = "clang"; | |
| } else if (compilerId == "PGI") { | |
| if (pureFortran) { | |
| compiler = "pgifortran"; | |
| } else { | |
| compiler = "pgi"; // does not exist as default in CodeBlocks 16.01 | |
| } | |
| } else if (compilerId == "LCC") { | |
| if (pureFortran) { | |
| compiler = "lfortran"; | |
| } else { | |
| compiler = "lcc"; | |
| } | |
| } else if (compilerId == "GNU") { | |
| if (pureFortran) { | |
| compiler = "gfortran"; | |
| } else { | |
| compiler = "gcc"; | |
| } | |
| } | |
| return compiler; | |
| } | |
| // Translate the cmake target type into the CodeBlocks target type id | |
| int cmExtraCodeBlocksGenerator::GetCBTargetType(cmGeneratorTarget* target) | |
| { | |
| switch (target->GetType()) { | |
| case cmStateEnums::EXECUTABLE: | |
| if ((target->IsWin32Executable( | |
| target->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) || | |
| (target->GetPropertyAsBool("MACOSX_BUNDLE"))) { | |
| return 0; | |
| } | |
| return 1; | |
| case cmStateEnums::STATIC_LIBRARY: | |
| case cmStateEnums::OBJECT_LIBRARY: | |
| return 2; | |
| case cmStateEnums::SHARED_LIBRARY: | |
| case cmStateEnums::MODULE_LIBRARY: | |
| return 3; | |
| default: | |
| return 4; | |
| } | |
| } | |
| // Create the command line for building the given target using the selected | |
| // make | |
| std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( | |
| const std::string& make, const std::string& makefile, | |
| const std::string& target, const std::string& makeFlags) | |
| { | |
| std::string command = make; | |
| if (!makeFlags.empty()) { | |
| command += " "; | |
| command += makeFlags; | |
| } | |
| std::string generator = this->GlobalGenerator->GetName(); | |
| if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") { | |
| // For Windows ConvertToOutputPath already adds quotes when required. | |
| // These need to be escaped, see | |
| // https://gitlab.kitware.com/cmake/cmake/-/issues/13952 | |
| std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); | |
| command += " /NOLOGO /f "; | |
| command += makefileName; | |
| command += " VERBOSE=1 "; | |
| command += target; | |
| } else if (generator == "MinGW Makefiles") { | |
| // no escaping of spaces in this case, see | |
| // https://gitlab.kitware.com/cmake/cmake/-/issues/10014 | |
| std::string const& makefileName = makefile; | |
| command += " -f \""; | |
| command += makefileName; | |
| command += "\" "; | |
| command += " VERBOSE=1 "; | |
| command += target; | |
| } else if (generator == "Ninja") { | |
| command += " -v "; | |
| command += target; | |
| } else { | |
| std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); | |
| command += " -f \""; | |
| command += makefileName; | |
| command += "\" "; | |
| command += " VERBOSE=1 "; | |
| command += target; | |
| } | |
| return command; | |
| } |