/*============================================================================ 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 "cmGhsMultiTargetGenerator.h" #include "cmGlobalGhsMultiGenerator.h" #include "cmLocalGhsMultiGenerator.h" #include "cmMakefile.h" #include "cmTarget.h" #include "cmGeneratedFileStream.h" #include "cmSourceFile.h" #include #include std::string const cmGhsMultiTargetGenerator::DDOption("-dynamic"); cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget *target) : Target(target->Target) , GeneratorTarget(target) , LocalGenerator(static_cast( target->GetLocalGenerator())) , Makefile(target->Target->GetMakefile()) , TargetGroup(DetermineIfTargetGroup(target)) , DynamicDownload(false) { this->RelBuildFilePath = this->GetRelBuildFilePath(target->Target); this->RelOutputFileName = this->RelBuildFilePath + this->Target->GetName() + ".a"; this->RelBuildFileName = this->RelBuildFilePath; this->RelBuildFileName += this->GetBuildFileName(target->Target); std::string absPathToRoot = this->GetAbsPathToRoot(target->Target); absPathToRoot = this->AddSlashIfNeededToPath(absPathToRoot); this->AbsBuildFilePath = absPathToRoot + this->RelBuildFilePath; this->AbsBuildFileName = absPathToRoot + this->RelBuildFileName; this->AbsOutputFileName = absPathToRoot + this->RelOutputFileName; } cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() { cmDeleteAll(this->FolderBuildStreams); } std::string cmGhsMultiTargetGenerator::GetRelBuildFilePath(const cmTarget *target) { std::string output; char const *folderProp = target->GetProperty("FOLDER"); output = NULL == folderProp ? "" : folderProp; cmSystemTools::ConvertToUnixSlashes(output); if (!output.empty()) { output += "/"; } output += target->GetName() + "/"; return output; } std::string cmGhsMultiTargetGenerator::GetAbsPathToRoot(const cmTarget *target) { cmGeneratorTarget* gt = target->GetMakefile()->GetGlobalGenerator() ->GetGeneratorTarget(target); return gt->GetLocalGenerator()->GetBinaryDirectory(); } std::string cmGhsMultiTargetGenerator::GetAbsBuildFilePath(const cmTarget *target) { std::string output; output = cmGhsMultiTargetGenerator::GetAbsPathToRoot(target); output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output); output += cmGhsMultiTargetGenerator::GetRelBuildFilePath(target); return output; } std::string cmGhsMultiTargetGenerator::GetRelBuildFileName(const cmTarget *target) { std::string output; output = cmGhsMultiTargetGenerator::GetRelBuildFilePath(target); output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output); output += cmGhsMultiTargetGenerator::GetBuildFileName(target); return output; } std::string cmGhsMultiTargetGenerator::GetBuildFileName(const cmTarget *target) { std::string output; output = target->GetName(); output += cmGlobalGhsMultiGenerator::FILE_EXTENSION; return output; } std::string cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(std::string const &input) { std::string output(input); if (!cmHasLiteralSuffix(output, "/")) { output += "/"; } return output; } void cmGhsMultiTargetGenerator::Generate() { const std::vector objectSources = this->GetSources(); if (!objectSources.empty() && this->IncludeThisTarget()) { if (!cmSystemTools::FileExists(this->AbsBuildFilePath.c_str())) { cmSystemTools::MakeDirectory(this->AbsBuildFilePath.c_str()); } cmGlobalGhsMultiGenerator::Open(std::string(""), this->AbsBuildFileName, &this->FolderBuildStreams); cmGlobalGhsMultiGenerator::OpenBuildFileStream( this->GetFolderBuildStreams()); std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); if (0 == config.length()) { config = "RELEASE"; } const std::string language( this->GeneratorTarget->GetLinkerLanguage(config)); config = cmSystemTools::UpperCase(config); this->DynamicDownload = this->DetermineIfDynamicDownload(config, language); if (this->DynamicDownload) { *this->GetFolderBuildStreams() << "#component integrity_dynamic_download" << std::endl; } GhsMultiGpj::WriteGpjTag(this->GetGpjTag(), this->GetFolderBuildStreams()); cmGlobalGhsMultiGenerator::WriteDisclaimer(this->GetFolderBuildStreams()); bool const notKernel = this->IsNotKernel(config, language); this->WriteTypeSpecifics(config, notKernel); this->SetCompilerFlags(config, language, notKernel); this->WriteCompilerFlags(config, language); this->WriteCompilerDefinitions(config, language); this->WriteIncludes(config, language); if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) { this->WriteTargetLinkLibraries(); } this->WriteCustomCommands(); this->WriteSources(objectSources); } } bool cmGhsMultiTargetGenerator::IncludeThisTarget() { bool output = true; char const *excludeFromAll = this->Target->GetProperty("EXCLUDE_FROM_ALL"); if (NULL != excludeFromAll && '1' == excludeFromAll[0] && '\0' == excludeFromAll[1]) { output = false; } return output; } std::vector cmGhsMultiTargetGenerator::GetSources() const { std::vector output; std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); this->GeneratorTarget->GetSourceFiles(output, config); 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() == cmState::STATIC_LIBRARY) { output = GhsMultiGpj::LIBRARY; } else { output = GhsMultiGpj::PROGRAM; } return output; } cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator() const { return static_cast( this->LocalGenerator->GetGlobalGenerator()); } void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string &config, bool const notKernel) { std::string outputDir(this->GetOutputDirectory(config)); std::string outputFilename(this->GetOutputFilename(config)); if (this->GeneratorTarget->GetType() == cmState::STATIC_LIBRARY) { *this->GetFolderBuildStreams() << " {optgroup=GhsCommonOptions} -o \"" << outputDir << outputFilename << ".a\"" << std::endl; } else if (this->GeneratorTarget->GetType() == cmState::EXECUTABLE) { if (notKernel && !this->IsTargetGroup()) { *this->GetFolderBuildStreams() << " -relprog" << std::endl; } if (this->IsTargetGroup()) { *this->GetFolderBuildStreams() << " {optgroup=GhsCommonOptions} -o \"" << outputDir << outputFilename << ".elf\"" << std::endl; *this->GetFolderBuildStreams() << " :extraOutputFile=\"" << outputDir << outputFilename << ".elf.ael\"" << std::endl; } else { *this->GetFolderBuildStreams() << " {optgroup=GhsCommonOptions} -o \"" << outputDir << outputFilename << ".as\"" << std::endl; } } } void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const &config, const std::string &language, bool const notKernel) { std::map::iterator i = this->FlagsByLanguage.find(language); if (i == this->FlagsByLanguage.end()) { std::string flags; const char *lang = language.c_str(); if (notKernel) { this->LocalGenerator->AddLanguageFlags(flags, lang, config); } else { this->LocalGenerator->AddLanguageFlags( flags, lang + std::string("_GHS_KERNEL"), config); } this->LocalGenerator->AddCMP0018Flags(flags, this->Target, lang, config); this->LocalGenerator->AddVisibilityPresetFlags(flags, this->Target, lang); // Append old-style preprocessor definition flags. if (std::string(" ") != std::string(this->Makefile->GetDefineFlags())) { this->LocalGenerator->AppendFlags(flags, this->Makefile->GetDefineFlags()); } // Add target-specific flags. this->LocalGenerator->AddCompileOptions(flags, this->Target, lang, config); std::map::value_type entry(language, flags); i = this->FlagsByLanguage.insert(entry).first; } } std::string cmGhsMultiTargetGenerator::GetDefines(const std::string &language, std::string const &config) { std::map::iterator i = this->DefinesByLanguage.find(language); if (i == this->DefinesByLanguage.end()) { std::set defines; const char *lang = language.c_str(); // Add the export symbol definition for shared library objects. if (const char *exportMacro = this->Target->GetExportMacro()) { this->LocalGenerator->AppendDefines(defines, exportMacro); } // Add preprocessor definitions for this target and configuration. this->LocalGenerator->AddCompileDefinitions(defines, this->Target, config, language); std::string definesString; this->LocalGenerator->JoinDefines(defines, definesString, lang); std::map::value_type entry(language, definesString); i = this->DefinesByLanguage.insert(entry).first; } return i->second; } void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::string const &, const std::string &language) { std::map::iterator flagsByLangI = this->FlagsByLanguage.find(language); if (flagsByLangI != this->FlagsByLanguage.end()) { if (!flagsByLangI->second.empty()) { *this->GetFolderBuildStreams() << " " << flagsByLangI->second << std::endl; } } } void cmGhsMultiTargetGenerator::WriteCompilerDefinitions( const std::string &config, const std::string &language) { std::vector compileDefinitions; this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config, language); for (std::vector::const_iterator cdI = compileDefinitions.begin(); cdI != compileDefinitions.end(); ++cdI) { *this->GetFolderBuildStreams() << " -D" << (*cdI) << std::endl; } } void cmGhsMultiTargetGenerator::WriteIncludes(const std::string &config, const std::string &language) { std::vector includes = this->GeneratorTarget->GetIncludeDirectories(config, language); for (std::vector::const_iterator includes_i = includes.begin(); includes_i != includes.end(); ++includes_i) { *this->GetFolderBuildStreams() << " -I\"" << *includes_i << "\"" << std::endl; } } void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries() { // library directories cmTargetDependSet tds = this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget); for (cmTargetDependSet::iterator tdsI = tds.begin(); tdsI != tds.end(); ++tdsI) { const cmTarget *tg = (*tdsI)->Target; *this->GetFolderBuildStreams() << " -L\"" << GetAbsBuildFilePath(tg) << "\"" << std::endl; } // library targets cmTarget::LinkLibraryVectorType llv = this->Target->GetOriginalLinkLibraries(); for (cmTarget::LinkLibraryVectorType::const_iterator llvI = llv.begin(); llvI != llv.end(); ++llvI) { std::string libName = llvI->first; // if it is a user defined target get the full path to the lib cmTarget *tg(GetGlobalGenerator()->FindTarget(libName)); if (NULL != tg) { libName = tg->GetName() + ".a"; } *this->GetFolderBuildStreams() << " -l\"" << libName << "\"" << std::endl; } } void cmGhsMultiTargetGenerator::WriteCustomCommands() { WriteCustomCommandsHelper(this->Target->GetPreBuildCommands(), cmTarget::PRE_BUILD); WriteCustomCommandsHelper(this->Target->GetPostBuildCommands(), cmTarget::POST_BUILD); } void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( std::vector const &commandsSet, cmTarget::CustomCommandType const commandType) { for (std::vector::const_iterator commandsSetI = commandsSet.begin(); commandsSetI != commandsSet.end(); ++commandsSetI) { cmCustomCommandLines const &commands = commandsSetI->GetCommandLines(); for (cmCustomCommandLines::const_iterator commandI = commands.begin(); commandI != commands.end(); ++commandI) { switch (commandType) { case cmTarget::PRE_BUILD: *this->GetFolderBuildStreams() << " :preexecShellSafe="; break; case cmTarget::POST_BUILD: *this->GetFolderBuildStreams() << " :postexecShellSafe="; break; default: assert("Only pre and post are supported"); } cmCustomCommandLine const &command = *commandI; for (cmCustomCommandLine::const_iterator commandLineI = command.begin(); commandLineI != command.end(); ++commandLineI) { std::string subCommandE = this->LocalGenerator->EscapeForShell(*commandLineI, true); if (!command.empty()) { *this->GetFolderBuildStreams() << (command.begin() == commandLineI ? "'" : " "); //Need to double escape backslashes cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\"); } *this->GetFolderBuildStreams() << subCommandE; } if (!command.empty()) { *this->GetFolderBuildStreams() << "'" << std::endl; } } } } void cmGhsMultiTargetGenerator::WriteSources( std::vector const &objectSources) { for (std::vector::const_iterator si = objectSources.begin(); si != objectSources.end(); ++si) { std::vector sourceGroups(this->Makefile->GetSourceGroups()); char const *sourceFullPath = (*si)->GetFullPath().c_str(); cmSourceGroup *sourceGroup = this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups); std::string sgPath(sourceGroup->GetFullName()); cmSystemTools::ConvertToUnixSlashes(sgPath); cmGlobalGhsMultiGenerator::AddFilesUpToPath( this->GetFolderBuildStreams(), &this->FolderBuildStreams, this->LocalGenerator->GetBinaryDirectory(), sgPath, GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath); std::string fullSourcePath((*si)->GetFullPath()); if ((*si)->GetExtension() == "int" || (*si)->GetExtension() == "bsp") { *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl; } else { //WORKAROUND: GHS MULTI needs the path to use backslashes without quotes // to open files in search as of version 6.1.6 cmsys::SystemTools::ReplaceString(fullSourcePath, "/", "\\"); *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl; } if ("ld" != (*si)->GetExtension() && "int" != (*si)->GetExtension() && "bsp" != (*si)->GetExtension()) { this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], (*si)); this->WriteObjectDir(this->FolderBuildStreams[sgPath], this->AbsBuildFilePath + sgPath); } } } void cmGhsMultiTargetGenerator::WriteObjectLangOverride( cmGeneratedFileStream *fileStream, cmSourceFile *sourceFile) { const char *rawLangProp = sourceFile->GetProperty("LANGUAGE"); if (NULL != rawLangProp) { std::string sourceLangProp(rawLangProp); std::string extension(sourceFile->GetExtension()); if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) { *fileStream << " -dotciscxx" << std::endl; } } } void cmGhsMultiTargetGenerator::WriteObjectDir( cmGeneratedFileStream *fileStream, std::string const &dir) { std::string workingDir(dir); cmSystemTools::ConvertToUnixSlashes(workingDir); if (!workingDir.empty()) { workingDir += "/"; } workingDir += "Objs"; *fileStream << " -object_dir=\"" << workingDir << "\"" << std::endl; } std::string cmGhsMultiTargetGenerator::GetOutputDirectory(const std::string &config) const { std::string outputDir(AbsBuildFilePath); const char *runtimeOutputProp = this->Target->GetProperty("RUNTIME_OUTPUT_DIRECTORY"); if (NULL != runtimeOutputProp) { outputDir = runtimeOutputProp; } std::string configCapped(cmSystemTools::UpperCase(config)); const char *runtimeOutputSProp = this->Target->GetProperty("RUNTIME_OUTPUT_DIRECTORY_" + configCapped); if (NULL != runtimeOutputSProp) { outputDir = runtimeOutputSProp; } cmSystemTools::ConvertToUnixSlashes(outputDir); if (!outputDir.empty()) { outputDir += "/"; } return outputDir; } std::string cmGhsMultiTargetGenerator::GetOutputFilename(const std::string &config) const { std::string outputFilename(this->Target->GetName()); const char *outputNameProp = this->Target->GetProperty("OUTPUT_NAME"); if (NULL != outputNameProp) { outputFilename = outputNameProp; } std::string configCapped(cmSystemTools::UpperCase(config)); const char *outputNameSProp = this->Target->GetProperty(configCapped + "_OUTPUT_NAME"); if (NULL != outputNameSProp) { outputFilename = outputNameSProp; } return outputFilename; } bool cmGhsMultiTargetGenerator::IsNotKernel(std::string const &config, const std::string &language) { bool output; std::vector options; this->GeneratorTarget->GetCompileOptions(options, config, language); output = options.end() == std::find(options.begin(), options.end(), "-kernel"); return output; } bool cmGhsMultiTargetGenerator::DetermineIfTargetGroup( const cmGeneratorTarget *target) { bool output = false; std::vector sources; std::string config = target->Target->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"); target->GetSourceFiles(sources, config); for (std::vector::const_iterator sources_i = sources.begin(); sources.end() != sources_i; ++sources_i) { if ("int" == (*sources_i)->GetExtension()) { output = true; } } return output; } bool cmGhsMultiTargetGenerator::DetermineIfDynamicDownload( std::string const &config, const std::string &language) { std::vector options; bool output = false; this->GeneratorTarget->GetCompileOptions(options, config, language); for (std::vector::const_iterator options_i = options.begin(); options_i != options.end(); ++options_i) { std::string option = *options_i; if (this->DDOption == option) { output = true; } } return output; }