diff options
Diffstat (limited to 'Source/cmGlobalGhsMultiGenerator.cxx')
-rw-r--r-- | Source/cmGlobalGhsMultiGenerator.cxx | 476 |
1 files changed, 360 insertions, 116 deletions
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index e6a1d78..b69dea0 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -119,10 +119,11 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts, 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\""); - std::string arch = "arm"; + arch = "arm"; /* store the platform name for later use * -- already done if -A<arch> was specified @@ -130,19 +131,51 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p, mf->AddCacheDefinition("CMAKE_GENERATOR_PLATFORM", arch.c_str(), "Name of generator platform.", cmStateEnums::INTERNAL); + } else { + arch = p; } - const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM"); - if (tgtPlatform == nullptr) { - cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not " - "specified; defaulting to \"integrity\""); - tgtPlatform = "integrity"; + /* 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; - /* store the platform name for later use */ - mf->AddCacheDefinition("GHS_TARGET_PLATFORM", tgtPlatform, - "Name of GHS target platform.", - cmStateEnums::INTERNAL); + // 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; } @@ -153,6 +186,21 @@ void cmGlobalGhsMultiGenerator::EnableLanguage( 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); } @@ -217,132 +265,239 @@ void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout) << std::endl; } -void cmGlobalGhsMultiGenerator::WriteTopLevelProject( - std::ostream& fout, cmLocalGenerator* root, - std::vector<cmLocalGenerator*>& generators) +void cmGlobalGhsMultiGenerator::WriteCustomRuleBOD(std::ostream& fout) { - WriteFileHeader(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"; +} - this->WriteMacros(fout); - this->WriteHighLevelDirectives(fout); +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 - // -- not all platforms require this entry in the project file - // integrity platforms require this field; use default if needed - std::string platform; - if (const char* p = - this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) { - platform = p; - } - - std::string bspName; - if (char const* bspCache = - this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) { - bspName = bspCache; - this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME"); - } else { - bspName = "IGNORE"; - } - - if (platform.find("integrity") != std::string::npos && - cmSystemTools::IsOff(bspName.c_str())) { - const char* a = - this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM"); - bspName = "sim"; - bspName += (a ? a : ""); - } - - if (!cmSystemTools::IsOff(bspName.c_str())) { + 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 - std::string osDir; - std::string osDirOption; - if (char const* osDirCache = - this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) { - osDir = osDirCache; + 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; } +} - if (char const* osDirOptionCache = - this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) { - osDirOption = osDirOptionCache; +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; } +} - if (!cmSystemTools::IsOff(osDir.c_str()) || - platform.find("integrity") != std::string::npos) { - std::replace(osDir.begin(), osDir.end(), '\\', '/'); - fout << " " << osDirOption << "\"" << osDir << "\"" << 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"; } +} - WriteSubProjects(fout, root, generators); +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::WriteSubProjects( - std::ostream& fout, cmLocalGenerator* root, - std::vector<cmLocalGenerator*>& generators) +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 orderedProjectTargets(projectTargets, ""); - - // write out all the sub-projects - std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); - for (cmGeneratorTarget const* target : orderedProjectTargets) { - if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { + 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; } - - 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 += "/"; - } - } - - if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) { - fout << "{comment} "; - } - std::string projFile = dir + projName + FILE_EXTENSION; - fout << projFile; - fout << " " << projType << std::endl; - - if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) { - // create reference project - std::string fname = dir; - fname += target->GetName(); - fname += "REF"; - fname += FILE_EXTENSION; - - cmGeneratedFileStream fref(fname); - fref.SetCopyIfDifferent(true); - - this->WriteFileHeader(fref); - GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref); - fref << " :reference=" << projFile << std::endl; - - fref.Close(); + 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(); @@ -350,11 +505,32 @@ void cmGlobalGhsMultiGenerator::Generate() 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; } @@ -363,18 +539,21 @@ void cmGlobalGhsMultiGenerator::OutputTopLevelProject( * with target projects. This avoid the issue where the project has * the same name as the executable target. */ - std::string fname = root->GetCurrentBinaryDirectory(); + fname = root->GetCurrentBinaryDirectory(); fname += "/"; fname += root->GetProjectName(); fname += ".top"; fname += FILE_EXTENSION; - cmGeneratedFileStream fout(fname); - fout.SetCopyIfDifferent(true); + cmGeneratedFileStream top(fname); + top.SetCopyIfDifferent(true); + this->WriteTopLevelProject(top, root); - this->WriteTopLevelProject(fout, root, generators); + this->WriteAllTarget(root, generators, all_target); + this->WriteTargets(root); - fout.Close(); + this->WriteSubProjects(top, all_target); + top.Close(); } std::vector<cmGlobalGenerator::GeneratedMakeCommand> @@ -406,6 +585,9 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand( 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); @@ -420,20 +602,24 @@ cmGlobalGhsMultiGenerator::GenerateBuildCommand( } else { for (const auto& tname : targetNames) { if (!tname.empty()) { - if (tname.compare(tname.size() - 4, 4, ".gpj") == 0) { - makeCommand.Add(tname); - } else { - makeCommand.Add(tname + ".gpj"); - } + 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) +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) { @@ -445,13 +631,14 @@ void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout) } } -void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout) +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) { + if (t && *t != '\0') { tgt = t; this->GetCMakeInstance()->MarkCliAsUsed("GHS_PRIMARY_TARGET"); } else { @@ -466,16 +653,20 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout) } 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=" << trimQuotes(customization) << std::endl; + fout << "customization=" << this->TrimQuotes(customization) << std::endl; this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION"); } } -std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str) +std::string cmGlobalGhsMultiGenerator::TrimQuotes(std::string const& str) { std::string result; result.reserve(str.size()); @@ -508,3 +699,56 @@ cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet( { 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; +} |