/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2015 Geoffrey Viola 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 "cmGeneratedFileStream.h" #include "cmGhsMultiTargetGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" #include "cmVersion.h" #include #include const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj"; const char* cmGlobalGhsMultiGenerator::DEFAULT_MAKE_PROGRAM = "gbuild"; cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm) : cmGlobalGenerator(cm) , OSDirRelative(false) { this->GhsBuildCommandInitialized = false; } cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator() { cmDeleteAll(TargetFolderBuildStreams); } 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::EnableLanguage( std::vector 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 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 potentialDirsHardPaths( GetCompRootHardPaths()); const std::vector potentialDirsRegistry(GetCompRootRegistry()); std::vector 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::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 cmGlobalGhsMultiGenerator::GetCompRootHardPaths() { std::vector output; cmSystemTools::Glob("C:/ghs", "comp_[^;]+", output); for (std::vector::iterator outputIt = output.begin(); outputIt != output.end(); ++outputIt) { *outputIt = "C:/ghs/" + *outputIt; } return output; } std::vector cmGlobalGhsMultiGenerator::GetCompRootRegistry() { std::vector 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(this->LocalGenerators[i]); std::vector tgts = lg->GetGeneratorTargets(); this->UpdateBuildFiles(tgts); } } cmDeleteAll(TargetFolderBuildStreams); this->TargetFolderBuildStreams.clear(); } void cmGlobalGhsMultiGenerator::GenerateBuildCommand( std::vector& 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 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 expandedList; cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList); for (std::vector::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* targetFolderBuildStreams, char const* homeOutputDirectory, std::string const& path, GhsMultiGpj::Types projType, std::string const& relPath) { std::string workingPath(path); cmSystemTools::ConvertToUnixSlashes(workingPath); std::vector splitPath = cmSystemTools::SplitString(workingPath); std::string workingRelPath(relPath); cmSystemTools::ConvertToUnixSlashes(workingRelPath); if (!workingRelPath.empty()) { workingRelPath += "/"; } std::string pathUpTo; for (std::vector::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* 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* 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* targetFolderBuildStreams, std::string const& pathUpTo, std::vector::const_iterator splitPathI, std::vector::const_iterator end, GhsMultiGpj::Types const projType) { std::vector::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 splitPath = cmSystemTools::SplitString(output); output += "/" + splitPath.back() + FILE_EXTENSION; } return output; } void cmGlobalGhsMultiGenerator::UpdateBuildFiles( std::vector tgts) { for (std::vector::iterator tgtsI = tgts.begin(); tgtsI != tgts.end(); ++tgtsI) { const cmGeneratorTarget* tgt = *tgtsI; if (IsTgtForBuild(tgt)) { char const* rawFolderName = tgt->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 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 = tgt->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); std::vector 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; }