CMake/Source/cmGlobalGhsMultiGenerator.cxx
Stephen Kelly 34c9ee2ed7 cmLocalGenerator: Require a global generator in the constructor.
Port generator factory methods to pass it.
2015-05-14 20:36:27 +02:00

549 lines
18 KiB
C++

/*============================================================================
CMake - Cross Platform Makefile Generator
Copyright 2015 Geoffrey Viola <geoffrey.viola@asirobots.com>
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the License for more information.
============================================================================*/
#include "cmGlobalGhsMultiGenerator.h"
#include "cmLocalGhsMultiGenerator.h"
#include "cmMakefile.h"
#include "cmVersion.h"
#include "cmGeneratedFileStream.h"
#include "cmGhsMultiTargetGenerator.h"
#include <cmsys/SystemTools.hxx>
#include <cmAlgorithms.h>
const char *cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
const char *cmGlobalGhsMultiGenerator::DEFAULT_MAKE_PROGRAM = "gbuild";
cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator()
: OSDirRelative(false)
{
this->GhsBuildCommandInitialized = false;
}
cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
{
cmDeleteAll(TargetFolderBuildStreams);
}
cmLocalGenerator *
cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmLocalGenerator* parent)
{
cmLocalGenerator *lg = new cmLocalGhsMultiGenerator(this, parent);
this->SetCurrentLocalGenerator(lg);
return lg;
}
void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry &entry)
{
entry.Name = GetActualName();
entry.Brief =
"Generates Green Hills MULTI files (experimental, work-in-progress).";
}
void cmGlobalGhsMultiGenerator::EnableLanguage(
std::vector<std::string> const &l, cmMakefile *mf, bool optional)
{
mf->AddDefinition("CMAKE_SYSTEM_NAME", "GHS-MULTI");
mf->AddDefinition("CMAKE_SYSTEM_PROCESSOR", "ARM");
const std::string ghsCompRoot(GetCompRoot());
mf->AddDefinition("GHS_COMP_ROOT", ghsCompRoot.c_str());
std::string ghsCompRootStart =
0 == ghsCompRootStart.size() ? "" : ghsCompRoot + "/";
mf->AddDefinition("CMAKE_C_COMPILER",
std::string(ghsCompRootStart + "ccarm.exe").c_str());
mf->AddDefinition("CMAKE_C_COMPILER_ID_RUN", "TRUE");
mf->AddDefinition("CMAKE_C_COMPILER_ID", "GHS");
mf->AddDefinition("CMAKE_C_COMPILER_FORCED", "TRUE");
mf->AddDefinition("CMAKE_CXX_COMPILER",
std::string(ghsCompRootStart + "cxarm.exe").c_str());
mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE");
mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHS");
mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
if (!ghsCompRoot.empty())
{
static const char *compPreFix = "comp_";
std::string compFilename =
cmsys::SystemTools::FindLastString(ghsCompRoot.c_str(), compPreFix);
cmsys::SystemTools::ReplaceString(compFilename, compPreFix, "");
mf->AddDefinition("CMAKE_SYSTEM_VERSION", compFilename.c_str());
}
mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
}
void cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile *mf)
{
// The GHS generator knows how to lookup its build tool
// directly instead of needing a helper module to do it, so we
// do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM")))
{
mf->AddDefinition("CMAKE_MAKE_PROGRAM",
this->GetGhsBuildCommand().c_str());
}
}
std::string const &cmGlobalGhsMultiGenerator::GetGhsBuildCommand()
{
if (!this->GhsBuildCommandInitialized)
{
this->GhsBuildCommandInitialized = true;
this->GhsBuildCommand = this->FindGhsBuildCommand();
}
return this->GhsBuildCommand;
}
std::string cmGlobalGhsMultiGenerator::FindGhsBuildCommand()
{
std::vector<std::string> userPaths;
userPaths.push_back(this->GetCompRoot());
std::string makeProgram =
cmSystemTools::FindProgram(DEFAULT_MAKE_PROGRAM, userPaths);
if (makeProgram.empty())
{
makeProgram = DEFAULT_MAKE_PROGRAM;
}
return makeProgram;
}
std::string cmGlobalGhsMultiGenerator::GetCompRoot()
{
std::string output;
const std::vector<std::string>
potentialDirsHardPaths(GetCompRootHardPaths());
const std::vector<std::string> potentialDirsRegistry(GetCompRootRegistry());
std::vector<std::string> potentialDirsComplete;
potentialDirsComplete.insert(potentialDirsComplete.end(),
potentialDirsHardPaths.begin(),
potentialDirsHardPaths.end());
potentialDirsComplete.insert(potentialDirsComplete.end(),
potentialDirsRegistry.begin(),
potentialDirsRegistry.end());
// Use latest version
std::string outputDirName;
for (std::vector<std::string>::const_iterator potentialDirsCompleteIt =
potentialDirsComplete.begin();
potentialDirsCompleteIt != potentialDirsComplete.end();
++potentialDirsCompleteIt)
{
const std::string dirName(
cmsys::SystemTools::GetFilenameName(*potentialDirsCompleteIt));
if (dirName.compare(outputDirName) > 0)
{
output = *potentialDirsCompleteIt;
outputDirName = dirName;
}
}
return output;
}
std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootHardPaths()
{
std::vector<std::string> output;
cmSystemTools::Glob("C:/ghs", "comp_[^;]+", output);
for (std::vector<std::string>::iterator outputIt = output.begin();
outputIt != output.end(); ++outputIt)
{
*outputIt = "C:/ghs/" + *outputIt;
}
return output;
}
std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootRegistry()
{
std::vector<std::string> output(2);
cmsys::SystemTools::ReadRegistryValue(
"HKEY_LOCAL_"
"MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
"Windows\\CurrentVersion\\Uninstall\\"
"GreenHillsSoftwared771f1b4;InstallLocation",
output[0]);
cmsys::SystemTools::ReadRegistryValue(
"HKEY_LOCAL_"
"MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
"Windows\\CurrentVersion\\Uninstall\\"
"GreenHillsSoftware9881cef6;InstallLocation",
output[1]);
return output;
}
void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
std::string const &filepath, cmGeneratedFileStream **filestream)
{
// Get a stream where to generate things.
if (NULL == *filestream)
{
*filestream = new cmGeneratedFileStream(filepath.c_str());
if (NULL != *filestream)
{
OpenBuildFileStream(*filestream);
}
}
}
void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
cmGeneratedFileStream *filestream)
{
*filestream << "#!gbuild" << std::endl;
}
void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
{
// Compute GHS MULTI's build file path.
std::string buildFilePath =
this->GetCMakeInstance()->GetHomeOutputDirectory();
buildFilePath += "/";
buildFilePath += "default";
buildFilePath += FILE_EXTENSION;
this->Open(std::string(""), buildFilePath, &this->TargetFolderBuildStreams);
OpenBuildFileStream(GetBuildFileStream());
char const *osDir =
this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR");
if (NULL == osDir)
{
osDir = "";
cmSystemTools::Error("GHS_OS_DIR cache variable must be set");
}
else
{
this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR");
}
std::string fOSDir(this->trimQuotes(osDir));
cmSystemTools::ReplaceString(fOSDir, "\\", "/");
if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0]))
{
this->OSDirRelative = false;
}
else
{
this->OSDirRelative = true;
}
char const *bspName =
this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
if (NULL == bspName)
{
bspName = "";
cmSystemTools::Error("GHS_BSP_NAME cache variable must be set");
}
else
{
this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
}
std::string fBspName(this->trimQuotes(bspName));
cmSystemTools::ReplaceString(fBspName, "\\", "/");
this->WriteMacros();
this->WriteHighLevelDirectives();
GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
this->WriteDisclaimer(this->GetBuildFileStream());
*this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
if (!fBspName.empty())
{
*this->GetBuildFileStream() << " -bsp " << fBspName << std::endl;
}
this->WriteCompilerOptions(fOSDir);
}
void cmGlobalGhsMultiGenerator::CloseBuildFileStream(
cmGeneratedFileStream **filestream)
{
if (filestream)
{
delete *filestream;
*filestream = NULL;
}
else
{
cmSystemTools::Error("Build file stream was not open.");
}
}
void cmGlobalGhsMultiGenerator::Generate()
{
this->cmGlobalGenerator::Generate();
if (!this->LocalGenerators.empty())
{
this->OpenBuildFileStream();
// Build all the folder build files
for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i)
{
cmLocalGhsMultiGenerator *lg =
static_cast<cmLocalGhsMultiGenerator *>(this->LocalGenerators[i]);
cmGeneratorTargetsType tgts = lg->GetMakefile()->GetGeneratorTargets();
this->UpdateBuildFiles(&tgts);
}
}
cmDeleteAll(TargetFolderBuildStreams);
this->TargetFolderBuildStreams.clear();
}
void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
std::vector<std::string> &makeCommand, const std::string &makeProgram,
const std::string & /*projectName*/, const std::string & /*projectDir*/,
const std::string &targetName, const std::string & /*config*/,
bool /*fast*/, bool /*verbose*/,
std::vector<std::string> const &makeOptions)
{
makeCommand.push_back(
this->SelectMakeProgram(makeProgram, this->GetGhsBuildCommand())
);
makeCommand.insert(makeCommand.end(),
makeOptions.begin(), makeOptions.end());
if (!targetName.empty())
{
if (targetName == "clean")
{
makeCommand.push_back("-clean");
}
else
{
makeCommand.push_back(targetName);
}
}
}
void cmGlobalGhsMultiGenerator::WriteMacros()
{
char const *ghsGpjMacros =
this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
if (NULL != ghsGpjMacros)
{
std::vector<std::string> expandedList;
cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
for (std::vector<std::string>::const_iterator expandedListI =
expandedList.begin();
expandedListI != expandedList.end(); ++expandedListI)
{
*this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
}
}
}
void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
{
*this->GetBuildFileStream() << "primaryTarget=arm_integrity.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;
this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
}
}
void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const &fOSDir)
{
*this->GetBuildFileStream() << " -os_dir=\"" << fOSDir << "\""
<< std::endl;
}
void cmGlobalGhsMultiGenerator::WriteDisclaimer(std::ostream *os)
{
(*os) << "#" << std::endl
<< "# CMAKE generated file: DO NOT EDIT!" << std::endl
<< "# Generated by \"" << GetActualName() << "\""
<< " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
<< cmVersion::GetMinorVersion() << std::endl
<< "#" << std::endl;
}
void cmGlobalGhsMultiGenerator::AddFilesUpToPath(
cmGeneratedFileStream *mainBuildFile,
std::map<std::string, cmGeneratedFileStream *> *targetFolderBuildStreams,
char const *homeOutputDirectory, std::string const &path,
GhsMultiGpj::Types projType, std::string const &relPath)
{
std::string workingPath(path);
cmSystemTools::ConvertToUnixSlashes(workingPath);
std::vector<cmsys::String> splitPath =
cmSystemTools::SplitString(workingPath);
std::string workingRelPath(relPath);
cmSystemTools::ConvertToUnixSlashes(workingRelPath);
if (!workingRelPath.empty())
{
workingRelPath += "/";
}
std::string pathUpTo;
for (std::vector<cmsys::String>::const_iterator splitPathI =
splitPath.begin();
splitPath.end() != splitPathI; ++splitPathI)
{
pathUpTo += *splitPathI;
if (targetFolderBuildStreams->end() ==
targetFolderBuildStreams->find(pathUpTo))
{
AddFilesUpToPathNewBuildFile(
mainBuildFile, targetFolderBuildStreams, homeOutputDirectory,
pathUpTo, splitPath.begin() == splitPathI, workingRelPath, projType);
}
AddFilesUpToPathAppendNextFile(targetFolderBuildStreams, pathUpTo,
splitPathI, splitPath.end(), projType);
pathUpTo += "/";
}
}
void cmGlobalGhsMultiGenerator::Open(
std::string const &mapKeyName, std::string const &fileName,
std::map<std::string, cmGeneratedFileStream *> *fileMap)
{
if (fileMap->end() == fileMap->find(fileName))
{
cmGeneratedFileStream *temp(new cmGeneratedFileStream);
temp->open(fileName.c_str());
(*fileMap)[mapKeyName] = temp;
}
}
void cmGlobalGhsMultiGenerator::AddFilesUpToPathNewBuildFile(
cmGeneratedFileStream *mainBuildFile,
std::map<std::string, cmGeneratedFileStream *> *targetFolderBuildStreams,
char const *homeOutputDirectory, std::string const &pathUpTo,
bool const isFirst, std::string const &relPath,
GhsMultiGpj::Types const projType)
{
// create folders up to file path
std::string absPath = std::string(homeOutputDirectory) + "/" + relPath;
std::string newPath = absPath + pathUpTo;
if (!cmSystemTools::FileExists(newPath.c_str()))
{
cmSystemTools::MakeDirectory(newPath.c_str());
}
// Write out to filename for first time
std::string relFilename(GetFileNameFromPath(pathUpTo));
std::string absFilename = absPath + relFilename;
Open(pathUpTo, absFilename, targetFolderBuildStreams);
OpenBuildFileStream((*targetFolderBuildStreams)[pathUpTo]);
GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo]);
// Add to main build file
if (isFirst)
{
*mainBuildFile << relFilename << " ";
GhsMultiGpj::WriteGpjTag(projType, mainBuildFile);
}
}
void cmGlobalGhsMultiGenerator::AddFilesUpToPathAppendNextFile(
std::map<std::string, cmGeneratedFileStream *> *targetFolderBuildStreams,
std::string const &pathUpTo,
std::vector<cmsys::String>::const_iterator splitPathI,
std::vector<cmsys::String>::const_iterator end,
GhsMultiGpj::Types const projType)
{
std::vector<cmsys::String>::const_iterator splitPathNextI = splitPathI + 1;
if (end != splitPathNextI &&
targetFolderBuildStreams->end() ==
targetFolderBuildStreams->find(pathUpTo + "/" + *splitPathNextI))
{
std::string nextFilename(*splitPathNextI);
nextFilename = GetFileNameFromPath(nextFilename);
*(*targetFolderBuildStreams)[pathUpTo] << nextFilename << " ";
GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
}
}
std::string
cmGlobalGhsMultiGenerator::GetFileNameFromPath(std::string const &path)
{
std::string output(path);
if (!path.empty())
{
cmSystemTools::ConvertToUnixSlashes(output);
std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(output);
output += "/" + splitPath.back() + FILE_EXTENSION;
}
return output;
}
void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
cmGeneratorTargetsType *tgts)
{
for (cmGeneratorTargetsType::iterator tgtsI = tgts->begin();
tgtsI != tgts->end(); ++tgtsI)
{
const cmTarget *tgt(tgtsI->first);
if (IsTgtForBuild(tgt))
{
char const *rawFolderName = tgtsI->first->GetProperty("FOLDER");
if (NULL == rawFolderName)
{
rawFolderName = "";
}
std::string folderName(rawFolderName);
if (this->TargetFolderBuildStreams.end() ==
this->TargetFolderBuildStreams.find(folderName))
{
this->AddFilesUpToPath(
GetBuildFileStream(), &this->TargetFolderBuildStreams,
this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName,
GhsMultiGpj::PROJECT);
}
std::vector<cmsys::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 cmTarget *tgt)
{
const std::string config =
tgt->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
std::vector<cmSourceFile *> tgtSources;
tgt->GetSourceFiles(tgtSources, config);
bool tgtInBuild = true;
char const *excludeFromAll = tgt->GetProperty("EXCLUDE_FROM_ALL");
if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
'\0' == excludeFromAll[1])
{
tgtInBuild = false;
}
return !tgtSources.empty() && tgtInBuild;
}
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;
}