diff options
Diffstat (limited to 'Source/cmGhsMultiTargetGenerator.cxx')
-rw-r--r-- | Source/cmGhsMultiTargetGenerator.cxx | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx new file mode 100644 index 0000000..9f8f12b --- /dev/null +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -0,0 +1,559 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmGhsMultiTargetGenerator.h" + +#include "cmComputeLinkInformation.h" +#include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGhsMultiGenerator.h" +#include "cmLinkLineComputer.h" +#include "cmLocalGhsMultiGenerator.h" +#include "cmMakefile.h" +#include "cmSourceFile.h" +#include "cmSourceGroup.h" +#include "cmTarget.h" + +cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target) + : GeneratorTarget(target) + , LocalGenerator( + static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator())) + , Makefile(target->Target->GetMakefile()) + , Name(target->GetName()) +{ + // Store the configuration name that is being used + if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) { + // Use the build type given by the user. + this->ConfigName = config; + } else { + // No configuration type given. + this->ConfigName.clear(); + } +} + +cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator() +{ +} + +void cmGhsMultiTargetGenerator::Generate() +{ + // Determine type of target for this project + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::EXECUTABLE: { + // Get the name of the executable to generate. + this->TargetNameReal = + this->GeneratorTarget->GetExecutableNames(this->ConfigName).Real; + if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) { + this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION; + } else { + this->TagType = GhsMultiGpj::PROGRAM; + } + break; + } + case cmStateEnums::STATIC_LIBRARY: { + this->TargetNameReal = + this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real; + this->TagType = GhsMultiGpj::LIBRARY; + break; + } + case cmStateEnums::SHARED_LIBRARY: { + std::string msg = "add_library(<name> SHARED ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg); + return; + } + case cmStateEnums::OBJECT_LIBRARY: { + this->TargetNameReal = + this->GeneratorTarget->GetLibraryNames(this->ConfigName).Real; + this->TagType = GhsMultiGpj::SUBPROJECT; + break; + } + case cmStateEnums::MODULE_LIBRARY: { + std::string msg = "add_library(<name> MODULE ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg); + return; + } + case cmStateEnums::UTILITY: { + std::string msg = "add_custom_target(<name> ...) not supported: "; + msg += this->Name; + cmSystemTools::Message(msg); + 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() +{ + // Open the filestream in copy-if-different mode. + std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory(); + fname += "/"; + fname += this->Name; + fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION; + cmGeneratedFileStream fout(fname.c_str()); + fout.SetCopyIfDifferent(true); + + this->GetGlobalGenerator()->WriteFileHeader(fout); + GhsMultiGpj::WriteGpjTag(this->TagType, fout); + + const std::string language( + this->GeneratorTarget->GetLinkerLanguage(this->ConfigName)); + + this->WriteTargetSpecifics(fout, this->ConfigName); + this->SetCompilerFlags(this->ConfigName, language); + this->WriteCompilerFlags(fout, this->ConfigName, language); + this->WriteCompilerDefinitions(fout, this->ConfigName, language); + this->WriteIncludes(fout, this->ConfigName, language); + this->WriteTargetLinkLine(fout, this->ConfigName); + this->WriteCustomCommands(fout); + this->WriteSources(fout); + this->WriteReferences(fout); + fout.Close(); +} + +cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator() + const +{ + return static_cast<cmGlobalGhsMultiGenerator*>( + this->LocalGenerator->GetGlobalGenerator()); +} + +void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout, + const std::string& config) +{ + std::string outpath; + std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + + if (this->TagType != GhsMultiGpj::SUBPROJECT) { + // set target binary file destination + outpath = this->GeneratorTarget->GetDirectory(config); + outpath = + this->LocalGenerator->MaybeConvertToRelativePath(rootpath, outpath); + fout << " :binDirRelative=\"" << outpath << "\"" << std::endl; + fout << " -o \"" << this->TargetNameReal << "\"" << std::endl; + } + + // set target object file destination + outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); + fout << " :outputDirRelative=\"" << outpath << "\"" << std::endl; +} + +void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config, + const std::string& language) +{ + std::map<std::string, std::string>::iterator i = + this->FlagsByLanguage.find(language); + if (i == this->FlagsByLanguage.end()) { + std::string flags; + const char* lang = language.c_str(); + + this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang, + config); + + this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang, + config); + this->LocalGenerator->AddVisibilityPresetFlags( + flags, this->GeneratorTarget, lang); + + // Append old-style preprocessor definition flags. + if (this->Makefile->GetDefineFlags() != " ") { + this->LocalGenerator->AppendFlags(flags, + this->Makefile->GetDefineFlags()); + } + + // Add target-specific flags. + this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, lang, + config); + + std::map<std::string, std::string>::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<std::string, std::string>::iterator i = + this->DefinesByLanguage.find(language); + if (i == this->DefinesByLanguage.end()) { + std::set<std::string> defines; + const char* lang = language.c_str(); + // Add preprocessor definitions for this target and configuration. + this->LocalGenerator->GetTargetDefines(this->GeneratorTarget, config, + language, defines); + + std::string definesString; + this->LocalGenerator->JoinDefines(defines, definesString, lang); + + std::map<std::string, std::string>::value_type entry(language, + definesString); + i = this->DefinesByLanguage.insert(entry).first; + } + return i->second; +} + +void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout, + std::string const&, + const std::string& language) +{ + std::map<std::string, std::string>::iterator flagsByLangI = + this->FlagsByLanguage.find(language); + if (flagsByLangI != this->FlagsByLanguage.end()) { + if (!flagsByLangI->second.empty()) { + std::vector<std::string> ghsCompFlags = + cmSystemTools::ParseArguments(flagsByLangI->second); + for (auto& f : ghsCompFlags) { + fout << " " << f << std::endl; + } + } + } +} + +void cmGhsMultiTargetGenerator::WriteCompilerDefinitions( + std::ostream& fout, const std::string& config, const std::string& language) +{ + std::vector<std::string> compileDefinitions; + this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config, + language); + for (std::string const& compileDefinition : compileDefinitions) { + fout << " -D" << compileDefinition << std::endl; + } +} + +void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout, + const std::string& config, + const std::string& language) +{ + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->GeneratorTarget, + language, config); + + for (std::string const& include : includes) { + fout << " -I\"" << include << "\"" << std::endl; + } +} + +void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout, + std::string const& config) +{ + if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) { + return; + } + + std::string linkLibraries; + std::string flags; + std::string linkFlags; + std::string frameworkPath; + std::string linkPath; + + std::unique_ptr<cmLinkLineComputer> linkLineComputer( + this->GetGlobalGenerator()->CreateLinkLineComputer( + this->LocalGenerator, + this->LocalGenerator->GetStateSnapshot().GetDirectory())); + + this->LocalGenerator->GetTargetFlags( + linkLineComputer.get(), config, linkLibraries, flags, linkFlags, + frameworkPath, linkPath, this->GeneratorTarget); + + // write out link options + std::vector<std::string> lopts = cmSystemTools::ParseArguments(linkFlags); + for (auto& l : lopts) { + fout << " " << l << std::endl; + } + + // write out link search paths + // must be quoted for paths that contain spaces + std::vector<std::string> lpath = cmSystemTools::ParseArguments(linkPath); + for (auto& l : lpath) { + fout << " -L\"" << l << "\"" << std::endl; + } + + // write out link libs + // must be quoted for filepaths that contains spaces + std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory(); + + std::vector<std::string> llibs = + cmSystemTools::ParseArguments(linkLibraries); + for (auto& l : llibs) { + if (l.compare(0, 2, "-l") == 0) { + fout << " \"" << l << "\"" << std::endl; + } else { + std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l); + fout << " -l\"" << rl << "\"" << std::endl; + } + } +} + +void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout) +{ + WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(), + cmTarget::PRE_BUILD); + WriteCustomCommandsHelper( + fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD); +} + +void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( + std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet, + cmTarget::CustomCommandType const commandType) +{ + for (cmCustomCommand const& customCommand : commandsSet) { + cmCustomCommandLines const& commandLines = customCommand.GetCommandLines(); + for (cmCustomCommandLine const& command : commandLines) { + switch (commandType) { + case cmTarget::PRE_BUILD: + fout << " :preexecShellSafe="; + break; + case cmTarget::POST_BUILD: + fout << " :postexecShellSafe="; + break; + default: + assert("Only pre and post are supported"); + } + + bool firstIteration = true; + for (std::string const& commandLine : command) { + std::string subCommandE = + this->LocalGenerator->EscapeForShell(commandLine, true); + fout << (firstIteration ? "'" : " "); + // Need to double escape backslashes + cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\"); + fout << subCommandE; + firstIteration = false; + } + if (!command.empty()) { + fout << "'" << std::endl; + } + } + } +} + +void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout, + const cmSourceFile* sf, + std::string propName, + std::string propFlag) +{ + const char* prop = sf->GetProperty(propName); + if (prop) { + std::vector<std::string> list; + cmSystemTools::ExpandListArgument(prop, list); + for (auto& p : list) { + fout << " " << propFlag << p << std::endl; + } + } +} + +void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj) +{ + /* vector of all sources for this target */ + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName); + + /* vector of all groups defined for this target + * -- but the vector is not expanded with sub groups or in any useful order + */ + std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); + + /* for each source file assign it to its group */ + std::map<std::string, std::vector<cmSourceFile*>> groupFiles; + std::set<std::string> groupNames; + for (auto& sf : sources) { + cmSourceGroup* sourceGroup = + this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups); + std::string gn = sourceGroup->GetFullName(); + groupFiles[gn].push_back(sf); + groupNames.insert(gn); + } + + /* list of known groups and the order they are displayed in a project file */ + const std::vector<std::string> standardGroups = { + "Header Files", "Source Files", "CMake Rules", + "Object Files", "Object Libraries", "Resources" + }; + + /* list of groups in the order they are displayed in a project file*/ + std::vector<std::string> groupFilesList(groupFiles.size()); + + /* put the groups in the order they should be listed + * - standard groups first, and then everything else + * in the order used by std::map. + */ + int i = 0; + for (const std::string& gn : standardGroups) { + auto n = groupNames.find(gn); + if (n != groupNames.end()) { + groupFilesList[i] = *n; + i += 1; + groupNames.erase(gn); + } + } + + { /* catch-all group - is last item */ + std::string gn = ""; + auto n = groupNames.find(gn); + if (n != groupNames.end()) { + groupFilesList.back() = *n; + groupNames.erase(gn); + } + } + + for (auto& n : groupNames) { + groupFilesList[i] = n; + i += 1; + } + + /* sort the files within each group */ + for (auto& n : groupFilesList) { + std::sort(groupFiles[n].begin(), groupFiles[n].end(), + [](cmSourceFile* l, cmSourceFile* r) { + return l->GetFullPath() < r->GetFullPath(); + }); + } + + /* list of open project files */ + std::vector<cmGeneratedFileStream*> gfiles; + + /* write files into the proper project file + * -- groups go into main project file + * unless FOLDER property or variable is set. + */ + for (auto& sg : groupFilesList) { + std::ostream* fout; + bool useProjectFile = + cmSystemTools::IsOn( + this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) || + cmSystemTools::IsOn( + this->Makefile->GetDefinition("CMAKE_GHS_NO_SOURCE_GROUP_FILE")); + if (useProjectFile || sg.empty()) { + fout = &fout_proj; + } else { + // Open the filestream in copy-if-different mode. + std::string gname = sg; + cmsys::SystemTools::ReplaceString(gname, "\\", "_"); + std::string lpath = + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget); + lpath += "/"; + lpath += gname; + lpath += cmGlobalGhsMultiGenerator::FILE_EXTENSION; + std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + fpath += "/"; + fpath += lpath; + cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str()); + f->SetCopyIfDifferent(true); + gfiles.push_back(f); + fout = f; + this->GetGlobalGenerator()->WriteFileHeader(*f); + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f); + fout_proj << lpath << " "; + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj); + } + + if (useProjectFile) { + if (sg.empty()) { + *fout << "{comment} Others" << std::endl; + } else { + *fout << "{comment} " << sg << std::endl; + } + } + + /* output rule for each source file */ + for (const cmSourceFile* si : groupFiles[sg]) { + + // Convert filename to native system + // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on + // windows when opening some files from the search window. + std::string fname(si->GetFullPath()); + cmSystemTools::ConvertToOutputSlashes(fname); + *fout << fname << std::endl; + + if ("ld" != si->GetExtension() && "int" != si->GetExtension() && + "bsp" != si->GetExtension()) { + this->WriteObjectLangOverride(*fout, si); + } + + this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I"); + this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D"); + this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", ""); + + /* to avoid clutter in the gui only print out the objectName if it has + * been renamed */ + std::string objectName = this->GeneratorTarget->GetObjectName(si); + if (!objectName.empty() && + this->GeneratorTarget->HasExplicitObjectName(si)) { + *fout << " -o " << objectName << std::endl; + } + } + } + + for (cmGeneratedFileStream* f : gfiles) { + f->Close(); + } +} + +void cmGhsMultiTargetGenerator::WriteObjectLangOverride( + std::ostream& fout, const 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)) { + fout << " -dotciscxx" << std::endl; + } + } +} + +void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout) +{ + // This only applies to INTEGRITY Applications + if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) { + return; + } + + // Get the targets that this one depends upon + cmTargetDependSet unordered = + this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget); + cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered, + this->Name); + for (auto& t : ordered) { + std::string tname = t->GetName(); + std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory(); + std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory(); + std::string outpath = + this->LocalGenerator->MaybeConvertToRelativePath(rootpath, tpath) + "/" + + tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION; + + fout << outpath; + fout << " "; + GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout); + + // Tell the global generator that a refernce project needs to be created + t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON"); + } +} + +bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void) +{ + const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app"); + if (p) { + return cmSystemTools::IsOn( + this->GeneratorTarget->GetProperty("ghs_integrity_app")); + } else { + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName); + for (auto& sf : sources) { + if ("int" == sf->GetExtension()) { + return true; + } + } + return false; + } +} |