| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmGlobalGhsMultiGenerator.h" |
| |
| #include "cmDocumentationEntry.h" |
| #include "cmGeneratedFileStream.h" |
| #include "cmGeneratorTarget.h" |
| #include "cmGhsMultiGpj.h" |
| #include "cmLocalGenerator.h" |
| #include "cmLocalGhsMultiGenerator.h" |
| #include "cmMakefile.h" |
| #include "cmState.h" |
| #include "cmStateTypes.h" |
| #include "cmSystemTools.h" |
| #include "cmVersion.h" |
| #include "cmake.h" |
| |
| #include <algorithm> |
| #include <map> |
| #include <ostream> |
| #include <string.h> |
| #include <utility> |
| |
| const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj"; |
| #ifdef __linux__ |
| const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild"; |
| const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "/usr/ghs"; |
| #elif defined(_WIN32) |
| const char* cmGlobalGhsMultiGenerator::DEFAULT_BUILD_PROGRAM = "gbuild.exe"; |
| const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs"; |
| #endif |
| |
| cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm) |
| : cmGlobalGenerator(cm) |
| { |
| cm->GetState()->SetGhsMultiIDE(true); |
| } |
| |
| cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() = default; |
| |
| cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator( |
| cmMakefile* mf) |
| { |
| return new cmLocalGhsMultiGenerator(this, mf); |
| } |
| |
| void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) |
| { |
| entry.Name = GetActualName(); |
| entry.Brief = |
| "Generates Green Hills MULTI files (experimental, work-in-progress)."; |
| } |
| |
| void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( |
| cmGeneratorTarget* gt) const |
| { |
| // Compute full path to object file directory for this target. |
| std::string dir; |
| dir += gt->LocalGenerator->GetCurrentBinaryDirectory(); |
| dir += "/"; |
| dir += gt->LocalGenerator->GetTargetDirectory(gt); |
| dir += "/"; |
| gt->ObjectDirectory = dir; |
| } |
| |
| bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, |
| cmMakefile* mf) |
| { |
| std::string tsp; /* toolset path */ |
| |
| this->GetToolset(mf, tsp, ts); |
| |
| /* no toolset was found */ |
| if (tsp.empty()) { |
| return false; |
| } |
| if (ts.empty()) { |
| std::string message; |
| message = |
| "Green Hills MULTI: -T <toolset> not specified; defaulting to \""; |
| message += tsp; |
| message += "\""; |
| cmSystemTools::Message(message); |
| |
| /* store the full toolset for later use |
| * -- already done if -T<toolset> was specified |
| */ |
| mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp.c_str(), |
| "Location of generator toolset.", |
| cmStateEnums::INTERNAL); |
| } |
| |
| /* set the build tool to use */ |
| std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") + |
| DEFAULT_BUILD_PROGRAM); |
| const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM"); |
| |
| /* check if the toolset changed from last generate */ |
| if (prevTool != nullptr && (gbuild != prevTool)) { |
| std::string message = "toolset build tool: "; |
| message += gbuild; |
| message += "\nDoes not match the previously used build tool: "; |
| message += prevTool; |
| message += "\nEither remove the CMakeCache.txt file and CMakeFiles " |
| "directory or choose a different binary directory."; |
| cmSystemTools::Error(message); |
| return false; |
| } |
| |
| /* store the toolset that is being used for this build */ |
| mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(), |
| "build program to use", cmStateEnums::INTERNAL, true); |
| |
| mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp); |
| |
| return true; |
| } |
| |
| bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, |
| cmMakefile* mf) |
| { |
| std::string arch; |
| if (p.empty()) { |
| cmSystemTools::Message( |
| "Green Hills MULTI: -A <arch> not specified; defaulting to \"arm\""); |
| arch = "arm"; |
| |
| /* store the platform name for later use |
| * -- already done if -A<arch> was specified |
| */ |
| mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(), |
| "Name of generator platform.", |
| cmStateEnums::INTERNAL); |
| } else { |
| arch = p; |
| } |
| |
| /* check if OS location has been updated by platform scripts */ |
| std::string platform = mf->GetSafeDefinition("GHS_TARGET_PLATFORM"); |
| std::string osdir = mf->GetSafeDefinition("GHS_OS_DIR"); |
| if (cmSystemTools::IsOff(osdir.c_str()) && |
| platform.find("integrity") != std::string::npos) { |
| if (!this->CMakeInstance->GetIsInTryCompile()) { |
| /* required OS location is not found */ |
| std::string m = |
| "Green Hills MULTI: GHS_OS_DIR not specified; No OS found in \""; |
| m += mf->GetSafeDefinition("GHS_OS_ROOT"); |
| m += "\""; |
| cmSystemTools::Message(m); |
| } |
| osdir = "GHS_OS_DIR-NOT-SPECIFIED"; |
| } else if (!this->CMakeInstance->GetIsInTryCompile() && |
| cmSystemTools::IsOff(this->OsDir) && |
| !cmSystemTools::IsOff(osdir)) { |
| /* OS location was updated by auto-selection */ |
| std::string m = "Green Hills MULTI: GHS_OS_DIR not specified; found \""; |
| m += osdir; |
| m += "\""; |
| cmSystemTools::Message(m); |
| } |
| this->OsDir = osdir; |
| |
| // Determine GHS_BSP_NAME |
| std::string bspName = mf->GetSafeDefinition("GHS_BSP_NAME"); |
| |
| if (cmSystemTools::IsOff(bspName.c_str()) && |
| platform.find("integrity") != std::string::npos) { |
| bspName = "sim" + arch; |
| /* write back the calculate name for next time */ |
| mf->AddCacheDefinition("GHS_BSP_NAME", bspName.c_str(), |
| "Name of GHS target platform.", |
| cmStateEnums::STRING, true); |
| std::string m = |
| "Green Hills MULTI: GHS_BSP_NAME not specified; defaulting to \""; |
| m += bspName; |
| m += "\""; |
| cmSystemTools::Message(m); |
| } |
| |
| return true; |
| } |
| |
| void cmGlobalGhsMultiGenerator::EnableLanguage( |
| std::vector<std::string> const& l, cmMakefile* mf, bool optional) |
| { |
| mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI"); |
| |
| mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files |
| |
| const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM"); |
| if (!tgtPlatform) { |
| cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not " |
| "specified; defaulting to \"integrity\""); |
| tgtPlatform = "integrity"; |
| } |
| |
| /* store the platform name for later use */ |
| mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform, |
| "Name of GHS target platform.", cmStateEnums::STRING); |
| |
| /* store original OS location */ |
| this->OsDir = mf->GetSafeDefinition("GHS_OS_DIR"); |
| |
| this->cmGlobalGenerator::EnableLanguage(l, mf, optional); |
| } |
| |
| bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/) |
| { |
| // The GHS generator only knows how to lookup its build tool |
| // during generation of the project files, but this |
| // can only be done after the toolset is specified. |
| |
| return true; |
| } |
| |
| void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd, |
| const std::string& ts) |
| { |
| const char* ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT"); |
| |
| if (!ghsRoot || ghsRoot[0] == '\0') { |
| ghsRoot = DEFAULT_TOOLSET_ROOT; |
| } |
| tsd = ghsRoot; |
| |
| if (ts.empty()) { |
| std::vector<std::string> output; |
| |
| // Use latest? version |
| if (tsd.back() != '/') { |
| tsd += "/"; |
| } |
| cmSystemTools::Glob(tsd, "comp_[^;]+", output); |
| |
| if (output.empty()) { |
| std::string msg = |
| "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + tsd + "\"."; |
| cmSystemTools::Error(msg); |
| tsd = ""; |
| } else { |
| tsd += output.back(); |
| } |
| } else { |
| std::string tryPath; |
| tryPath = cmSystemTools::CollapseFullPath(ts, tsd); |
| if (!cmSystemTools::FileExists(tryPath)) { |
| std::string msg = "GHS toolset \"" + tryPath + "\" not found."; |
| cmSystemTools::Error(msg); |
| tsd = ""; |
| } else { |
| tsd = tryPath; |
| } |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout) |
| { |
| fout << "#!gbuild" << std::endl; |
| fout << "#" << std::endl |
| << "# CMAKE generated file: DO NOT EDIT!" << std::endl |
| << "# Generated by \"" << GetActualName() << "\"" |
| << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "." |
| << cmVersion::GetMinorVersion() << std::endl |
| << "#" << std::endl |
| << std::endl; |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout) |
| { |
| fout << "Commands {\n" |
| " Custom_Rule_Command {\n" |
| " name = \"Custom Rule Command\"\n" |
| " exec = \""; |
| #ifdef _WIN32 |
| fout << "cmd.exe"; |
| #else |
| fout << "/bin/sh"; |
| #endif |
| fout << "\"\n" |
| " options = {\"SpecialOptions\"}\n" |
| " }\n" |
| "}\n"; |
| |
| fout << "\n\n"; |
| fout << "FileTypes {\n" |
| " CmakeRule {\n" |
| " name = \"Custom Rule\"\n" |
| " action = \"&Run\"\n" |
| " extensions = {\""; |
| #ifdef _WIN32 |
| fout << "bat"; |
| #else |
| fout << "sh"; |
| #endif |
| fout << "\"}\n" |
| " grepable = false\n" |
| " command = \"Custom Rule Command\"\n" |
| " commandLine = \"$COMMAND "; |
| #ifdef _WIN32 |
| fout << "/c"; |
| #endif |
| fout << " $INPUTFILE\"\n" |
| " progress = \"Processing Custom Rule\"\n" |
| " promoteToFirstPass = true\n" |
| " outputType = \"None\"\n" |
| " color = \"#800080\"\n" |
| " }\n" |
| "}\n"; |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteCustomTargetBOD(std::ostream& fout) |
| { |
| fout << "FileTypes {\n" |
| " CmakeTarget {\n" |
| " name = \"Custom Target\"\n" |
| " action = \"&Execute\"\n" |
| " grepable = false\n" |
| " outputType = \"None\"\n" |
| " color = \"#800080\"\n" |
| " }\n" |
| "}\n"; |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteTopLevelProject(std::ostream& fout, |
| cmLocalGenerator* root) |
| { |
| this->WriteFileHeader(fout); |
| this->WriteMacros(fout, root); |
| this->WriteHighLevelDirectives(root, fout); |
| GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout); |
| |
| fout << "# Top Level Project File" << std::endl; |
| |
| // Specify BSP option if supplied by user |
| const char* bspName = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME"); |
| if (!cmSystemTools::IsOff(bspName)) { |
| fout << " -bsp " << bspName << std::endl; |
| } |
| |
| // Specify OS DIR if supplied by user |
| // -- not all platforms require this entry in the project file |
| if (!cmSystemTools::IsOff(this->OsDir.c_str())) { |
| const char* osDirOption = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION"); |
| std::replace(this->OsDir.begin(), this->OsDir.end(), '\\', '/'); |
| fout << " "; |
| if (cmSystemTools::IsOff(osDirOption)) { |
| fout << ""; |
| } else { |
| fout << osDirOption; |
| } |
| fout << "\"" << this->OsDir << "\"" << std::endl; |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteSubProjects(std::ostream& fout, |
| std::string& all_target) |
| { |
| fout << "CMakeFiles/" << all_target << " [Project]" << std::endl; |
| // All known targets |
| for (cmGeneratorTarget const* target : this->ProjectTargets) { |
| if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY || |
| target->GetType() == cmStateEnums::MODULE_LIBRARY || |
| target->GetType() == cmStateEnums::SHARED_LIBRARY || |
| (target->GetType() == cmStateEnums::GLOBAL_TARGET && |
| target->GetName() != GetInstallTargetName())) { |
| continue; |
| } |
| fout << "CMakeFiles/" << target->GetName() + ".tgt" + FILE_EXTENSION |
| << " [Project]" << std::endl; |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteProjectLine( |
| std::ostream& fout, cmGeneratorTarget const* target, cmLocalGenerator* root, |
| std::string& rootBinaryDir) |
| { |
| const char* projName = target->GetProperty("GENERATOR_FILE_NAME"); |
| const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT"); |
| if (projName && projType) { |
| cmLocalGenerator* lg = target->GetLocalGenerator(); |
| std::string dir = lg->GetCurrentBinaryDirectory(); |
| dir = root->MaybeConvertToRelativePath(rootBinaryDir, dir); |
| if (dir == ".") { |
| dir.clear(); |
| } else { |
| if (dir.back() != '/') { |
| dir += "/"; |
| } |
| } |
| |
| std::string projFile = dir + projName + FILE_EXTENSION; |
| fout << projFile; |
| fout << " " << projType << std::endl; |
| } else { |
| /* Should never happen */ |
| std::string message = |
| "The project file for target [" + target->GetName() + "] is missing.\n"; |
| cmSystemTools::Error(message); |
| fout << "{comment} " << target->GetName() << " [missing project file]\n"; |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteTargets(cmLocalGenerator* root) |
| { |
| std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); |
| rootBinaryDir += "/CMakeFiles"; |
| |
| // All known targets |
| for (cmGeneratorTarget const* target : this->ProjectTargets) { |
| if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY || |
| target->GetType() == cmStateEnums::MODULE_LIBRARY || |
| target->GetType() == cmStateEnums::SHARED_LIBRARY || |
| (target->GetType() == cmStateEnums::GLOBAL_TARGET && |
| target->GetName() != GetInstallTargetName())) { |
| continue; |
| } |
| |
| // create target build file |
| std::string name = target->GetName() + ".tgt" + FILE_EXTENSION; |
| std::string fname = rootBinaryDir + "/" + name; |
| cmGeneratedFileStream fbld(fname); |
| fbld.SetCopyIfDifferent(true); |
| this->WriteFileHeader(fbld); |
| GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld); |
| std::vector<cmGeneratorTarget const*> build; |
| if (ComputeTargetBuildOrder(target, build)) { |
| std::string message = "The inter-target dependency graph for target [" + |
| target->GetName() + "] had a cycle.\n"; |
| cmSystemTools::Error(message); |
| } else { |
| for (auto& tgt : build) { |
| WriteProjectLine(fbld, tgt, root, rootBinaryDir); |
| } |
| } |
| fbld.Close(); |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteAllTarget( |
| cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators, |
| std::string& all_target) |
| { |
| this->ProjectTargets.clear(); |
| |
| // create target build file |
| all_target = root->GetProjectName() + "." + this->GetAllTargetName() + |
| ".tgt" + FILE_EXTENSION; |
| std::string fname = |
| root->GetCurrentBinaryDirectory() + "/CMakeFiles/" + all_target; |
| cmGeneratedFileStream fbld(fname); |
| fbld.SetCopyIfDifferent(true); |
| this->WriteFileHeader(fbld); |
| GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fbld); |
| |
| // Collect all targets under this root generator and the transitive |
| // closure of their dependencies. |
| TargetDependSet projectTargets; |
| TargetDependSet originalTargets; |
| this->GetTargetSets(projectTargets, originalTargets, root, generators); |
| OrderedTargetDependSet sortedProjectTargets(projectTargets, ""); |
| std::vector<cmGeneratorTarget const*> defaultTargets; |
| for (cmGeneratorTarget const* t : sortedProjectTargets) { |
| /* save list of all targets in sorted order */ |
| this->ProjectTargets.push_back(t); |
| } |
| for (cmGeneratorTarget const* t : sortedProjectTargets) { |
| if (t->GetType() == cmStateEnums::INTERFACE_LIBRARY) { |
| continue; |
| } |
| if (!cmSystemTools::IsOn(t->GetProperty("EXCLUDE_FROM_ALL"))) { |
| defaultTargets.push_back(t); |
| } |
| } |
| std::vector<cmGeneratorTarget const*> build; |
| if (ComputeTargetBuildOrder(defaultTargets, build)) { |
| std::string message = "The inter-target dependency graph for project [" + |
| root->GetProjectName() + "] had a cycle.\n"; |
| cmSystemTools::Error(message); |
| } else { |
| // determine the targets for ALL target |
| std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); |
| rootBinaryDir += "/CMakeFiles"; |
| for (cmGeneratorTarget const* target : build) { |
| if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY || |
| target->GetType() == cmStateEnums::MODULE_LIBRARY || |
| target->GetType() == cmStateEnums::SHARED_LIBRARY) { |
| continue; |
| } |
| this->WriteProjectLine(fbld, target, root, rootBinaryDir); |
| } |
| } |
| fbld.Close(); |
| } |
| |
| void cmGlobalGhsMultiGenerator::Generate() |
| { |
| std::string fname; |
| |
| // first do the superclass method |
| this->cmGlobalGenerator::Generate(); |
| |
| // output top-level projects |
| for (auto& it : this->ProjectMap) { |
| this->OutputTopLevelProject(it.second[0], it.second); |
| } |
| |
| // create custom rule BOD file |
| fname = this->GetCMakeInstance()->GetHomeOutputDirectory() + |
| "/CMakeFiles/custom_rule.bod"; |
| cmGeneratedFileStream frule(fname); |
| frule.SetCopyIfDifferent(true); |
| this->WriteFileHeader(frule); |
| this->WriteCustomRuleBOD(frule); |
| frule.Close(); |
| |
| // create custom target BOD file |
| fname = this->GetCMakeInstance()->GetHomeOutputDirectory() + |
| "/CMakeFiles/custom_target.bod"; |
| cmGeneratedFileStream ftarget(fname); |
| ftarget.SetCopyIfDifferent(true); |
| this->WriteFileHeader(ftarget); |
| this->WriteCustomTargetBOD(ftarget); |
| ftarget.Close(); |
| } |
| |
| void cmGlobalGhsMultiGenerator::OutputTopLevelProject( |
| cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators) |
| { |
| std::string fname; |
| std::string all_target; |
| |
| if (generators.empty()) { |
| return; |
| } |
| |
| /* Name top-level projects as filename.top.gpj to avoid name clashes |
| * with target projects. This avoid the issue where the project has |
| * the same name as the executable target. |
| */ |
| fname = root->GetCurrentBinaryDirectory(); |
| fname += "/"; |
| fname += root->GetProjectName(); |
| fname += ".top"; |
| fname += FILE_EXTENSION; |
| |
| cmGeneratedFileStream top(fname); |
| top.SetCopyIfDifferent(true); |
| this->WriteTopLevelProject(top, root); |
| |
| this->WriteAllTarget(root, generators, all_target); |
| this->WriteTargets(root); |
| |
| this->WriteSubProjects(top, all_target); |
| top.Close(); |
| } |
| |
| std::vector<cmGlobalGenerator::GeneratedMakeCommand> |
| cmGlobalGhsMultiGenerator::GenerateBuildCommand( |
| const std::string& makeProgram, const std::string& projectName, |
| const std::string& projectDir, std::vector<std::string> const& targetNames, |
| const std::string& /*config*/, bool /*fast*/, int jobs, bool /*verbose*/, |
| std::vector<std::string> const& makeOptions) |
| { |
| GeneratedMakeCommand makeCommand = {}; |
| std::string gbuild; |
| if (const char* gbuildCached = |
| this->CMakeInstance->GetCacheDefinition("CMAKE_MAKE_PROGRAM")) { |
| gbuild = gbuildCached; |
| } |
| makeCommand.Add(this->SelectMakeProgram(makeProgram, gbuild)); |
| |
| if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { |
| makeCommand.Add("-parallel"); |
| if (jobs != cmake::DEFAULT_BUILD_PARALLEL_LEVEL) { |
| makeCommand.Add(std::to_string(jobs)); |
| } |
| } |
| |
| makeCommand.Add(makeOptions.begin(), makeOptions.end()); |
| |
| /* determine which top-project file to use */ |
| std::string proj = projectName + ".top" + FILE_EXTENSION; |
| std::vector<std::string> files; |
| cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files); |
| if (!files.empty()) { |
| /* if multiple top-projects are found in build directory |
| * then prefer projectName top-project. |
| */ |
| auto p = std::find(files.begin(), files.end(), proj); |
| if (p == files.end()) { |
| proj = files.at(0); |
| } |
| } |
| |
| makeCommand.Add("-top", proj); |
| if (!targetNames.empty()) { |
| if (std::find(targetNames.begin(), targetNames.end(), "clean") != |
| targetNames.end()) { |
| makeCommand.Add("-clean"); |
| } else { |
| for (const auto& tname : targetNames) { |
| if (!tname.empty()) { |
| makeCommand.Add(tname + ".tgt.gpj"); |
| } |
| } |
| } |
| } else { |
| /* transform name to default build */; |
| std::string all = proj; |
| all.replace(all.end() - 7, all.end(), |
| std::string(this->GetAllTargetName()) + ".tgt.gpj"); |
| makeCommand.Add(all); |
| } |
| return { makeCommand }; |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout, |
| cmLocalGenerator* root) |
| { |
| fout << "macro PROJ_NAME=" << root->GetProjectName() << std::endl; |
| char const* ghsGpjMacros = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS"); |
| if (nullptr != ghsGpjMacros) { |
| std::vector<std::string> expandedList; |
| cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList); |
| for (std::string const& arg : expandedList) { |
| fout << "macro " << arg << std::endl; |
| } |
| } |
| } |
| |
| void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives( |
| cmLocalGenerator* root, std::ostream& fout) |
| { |
| /* set primary target */ |
| std::string tgt; |
| const char* t = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_PRIMARY_TARGET"); |
| if (t && *t != '\0') { |
| tgt = t; |
| this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET"); |
| } else { |
| const char* a = |
| this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM"); |
| const char* p = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM"); |
| tgt = (a ? a : ""); |
| tgt += "_"; |
| tgt += (p ? p : ""); |
| tgt += ".tgt"; |
| } |
| |
| fout << "primaryTarget=" << tgt << std::endl; |
| fout << "customization=" << root->GetBinaryDirectory() |
| << "/CMakeFiles/custom_rule.bod" << std::endl; |
| fout << "customization=" << root->GetBinaryDirectory() |
| << "/CMakeFiles/custom_target.bod" << std::endl; |
| |
| char const* const customization = |
| this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION"); |
| if (nullptr != customization && strlen(customization) > 0) { |
| fout << "customization=" << this->TrimQuotes(customization) << std::endl; |
| this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION"); |
| } |
| } |
| |
| std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str) |
| { |
| std::string result; |
| result.reserve(str.size()); |
| for (const char* ch = str.c_str(); *ch != '\0'; ++ch) { |
| if (*ch != '"') { |
| result += *ch; |
| } |
| } |
| return result; |
| } |
| |
| bool cmGlobalGhsMultiGenerator::TargetCompare::operator()( |
| cmGeneratorTarget const* l, cmGeneratorTarget const* r) const |
| { |
| // Make sure a given named target is ordered first, |
| // e.g. to set ALL_BUILD as the default active project. |
| // When the empty string is named this is a no-op. |
| if (r->GetName() == this->First) { |
| return false; |
| } |
| if (l->GetName() == this->First) { |
| return true; |
| } |
| return l->GetName() < r->GetName(); |
| } |
| |
| cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet( |
| TargetDependSet const& targets, std::string const& first) |
| : derived(TargetCompare(first)) |
| { |
| this->insert(targets.begin(), targets.end()); |
| } |
| |
| bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( |
| cmGeneratorTarget const* tgt, std::vector<cmGeneratorTarget const*>& build) |
| { |
| std::vector<cmGeneratorTarget const*> t{ tgt }; |
| return ComputeTargetBuildOrder(t, build); |
| } |
| |
| bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( |
| std::vector<cmGeneratorTarget const*>& tgt, |
| std::vector<cmGeneratorTarget const*>& build) |
| { |
| std::set<cmGeneratorTarget const*> temp; |
| std::set<cmGeneratorTarget const*> perm; |
| |
| for (auto ti : tgt) { |
| bool r = VisitTarget(temp, perm, build, ti); |
| if (r) { |
| return r; |
| } |
| } |
| return false; |
| } |
| |
| bool cmGlobalGhsMultiGenerator::VisitTarget( |
| std::set<cmGeneratorTarget const*>& temp, |
| std::set<cmGeneratorTarget const*>& perm, |
| std::vector<cmGeneratorTarget const*>& order, cmGeneratorTarget const* ti) |
| { |
| /* check if permanent mark is set*/ |
| if (perm.find(ti) == perm.end()) { |
| /* set temporary mark; check if revisit*/ |
| if (temp.insert(ti).second) { |
| /* sort targets lexicographically to ensure that nodes are always visited |
| * in the same order */ |
| OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti), |
| ""); |
| for (auto& di : sortedTargets) { |
| if (this->VisitTarget(temp, perm, order, di)) { |
| return true; |
| } |
| } |
| /* mark as complete; insert into beginning of list*/ |
| perm.insert(ti); |
| order.push_back(ti); |
| return false; |
| } |
| /* revisiting item - not a DAG */ |
| return true; |
| } |
| /* already complete */ |
| return false; |
| } |