GHS: Update the top-level project generation

-- Sort targets by name
-- Generate a top-level project for each project command named as project.top.gpj
   Use the target set for the current project instead of assuming all targets
-- Add support for building projects not in binary root
-- Directly create files and pass ostream
-- Do no generate project files for UTILITY targets; this was never supported
-- Do no generate project files for OBJECT, SHARED, or MODULE libraries; this was never supported
-- Update GHS tags to support project types
   NOTE: The default tag is changed to "" because "[ ]" is an invalid token in project file
This commit is contained in:
Fred Baksik 2019-01-05 11:01:21 -05:00
parent e7825386e2
commit ead7117afd
6 changed files with 240 additions and 105 deletions

View File

@ -4,31 +4,35 @@
#include "cmGeneratedFileStream.h"
void GhsMultiGpj::WriteGpjTag(Types const gpjType,
cmGeneratedFileStream* const filestream)
static const char* GHS_TAG[] = { "[INTEGRITY Application]",
"[Library]",
"[Project]",
"[Program]",
"[Reference]",
"[Subproject]" };
const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
{
char const* tag;
switch (gpjType) {
case INTERGRITY_APPLICATION:
tag = "INTEGRITY Application";
break;
case LIBRARY:
tag = "Library";
break;
case PROJECT:
tag = "Project";
break;
case PROGRAM:
tag = "Program";
break;
case REFERENCE:
tag = "Reference";
break;
case SUBPROJECT:
tag = "Subproject";
tag = GHS_TAG[gpjType];
break;
default:
tag = "";
}
*filestream << "[" << tag << "]" << std::endl;
return tag;
}
void GhsMultiGpj::WriteGpjTag(Types const gpjType,
cmGeneratedFileStream* const filestream)
{
char const* tag;
tag = GhsMultiGpj::GetGpjTag(gpjType);
*filestream << tag << std::endl;
}

View File

@ -22,6 +22,8 @@ public:
static void WriteGpjTag(Types const gpjType,
cmGeneratedFileStream* filestream);
static const char* GetGpjTag(Types const gpjType);
};
#endif // ! cmGhsMultiGpjType_h

View File

@ -101,10 +101,59 @@ std::string cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(
void cmGhsMultiTargetGenerator::Generate()
{
// Determine type of target for this project
switch (this->GeneratorTarget->GetType()) {
case cmStateEnums::EXECUTABLE: {
if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(
this->GeneratorTarget)) {
this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
} else {
this->TagType = GhsMultiGpj::PROGRAM;
}
break;
}
case cmStateEnums::STATIC_LIBRARY: {
this->TagType = GhsMultiGpj::LIBRARY;
break;
}
case cmStateEnums::SHARED_LIBRARY: {
std::string msg = "add_library(<name> SHARED ...) not supported: ";
msg += this->Name;
cmSystemTools::Message(msg.c_str());
return;
}
case cmStateEnums::OBJECT_LIBRARY: {
std::string msg = "add_library(<name> OBJECT ...) not supported: ";
msg += this->Name;
cmSystemTools::Message(msg.c_str());
return;
}
case cmStateEnums::MODULE_LIBRARY: {
std::string msg = "add_library(<name> MODULE ...) not supported: ";
msg += this->Name;
cmSystemTools::Message(msg.c_str());
return;
}
case cmStateEnums::UTILITY: {
std::string msg = "add_custom_target(<name> ...) not supported: ";
msg += this->Name;
cmSystemTools::Message(msg.c_str());
return;
}
default:
return;
}
// Tell the global generator the name of the project file
this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
this->Name.c_str());
this->GeneratorTarget->Target->SetProperty(
"GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
this->GenerateTarget();
}
void cmGhsMultiTargetGenerator::GenerateTarget()
{
// Skip if empty or not included in build
if (!this->GetSources().empty() && this->IncludeThisTarget()) {
@ -129,7 +178,7 @@ void cmGhsMultiTargetGenerator::Generate()
if (this->DynamicDownload) {
fout << "#component integrity_dynamic_download" << std::endl;
}
GhsMultiGpj::WriteGpjTag(this->GetGpjTag(), &fout);
GhsMultiGpj::WriteGpjTag(this->TagType, &fout);
cmGlobalGhsMultiGenerator::WriteDisclaimer(&fout);
bool const notKernel = this->IsNotKernel(config, language);
@ -168,25 +217,6 @@ std::vector<cmSourceFile*> cmGhsMultiTargetGenerator::GetSources() const
return output;
}
GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const
{
return cmGhsMultiTargetGenerator::GetGpjTag(this->GeneratorTarget);
}
GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag(
const cmGeneratorTarget* target)
{
GhsMultiGpj::Types output;
if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(target)) {
output = GhsMultiGpj::INTERGRITY_APPLICATION;
} else if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
output = GhsMultiGpj::LIBRARY;
} else {
output = GhsMultiGpj::PROGRAM;
}
return output;
}
cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
const
{

View File

@ -26,8 +26,6 @@ public:
bool IncludeThisTarget();
std::vector<cmSourceFile*> GetSources() const;
GhsMultiGpj::Types GetGpjTag() const;
static GhsMultiGpj::Types GetGpjTag(const cmGeneratorTarget* target);
const char* GetAbsBuildFilePath() const
{
return this->AbsBuildFilePath.c_str();
@ -58,6 +56,8 @@ private:
{
return this->FolderBuildStreams[""];
};
void GenerateTarget();
bool IsTargetGroup() const { return this->TargetGroup; }
void WriteTypeSpecifics(std::ostream& fout, const std::string& config,
@ -114,6 +114,8 @@ private:
static std::string const DDOption;
std::map<std::string, std::string> FlagsByLanguage;
std::map<std::string, std::string> DefinesByLanguage;
GhsMultiGpj::Types TagType;
std::string const Name;
};

View File

@ -209,25 +209,24 @@ void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
{
*filestream << "#!gbuild" << std::endl;
}
void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
/* temporary until all file handling is cleaned up */
void cmGlobalGhsMultiGenerator::OpenBuildFileStream(std::ostream& fout)
{
// Compute GHS MULTI's build file path.
std::string buildFilePath =
this->GetCMakeInstance()->GetHomeOutputDirectory();
buildFilePath += "/";
buildFilePath +=
this->GetCMakeInstance()->GetCurrentSnapshot().GetProjectName();
buildFilePath += FILE_EXTENSION;
fout << "#!gbuild" << std::endl;
}
this->Open(std::string(""), buildFilePath, &this->TargetFolderBuildStreams);
OpenBuildFileStream(GetBuildFileStream());
void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators)
{
OpenBuildFileStream(fout);
this->WriteMacros();
this->WriteHighLevelDirectives();
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
this->WriteDisclaimer(this->GetBuildFileStream());
*this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
this->WriteMacros(fout);
this->WriteHighLevelDirectives(fout);
// GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, &fout);
fout << "[Project]" << std::endl;
this->WriteDisclaimer(&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
@ -256,7 +255,7 @@ void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
}
if (!cmSystemTools::IsOff(bspName.c_str())) {
*this->GetBuildFileStream() << " -bsp " << bspName << std::endl;
fout << " -bsp " << bspName << std::endl;
}
// Specify OS DIR if supplied by user
@ -276,8 +275,46 @@ void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
if (!cmSystemTools::IsOff(osDir.c_str()) ||
platform.find("integrity") != std::string::npos) {
std::replace(osDir.begin(), osDir.end(), '\\', '/');
*this->GetBuildFileStream()
<< " " << osDirOption << "\"" << osDir << "\"" << std::endl;
fout << " " << osDirOption << "\"" << osDir << "\"" << std::endl;
}
WriteSubProjects(fout, root, generators);
}
void cmGlobalGhsMultiGenerator::WriteSubProjects(
std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators)
{
// 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) {
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->ConvertToRelativePath(rootBinaryDir, dir.c_str());
if (dir == ".") {
dir.clear();
} else {
if (dir.back() != '/') {
dir += "/";
}
}
fout << dir << projName << FILE_EXTENSION;
fout << " " << projType << std::endl;
}
}
}
@ -294,27 +331,43 @@ void cmGlobalGhsMultiGenerator::CloseBuildFileStream(
void cmGlobalGhsMultiGenerator::Generate()
{
// first do the superclass method
this->cmGlobalGenerator::Generate();
if (!this->LocalGenerators.empty()) {
this->OpenBuildFileStream();
// output top-level projects
for (auto& it : this->ProjectMap) {
this->OutputTopLevelProject(it.second[0], it.second);
}
}
// Build all the folder build files
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
cmLocalGhsMultiGenerator* lg =
static_cast<cmLocalGhsMultiGenerator*>(this->LocalGenerators[i]);
const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
this->UpdateBuildFiles(tgts);
}
void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
{
if (generators.empty()) {
return;
}
cmDeleteAll(TargetFolderBuildStreams);
this->TargetFolderBuildStreams.clear();
/* 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.
*/
std::string fname = root->GetCurrentBinaryDirectory();
fname += "/";
fname += root->GetProjectName();
fname += ".top";
fname += FILE_EXTENSION;
cmGeneratedFileStream fout(fname.c_str());
fout.SetCopyIfDifferent(true);
this->WriteTopLevelProject(fout, root, generators);
fout.Close();
}
void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
std::vector<std::string>& makeCommand, const std::string& makeProgram,
const std::string& projectName, const std::string& /*projectDir*/,
const std::string& projectName, const std::string& projectDir,
const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
{
@ -332,8 +385,20 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
makeCommand.insert(makeCommand.end(), 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()) {
auto p = std::find(files.begin(), files.end(), proj);
if (p == files.end()) {
proj = files.at(0);
}
}
makeCommand.push_back("-top");
makeCommand.push_back(projectName + FILE_EXTENSION);
makeCommand.push_back(proj);
if (!targetName.empty()) {
if (targetName == "clean") {
makeCommand.push_back("-clean");
@ -343,7 +408,7 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
}
}
void cmGlobalGhsMultiGenerator::WriteMacros()
void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
{
char const* ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
@ -353,12 +418,12 @@ void cmGlobalGhsMultiGenerator::WriteMacros()
for (std::vector<std::string>::const_iterator expandedListI =
expandedList.begin();
expandedListI != expandedList.end(); ++expandedListI) {
*this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
fout << "macro " << *expandedListI << std::endl;
}
}
}
void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
{
/* set primary target */
std::string tgt;
@ -378,13 +443,12 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
tgt += ".tgt";
}
*this->GetBuildFileStream() << "primaryTarget=" << tgt << std::endl;
fout << "primaryTarget=" << tgt << std::endl;
char const* const customization =
this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
if (NULL != customization && strlen(customization) > 0) {
*this->GetBuildFileStream()
<< "customization=" << trimQuotes(customization) << std::endl;
fout << "customization=" << trimQuotes(customization) << std::endl;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
@ -499,33 +563,6 @@ std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath(
return output;
}
void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
const std::vector<cmGeneratorTarget*>& tgts)
{
for (std::vector<cmGeneratorTarget*>::const_iterator tgtsI = tgts.begin();
tgtsI != tgts.end(); ++tgtsI) {
const cmGeneratorTarget* tgt = *tgtsI;
if (IsTgtForBuild(tgt)) {
std::string folderName = tgt->GetEffectiveFolderName();
if (this->TargetFolderBuildStreams.end() ==
this->TargetFolderBuildStreams.find(folderName)) {
this->AddFilesUpToPath(
GetBuildFileStream(), &this->TargetFolderBuildStreams,
this->GetCMakeInstance()->GetHomeOutputDirectory().c_str(),
folderName, GhsMultiGpj::PROJECT);
}
std::vector<std::string> splitPath = cmSystemTools::SplitString(
cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt));
std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" +
splitPath.back());
*this->TargetFolderBuildStreams[folderName] << foldNameRelBuildFile
<< " ";
GhsMultiGpj::WriteGpjTag(cmGhsMultiTargetGenerator::GetGpjTag(tgt),
this->TargetFolderBuildStreams[folderName]);
}
}
}
bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmGeneratorTarget* tgt)
{
const std::string config =
@ -552,3 +589,25 @@ std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
}
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());
}

View File

@ -71,6 +71,7 @@ public:
static void OpenBuildFileStream(std::string const& filepath,
cmGeneratedFileStream** filestream);
static void OpenBuildFileStream(cmGeneratedFileStream* filestream);
void OpenBuildFileStream(std::ostream& fout);
static void CloseBuildFileStream(cmGeneratedFileStream** filestream);
/// Write the common disclaimer text at the top of each build file.
static void WriteDisclaimer(std::ostream* os);
@ -86,6 +87,24 @@ public:
static std::string trimQuotes(std::string const& str);
// Target dependency sorting
class TargetSet : public std::set<cmGeneratorTarget const*>
{
};
class TargetCompare
{
std::string First;
public:
TargetCompare(std::string const& first)
: First(first)
{
}
bool operator()(cmGeneratorTarget const* l,
cmGeneratorTarget const* r) const;
};
class OrderedTargetDependSet;
protected:
void Generate() override;
void GenerateBuildCommand(std::vector<std::string>& makeCommand,
@ -100,10 +119,16 @@ protected:
private:
void GetToolset(cmMakefile* mf, std::string& tsd, std::string& ts);
void OpenBuildFileStream();
void WriteMacros();
void WriteHighLevelDirectives();
/* top-level project */
void OutputTopLevelProject(cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
void WriteMacros(std::ostream& fout);
void WriteHighLevelDirectives(std::ostream& fout);
void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
std::vector<cmLocalGenerator*>& generators);
static void AddFilesUpToPathNewBuildFile(
cmGeneratedFileStream* mainBuildFile,
@ -116,7 +141,7 @@ private:
std::vector<std::string>::const_iterator splitPathI,
std::vector<std::string>::const_iterator end, GhsMultiGpj::Types projType);
static std::string GetFileNameFromPath(std::string const& path);
void UpdateBuildFiles(const std::vector<cmGeneratorTarget*>& tgts);
bool IsTgtForBuild(const cmGeneratorTarget* tgt);
std::vector<cmGeneratedFileStream*> TargetSubProjects;
@ -128,4 +153,17 @@ private:
static const char* DEFAULT_TOOLSET_ROOT;
};
class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
: public std::multiset<cmTargetDepend,
cmGlobalGhsMultiGenerator::TargetCompare>
{
typedef std::multiset<cmTargetDepend,
cmGlobalGhsMultiGenerator::TargetCompare>
derived;
public:
typedef cmGlobalGenerator::TargetDependSet TargetDependSet;
OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
};
#endif