summaryrefslogtreecommitdiffstats
path: root/Source/cmGhsMultiTargetGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGhsMultiTargetGenerator.cxx')
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx559
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;
+ }
+}