On 10/09/2014 07:36 PM, Geoffrey Viola wrote:
> Attached is a patch to make CMake generate files for the Green
> Hills MULTI IDE. These patches are in reference to this feature
> request: http://public.kitware.com/Bug/view.php?id=14992.

Thanks for working on this.

First I've extracted the comment typo fixes from the second patch:

 Fix some spelling errors in comments
 http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=bef23e81

I've attached a patch rebasing the rest of the changes on 'master'
after integration of the typo fixes.

To aid others for review, please provide a high-level explanation
of the MULTI IDE, its target platforms, and how developers might
use it with CMake.

> There were some limitations. It has been restricted to Windows,
> because that is the version of the IDE that I have. There is a
> special grouping called a Monolith that includes several
> executables, shared libraries, and the kernel. These monoliths
> have their own set of compile options. I’m not sure how CMake
> would be able to create these. Also, there are some internal
> macros that point to the compiler’s target BSP and OS that are
> currently populated via CMake variables: GHS_CUSTOMIZATION,
> GHS_OS_DIR, and GHS_BSP_NAME.

Depending on the semantics, these may belong in
Modules/Platform/<os>.cmake for some <os> name of the target
platform.  We'll need a better understanding of their role to
say for sure though.  See CMAKE_OSX_SYSROOT in Darwin*.cmake
for example.

Thanks,
-Brad
>From 2a6c15be56d938d1fac6a06ef9acb06ceeec1e67 Mon Sep 17 00:00:00 2001
Message-Id: <2a6c15be56d938d1fac6a06ef9acb06ceeec1e67.1413294735.git.brad.k...@kitware.com>
From: Geoff Viola <[email protected]>
Date: Thu, 9 Oct 2014 17:07:48 -0600
Subject: [PATCH] Added basic and partial support for a Green Hill MULTI IDE.

---
 Modules/CMakeGreenHillsFindMake.cmake |  25 +++
 Source/CMakeLists.txt                 |   6 +
 Source/cmGhsMultiTargetGenerator.cxx  | 301 ++++++++++++++++++++++++++++++
 Source/cmGhsMultiTargetGenerator.h    |  74 ++++++++
 Source/cmGlobalGhsMultiGenerator.cxx  | 338 ++++++++++++++++++++++++++++++++++
 Source/cmGlobalGhsMultiGenerator.h    | 104 +++++++++++
 Source/cmLocalGhsMultiGenerator.cxx   |  56 ++++++
 Source/cmLocalGhsMultiGenerator.h     |  56 ++++++
 Source/cmake.cxx                      |   4 +
 9 files changed, 964 insertions(+)
 create mode 100644 Modules/CMakeGreenHillsFindMake.cmake
 create mode 100644 Source/cmGhsMultiTargetGenerator.cxx
 create mode 100644 Source/cmGhsMultiTargetGenerator.h
 create mode 100644 Source/cmGlobalGhsMultiGenerator.cxx
 create mode 100644 Source/cmGlobalGhsMultiGenerator.h
 create mode 100644 Source/cmLocalGhsMultiGenerator.cxx
 create mode 100644 Source/cmLocalGhsMultiGenerator.h

diff --git a/Modules/CMakeGreenHillsFindMake.cmake b/Modules/CMakeGreenHillsFindMake.cmake
new file mode 100644
index 0000000..7af9f18
--- /dev/null
+++ b/Modules/CMakeGreenHillsFindMake.cmake
@@ -0,0 +1,25 @@
+
+#=============================================================================
+# Copyright 2005-2009 Kitware, Inc.
+#
+# 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.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+# set(CMAKE_CROSSCOMPILING TRUE)
+
+set(CMAKE_SYSTEM_NAME "Green Hills MULTI")
+set(CMAKE_SYSTEM_PROCESSOR "ARM")
+find_program(CMAKE_MAKE_PROGRAM gbuild.exe PATHS
+    "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\GreenHillsSoftware9881cef6;InstallLocation]"
+    c:/ghs/comp_.*
+)
+string(REGEX MATCH "(comp_)([0-9]+)" CMAKE_SYSTEM_VERSION "${CMAKE_MAKE_PROGRAM}")
+string(REPLACE "comp_" "" CMAKE_SYSTEM_VERSION "${CMAKE_SYSTEM_VERSION}")
+
+mark_as_advanced(CMAKE_MAKE_PROGRAM)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index f9405b3..df642d5 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -446,6 +446,12 @@ if (WIN32)
       cmVisualStudioSlnParser.cxx
       cmVisualStudioWCEPlatformParser.h
       cmVisualStudioWCEPlatformParser.cxx
+      cmGlobalGhsMultiGenerator.cxx
+      cmGlobalGhsMultiGenerator.h
+      cmLocalGhsMultiGenerator.cxx
+      cmLocalGhsMultiGenerator.h
+      cmGhsMultiTargetGenerator.cxx
+      cmGhsMultiTargetGenerator.h
       )
   endif()
 endif ()
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
new file mode 100644
index 0000000..9a955bc
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -0,0 +1,301 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <[email protected]>
+  Copyright 2011 Nicolas Despres <[email protected]>
+
+  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 <assert.h>
+
+cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmTarget const* target)
+  : Target(target)
+  , LocalGenerator(static_cast<cmLocalGhsMultiGenerator*>
+      (target->GetMakefile()->GetLocalGenerator()))
+  , Makefile(target->GetMakefile())
+{
+  std::string BuildFileName;
+  BuildFileName = this->Target->GetFullName();
+  BuildFileName += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+
+  char const* folderProp = this->Target->GetProperty("FOLDER");
+  RelBuildFilePath = nullptr == folderProp ? "" : folderProp;
+  if (RelBuildFilePath.size() > 0 && '/' != RelBuildFilePath.back())
+  {
+    RelBuildFilePath += "/";
+  }
+  RelBuildFilePath += Target->GetName() + "/";
+
+  RelOutputFileName = RelBuildFilePath + Target->GetName() + ".a";
+
+  RelBuildFileName = RelBuildFilePath;
+  if (RelBuildFileName.size() > 0 && '/' != RelBuildFileName.back())
+  {
+    RelBuildFileName += "/";
+  }
+  RelBuildFileName += BuildFileName;
+
+  std::string absPathToRoot(this->Makefile->GetHomeOutputDirectory());
+  if (absPathToRoot.size() > 0 && '/' != absPathToRoot.back())
+  {
+    absPathToRoot += "/";
+  }
+  AbsBuildFilePath = absPathToRoot + RelBuildFilePath;
+  AbsBuildFileName = absPathToRoot + RelBuildFileName;
+  AbsOutputFileName = absPathToRoot + RelOutputFileName;
+}
+
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
+{
+}
+
+void cmGhsMultiTargetGenerator::Generate()
+{
+  std::vector<cmSourceFile*> objectSources = GetSources();
+  if (objectSources.size() > 0 && IncludeThisTarget())
+  {
+    if (!cmSystemTools::FileExists(AbsBuildFilePath.c_str()))
+    {
+      cmSystemTools::MakeDirectory(AbsBuildFilePath.c_str());
+    }
+    FolderBuildStreams[""].open(this->AbsBuildFileName.c_str());
+    cmGlobalGhsMultiGenerator::OpenBuildFileStream(GetFolderBuildStreams());
+    cmGlobalGhsMultiGenerator::WriteGpjTag(cmGlobalGhsMultiGenerator::PROGRAM,
+      this->GetFolderBuildStreams());
+    cmGlobalGhsMultiGenerator::WriteDisclaimer(GetFolderBuildStreams());
+
+    WriteTypeSpecifics();
+    const std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+    WriteCompilerOptions(config);
+    WriteCompilerFlags();
+    WriteCompilerDefinitions(config);
+    WriteIncludes(config);
+    WriteTargetLinkLibraries();
+    WriteCustomCommands();
+
+    WriteSources(objectSources);
+  }
+}
+
+bool cmGhsMultiTargetGenerator::IncludeThisTarget()
+{
+  bool output = true;
+  char const* excludeFromAll = this->Target->GetProperty("EXCLUDE_FROM_ALL");
+  if (nullptr != excludeFromAll &&
+    '1' == excludeFromAll[0] &&
+    '\0' == excludeFromAll[1])
+  {
+    output = false;
+  }
+  return output;
+}
+
+std::vector<cmSourceFile*> cmGhsMultiTargetGenerator::GetSources() const
+{
+  std::vector<cmSourceFile*> output;
+  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  this->Target->GetSourceFiles(output, config);
+  return output;
+}
+
+cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator() const
+{
+  return static_cast<cmGlobalGhsMultiGenerator*>(LocalGenerator->GetGlobalGenerator());
+}
+
+void cmGhsMultiTargetGenerator::WriteTypeSpecifics()
+{
+  if (Target->GetType() == cmTarget::TargetType::STATIC_LIBRARY)
+  {
+    *GetFolderBuildStreams() << "    -relobj" << std::endl;
+    *GetFolderBuildStreams() << "    {optgroup=GhsCommonOptions} -o " <<
+      AbsBuildFilePath << Target->GetFullName() << ".a" << std::endl;
+  }
+  else if (Target->GetType() == cmTarget::TargetType::EXECUTABLE)
+  {
+    *GetFolderBuildStreams() << "    -relprog" << std::endl;
+    *GetFolderBuildStreams() << "    {optgroup=GhsCommonOptions} -o " <<
+      AbsBuildFilePath << Target->GetFullName() << ".a" << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerOptions(std::string const& config)
+{
+  std::vector<std::string> options;
+  Target->GetCompileOptions(options, config);
+  for (std::vector<std::string>::const_iterator options_i = options.begin();
+    options_i != options.end(); ++options_i)
+  {
+    std::string option = *options_i;
+    cmSystemTools::ConvertToUnixSlashes(option);
+    *this->GetFolderBuildStreams() << "    " << option << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerFlags()
+{
+  char const* const compileFlags = Target->GetProperty("COMPILE_FLAGS");
+  if (nullptr != compileFlags)
+  {
+    *this->GetFolderBuildStreams() << "    " << compileFlags << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(const std::string& config)
+{
+  std::vector<std::string> compileDefinitions;
+  this->Target->GetCompileDefinitions(compileDefinitions, config);
+  for (std::vector<std::string>::const_iterator cdI = compileDefinitions.begin();
+    cdI != compileDefinitions.end(); ++cdI)
+  {
+    *this->GetFolderBuildStreams() << "    -D" << (*cdI) << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config)
+{
+  std::vector<std::string> includes = Target->GetIncludeDirectories(config);
+  for (std::vector<std::string>::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 = GetGlobalGenerator()->GetTargetDirectDepends(*this->Target);
+  for (cmTargetDependSet::iterator tdsI = tds.begin();
+    tdsI != tds.end(); ++tdsI)
+  {
+    cmTarget const *tg(*tdsI);
+    cmGhsMultiTargetGenerator gmtg(tg);
+    *this->GetFolderBuildStreams() << "    -L" << gmtg.GetAbsBuildFilePath() << 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 (nullptr != tg)
+    {
+      cmGhsMultiTargetGenerator gmtg(tg);
+      libName = tg->GetName() + ".a";
+    }
+    *this->GetFolderBuildStreams() << "    -l" << libName << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommands()
+{
+  WriteCustomCommandsHelper(this->Target->GetPreBuildCommands(),
+    cmTarget::CustomCommandType::PRE_BUILD);
+  WriteCustomCommandsHelper(this->Target->GetPostBuildCommands(),
+    cmTarget::CustomCommandType::POST_BUILD);
+}
+
+void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
+  std::vector<cmCustomCommand> const& commandsSet, cmTarget::CustomCommandType const commandType)
+{
+  for (std::vector<cmCustomCommand>::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::CustomCommandType::PRE_BUILD:
+        *GetFolderBuildStreams() << "    :preexecShellSafe=";
+        break;
+      case cmTarget::CustomCommandType::POST_BUILD:
+        *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)
+      {
+        if (command.size() > 0)
+        {
+          *GetFolderBuildStreams() << (command.begin() == commandLineI ? "'" : " ");
+        }
+        *GetFolderBuildStreams() << *commandLineI;
+      }
+      if (command.size() > 0)
+      {
+        *GetFolderBuildStreams() << "'" << std::endl;
+      }
+    }
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteSources(std::vector<cmSourceFile*>
+  const& objectSources)
+{
+  for (std::vector<cmSourceFile*>::const_iterator
+    si = objectSources.begin(); si != objectSources.end(); ++si)
+  {
+    std::vector<cmSourceGroup> 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(GetFolderBuildStreams(),
+      &FolderBuildStreams, this->Makefile->GetHomeOutputDirectory(),
+      sgPath, cmGlobalGhsMultiGenerator::GpjType::SUBPROJECT, RelBuildFilePath);
+
+    this->FolderBuildStreams[sgPath] << (*si)->GetFullPath() << std::endl;
+
+    WriteObjectLangOverride(&this->FolderBuildStreams[sgPath], (*si));
+
+    WriteObjectDir(&this->FolderBuildStreams[sgPath],
+      AbsBuildFilePath + sgPath);
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
+  cmGeneratedFileStream *fileStream, cmSourceFile *sourceFile)
+{
+  const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
+  if (nullptr != 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);
+  if (workingDir.size() > 0 && '/' != workingDir.back())
+  {
+    workingDir += "/";
+  }
+  workingDir += "Objs";
+  *fileStream << "    -object_dir=" << workingDir << std::endl;
+}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
new file mode 100644
index 0000000..061a220
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -0,0 +1,74 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2011 Peter Collingbourne <[email protected]>
+  Copyright 2011 Nicolas Despres <[email protected]>
+
+  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.
+============================================================================*/
+#ifndef cmGhsMultiTargetGenerator_h
+#define cmGhsMultiTargetGenerator_h
+
+#include "cmStandardIncludes.h"
+#include "cmTarget.h"
+
+class cmGeneratedFileStream;
+class cmGlobalGhsMultiGenerator;
+class cmLocalGhsMultiGenerator;
+class cmMakefile;
+class cmSourceFile;
+class cmGeneratedFileStream;
+class cmCustomCommand;
+
+class cmGhsMultiTargetGenerator
+{
+public:
+  cmGhsMultiTargetGenerator(cmTarget const* target);
+
+  virtual ~cmGhsMultiTargetGenerator();
+
+  virtual void Generate();
+
+  bool IncludeThisTarget();
+  std::vector<cmSourceFile*> GetSources() const;
+  const char* GetAbsBuildFilePath() const { return AbsBuildFilePath.c_str(); }
+  const char* GetRelBuildFileName() const { return RelBuildFileName.c_str(); }
+  const char* GetAbsBuildFileName() const { return AbsBuildFileName.c_str(); }
+  const char* GetAbsOutputFileName() const { return AbsOutputFileName.c_str(); }
+
+private:
+  cmGlobalGhsMultiGenerator* GetGlobalGenerator() const;
+  cmGeneratedFileStream* GetFolderBuildStreams() { return &(FolderBuildStreams[""]); };
+
+  void WriteTypeSpecifics();
+  void WriteCompilerOptions(const std::string& config);
+  void WriteCompilerFlags();
+  void WriteCompilerDefinitions(const std::string& config);
+  void WriteIncludes(std::string const& config);
+  void WriteTargetLinkLibraries();
+  void WriteCustomCommands();
+  void WriteCustomCommandsHelper(std::vector<cmCustomCommand> const& commandsSet,
+    cmTarget::CustomCommandType commandType);
+  void WriteSources(std::vector<cmSourceFile*> const& objectSources);
+  static void WriteObjectLangOverride(
+    cmGeneratedFileStream *fileStream, cmSourceFile *sourceFile);
+  static void WriteObjectDir(cmGeneratedFileStream *fileStream,
+    std::string const& dir);
+
+  cmTarget const* Target;
+  cmLocalGhsMultiGenerator* LocalGenerator;
+  cmMakefile* Makefile;
+  std::string AbsBuildFilePath;
+  std::string RelBuildFilePath;
+  std::string AbsBuildFileName;
+  std::string RelBuildFileName;
+  std::string RelOutputFileName;
+  std::string AbsOutputFileName;
+  std::map<std::string, cmGeneratedFileStream> FolderBuildStreams;
+};
+
+#endif // ! cmNinjaTargetGenerator_h
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..52dd81f
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -0,0 +1,338 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  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"
+
+const char* cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+
+cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator()
+{
+  this->FindMakeProgramFile = "CMakeGreenHillsFindMake.cmake";
+}
+
+cmLocalGenerator *cmGlobalGhsMultiGenerator::CreateLocalGenerator()
+{
+  cmLocalGenerator* lg =
+    new cmLocalGhsMultiGenerator;
+  lg->SetGlobalGenerator(this);
+  this->SetCurrentLocalGenerator(lg);
+  return lg;
+}
+
+void cmGlobalGhsMultiGenerator
+::GetDocumentation(cmDocumentationEntry& entry)
+{
+  entry.Name = cmGlobalGhsMultiGenerator::GetActualName();
+  entry.Brief = "Generates Green Hills MULTI files (experimental).";
+}
+
+void cmGlobalGhsMultiGenerator
+::EnableLanguage(std::vector<std::string>const& l,
+cmMakefile *mf,
+bool optional)
+{
+  mf->AddDefinition("CMAKE_GENERATOR_CC", "ccarm");
+  mf->AddDefinition("CMAKE_GENERATOR_CXX", "cxarm");
+  mf->AddDefinition("GHSMULTI", "1"); //identifier for user CMake files
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(std::string const& filepath,
+  cmGeneratedFileStream** filestream)
+{
+  // Get a stream where to generate things.
+  if (nullptr == *filestream)
+  {
+    *filestream = new cmGeneratedFileStream(filepath.c_str());
+    if (nullptr != *filestream)
+    {
+      OpenBuildFileStream(*filestream);
+    }
+  }
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(cmGeneratedFileStream* filestream)
+{
+  *filestream << "#!gbuild" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::WriteGpjTag(cmGlobalGhsMultiGenerator::GpjType const gpjType,
+  cmGeneratedFileStream *filestream)
+{
+  char const* tag;
+  switch (gpjType)
+  {
+  case cmGlobalGhsMultiGenerator::INTERGRITY_APPLICATION:
+    tag = "INTEGRITY Application";
+    break;
+  case cmGlobalGhsMultiGenerator::PROJECT:
+    tag = "Project";
+    break;
+  case cmGlobalGhsMultiGenerator::PROGRAM:
+    tag = "Program";
+    break;
+  case cmGlobalGhsMultiGenerator::REFERENCE:
+    tag = "Reference";
+    break;
+  case cmGlobalGhsMultiGenerator::SUBPROJECT:
+    tag = "Subproject";
+    break;
+  default:
+    tag = "";
+  }
+  *filestream << "[" << tag << "]" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream()
+{
+  // Compute GHS MULTI's build file path.
+  std::string buildFilePath =
+    this->GetCMakeInstance()->GetHomeOutputDirectory();
+  buildFilePath += "/";
+  buildFilePath += this->GetCurrentLocalGenerator()->GetMakefile()->GetProjectName();
+  buildFilePath += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+
+  TargetFolderBuildStreams[""].open(buildFilePath.c_str());
+  cmGlobalGhsMultiGenerator::OpenBuildFileStream(GetBuildFileStream());
+
+  char const* osDir =
+    this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR");
+  if (nullptr == osDir)
+  {
+    osDir = "";
+  }
+  else
+  {
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR");
+  }
+  std::string fOSDir(osDir);
+  cmSystemTools::ReplaceString(fOSDir, "\\", "/");
+  char const* bspName =
+    this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+  if (nullptr == bspName)
+  {
+    bspName = "";
+  }
+  else
+  {
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
+  }
+  std::string fBspName(bspName);
+  cmSystemTools::ReplaceString(fBspName, "\\", "/");
+  WriteMacros(fOSDir, fBspName);
+  WriteHighLevelDirectives();
+
+  WriteGpjTag(cmGlobalGhsMultiGenerator::PROJECT, GetBuildFileStream());
+  cmGlobalGhsMultiGenerator::WriteDisclaimer(GetBuildFileStream());
+  *GetBuildFileStream() << "# Top Level Project File" << std::endl;
+  if (fBspName.length() > 0)
+  {
+    *GetBuildFileStream() << "    -bsp " << fBspName << std::endl;
+  }
+  WriteCompilerOptions(fOSDir);
+}
+
+void cmGlobalGhsMultiGenerator::CloseBuildFileStream(cmGeneratedFileStream** filestream)
+{
+  if (filestream)
+  {
+    delete *filestream;
+    *filestream = nullptr;
+  }
+  else
+  {
+    cmSystemTools::Error("Build file stream was not open.");
+  }
+}
+
+void cmGlobalGhsMultiGenerator::Generate()
+{
+  this->OpenBuildFileStream();
+
+  this->cmGlobalGenerator::Generate();
+
+  //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();
+    UpdateBuildFiles(tgts);
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteMacros(std::string const& fOSDir, std::string const& fBspName)
+{
+  *GetBuildFileStream() << "macro __BUILD_DIR=" <<
+    this->GetCMakeInstance()->GetHomeOutputDirectory() << std::endl;;
+  *GetBuildFileStream() << "macro __OS_DIR=" << fOSDir << std::endl;
+  *GetBuildFileStream() << "macro __LIBS_DIR_BASE=" << fOSDir << "/libs" << std::endl;
+  *GetBuildFileStream() << "macro __BSP_NAME=" << fBspName << std::endl;
+  *GetBuildFileStream() << "macro __BSP_DIR=" << fOSDir << "/" << fBspName << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
+{
+  *GetBuildFileStream() << "primaryTarget=arm_integrity.tgt" << std::endl;
+  char const* const customization = this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
+  if (nullptr != customization)
+  {
+    *GetBuildFileStream() << "customization=" << customization << std::endl;
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const& fOSDir)
+{
+  *GetBuildFileStream() << "    -os_dir=$(__OS_DIR)" << std::endl;
+  *GetBuildFileStream() << "    --link_once_templates" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::WriteDisclaimer(std::ostream* os)
+{
+  (*os)
+    << "#" << std::endl
+    << "# CMAKE generated file: DO NOT EDIT!" << std::endl
+    << "# Generated by \"" << cmGlobalGhsMultiGenerator::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,
+  GpjType projType, std::string const& relPath)
+{
+  std::string workingPath(path);
+  cmSystemTools::ConvertToUnixSlashes(workingPath);
+  std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(workingPath);
+  std::string workingRelPath(relPath);
+  if (relPath.size() > 0 && '/' != relPath.back())
+  {
+    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::AddFilesUpToPathNewBuildFile(
+  cmGeneratedFileStream* mainBuildFile,
+  std::map<std::string, cmGeneratedFileStream> *targetFolderBuildStreams,
+  char const *homeOutputDirectory,
+  std::string const& pathUpTo, bool const isFirst, std::string const& relPath,
+  GpjType 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(cmGlobalGhsMultiGenerator::GetFileNameFromPath(pathUpTo));
+  std::string absFilename = absPath + relFilename;
+  (*targetFolderBuildStreams)[pathUpTo].open(absFilename.c_str());
+  cmGlobalGhsMultiGenerator::OpenBuildFileStream(&(*targetFolderBuildStreams)[pathUpTo]);
+  cmGlobalGhsMultiGenerator::WriteGpjTag(projType,
+    &(*targetFolderBuildStreams)[pathUpTo]);
+  cmGlobalGhsMultiGenerator::WriteDisclaimer(&(*targetFolderBuildStreams)[pathUpTo]);
+
+  //Add to main build file
+  if (isFirst)
+  {
+    *mainBuildFile << relFilename << " ";
+    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,
+  GpjType 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 = cmGlobalGhsMultiGenerator::GetFileNameFromPath(nextFilename);
+    (*targetFolderBuildStreams)[pathUpTo] << nextFilename << " ";
+    cmGlobalGhsMultiGenerator::WriteGpjTag(projType,
+      &(*targetFolderBuildStreams)[pathUpTo]);
+  }
+}
+
+std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath(std::string const& path)
+{
+  std::string output(path);
+  if (path.length() > 0)
+  {
+    cmSystemTools::ConvertToUnixSlashes(output);
+    std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(output);
+    output += "/" + splitPath.back() + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+  }
+  return output;
+}
+
+void cmGlobalGhsMultiGenerator::UpdateBuildFiles(cmGeneratorTargetsType const& tgts)
+{
+  for (cmGeneratorTargetsType::const_iterator tgtsI = tgts.begin();
+    tgtsI != tgts.end(); ++tgtsI)
+  {
+    cmGhsMultiTargetGenerator gmtg(tgtsI->first);
+    if (gmtg.GetSources().size() > 0 && gmtg.IncludeThisTarget())
+    {
+      char const* rawFolderName = tgtsI->first->GetProperty("FOLDER");
+      if (nullptr == rawFolderName)
+      {
+        rawFolderName = "";
+      }
+      std::string folderName(rawFolderName);
+      if (TargetFolderBuildStreams.end() == TargetFolderBuildStreams.find(folderName))
+      {
+        AddFilesUpToPath(GetBuildFileStream(), &TargetFolderBuildStreams,
+          this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName,
+          GpjType::PROJECT);
+      }
+      std::vector<cmsys::String> splitPath =
+        cmSystemTools::SplitString(gmtg.GetRelBuildFileName());
+      std::string foldNameRelBuildFile(*(splitPath.end() - 2) +
+        "/" + splitPath.back());
+      TargetFolderBuildStreams[folderName] << foldNameRelBuildFile << " ";
+      WriteGpjTag(GpjType::PROGRAM, &TargetFolderBuildStreams[folderName]);
+    }
+  }
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
new file mode 100644
index 0000000..0e33d87
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -0,0 +1,104 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  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.
+============================================================================*/
+#ifndef cmGhsMultiGenerator_h
+#define cmGhsMultiGenerator_h
+
+#include "cmGlobalGeneratorFactory.h"
+#include "cmGlobalGenerator.h"
+
+class cmGeneratedFileStream;
+
+class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
+{
+public:
+  enum GpjType
+  {
+    INTERGRITY_APPLICATION, PROJECT, PROGRAM, REFERENCE, SUBPROJECT
+  };
+
+  /// The default name of GHS MULTI's build file. Typically: monolith.gpj.
+  static const char* FILE_EXTENSION;
+
+  cmGlobalGhsMultiGenerator();
+
+  static cmGlobalGeneratorFactory* NewFactory() {
+    return new cmGlobalGeneratorSimpleFactory<cmGlobalGhsMultiGenerator>();
+  }
+
+  ///! create the correct local generator
+  virtual cmLocalGenerator *CreateLocalGenerator();
+
+  /// @return the name of this generator.
+  static std::string GetActualName() { return "Green Hills MULTI"; }
+  ///! Get the name for this generator
+  virtual std::string GetName() const { return cmGlobalGhsMultiGenerator::GetActualName(); }
+
+  /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation()
+  static void GetDocumentation(cmDocumentationEntry& entry);
+
+  /**
+  * Try to determine system information such as shared library
+  * extension, pthreads, byte order etc.
+  */
+  virtual void EnableLanguage(std::vector<std::string>const& languages,
+    cmMakefile *, bool optional);
+
+  cmGeneratedFileStream* GetBuildFileStream() {
+    return &(TargetFolderBuildStreams[""]);
+  }
+
+  static void WriteGpjTag(GpjType gpjType, cmGeneratedFileStream *filestream);
+  static void OpenBuildFileStream(std::string const& filepath,
+    cmGeneratedFileStream** filestream);
+  static void OpenBuildFileStream(cmGeneratedFileStream* filestream);
+  static void CloseBuildFileStream(cmGeneratedFileStream **filestream);
+  /// Write the common disclaimer text at the top of each build file.
+  static void WriteDisclaimer(std::ostream* os);
+  std::vector<std::string> GetLibDirs() { return LibDirs; }
+
+  static void AddFilesUpToPath(cmGeneratedFileStream* mainBuildFile,
+    std::map<std::string, cmGeneratedFileStream> *targetFolderBuildStreams,
+    char const *homeOutputDirectory,
+    std::string const& path, GpjType projType,
+    std::string const& relPath = "");
+
+protected:
+  virtual void Generate();
+
+private:
+  void OpenBuildFileStream();
+
+  void WriteMacros(std::string const& fOSDir, std::string const& fBspName);
+  void WriteHighLevelDirectives();
+  void WriteCompilerOptions(std::string const& fOSDir);
+
+  static void AddFilesUpToPathNewBuildFile(cmGeneratedFileStream* mainBuildFile,
+    std::map<std::string, cmGeneratedFileStream> *targetFolderBuildStreams,
+    char const *homeOutputDirectory,
+    std::string const& pathUpTo, bool isFirst, std::string const& relPath,
+    GpjType projType);
+  static void 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,
+    GpjType projType);
+  static std::string GetFileNameFromPath(std::string const& path);
+  void UpdateBuildFiles(cmGeneratorTargetsType const& tgts);
+
+  std::vector<cmGeneratedFileStream*> TargetSubProjects;
+  std::map<std::string, cmGeneratedFileStream> TargetFolderBuildStreams;
+
+  std::vector<std::string> LibDirs;
+};
+
+#endif
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..ce47569
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -0,0 +1,56 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  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 "cmLocalGhsMultiGenerator.h"
+#include "cmGlobalGhsMultiGenerator.h"
+#include "cmGeneratorTarget.h"
+#include "cmMakefile.h"
+#include "cmGhsMultiTargetGenerator.h"
+#include "cmGeneratedFileStream.h"
+
+cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator()
+{
+}
+
+cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
+{
+}
+
+void cmLocalGhsMultiGenerator::Generate()
+{
+  cmGeneratorTargetsType tgts = this->GetMakefile()->GetGeneratorTargets();
+  if (tgts.size() > 0)
+  {
+    for (cmGeneratorTargetsType::iterator l = tgts.begin(); l != tgts.end(); ++l)
+    {
+      cmGhsMultiTargetGenerator tg(l->second->Target);
+      tg.Generate();
+    }
+  }
+}
+
+// Implemented in:
+//   cmLocalGenerator.
+// Used in:
+//   Source/cmMakefile.cxx
+//   Source/cmGlobalGenerator.cxx
+void cmLocalGhsMultiGenerator::Configure()
+{
+  // Compute the path to use when referencing the current output
+  // directory from the top output directory.
+  this->HomeRelativeOutputPath =
+    this->Convert(this->Makefile->GetStartOutputDirectory(), HOME_OUTPUT);
+  if (this->HomeRelativeOutputPath == ".")
+  {
+    this->HomeRelativeOutputPath = "";
+  }
+  this->cmLocalGenerator::Configure();
+}
diff --git a/Source/cmLocalGhsMultiGenerator.h b/Source/cmLocalGhsMultiGenerator.h
new file mode 100644
index 0000000..0b34a3b
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -0,0 +1,56 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+  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.
+============================================================================*/
+#ifndef cmLocalGhsMultiGenerator_h
+#define cmLocalGhsMultiGenerator_h
+
+#include "cmLocalGenerator.h"
+
+class cmGeneratedFileStream;
+
+/** \class cmLocalGhsMultiGenerator
+ * \brief Write Green Hills MULTI project files.
+ *
+ * cmLocalGhsMultiGenerator produces a set of .gpj
+ * file for each target in its mirrored directory.
+ */
+class cmLocalGhsMultiGenerator : public cmLocalGenerator
+{
+public:
+  cmLocalGhsMultiGenerator();
+
+  virtual ~cmLocalGhsMultiGenerator();
+
+  /// @returns the relative path between the HomeOutputDirectory and this
+  /// local generators StartOutputDirectory.
+  std::string GetHomeRelativeOutputPath() const
+  {
+    return this->HomeRelativeOutputPath;
+  }
+
+  /**
+   * Generate the makefile for this directory.
+   */
+  virtual void Generate();
+
+  /// Overloaded methods. @see cmLocalGenerator::Configure()
+  virtual void Configure();
+  const char* GetBuildFileName() { return BuildFileName.c_str(); }
+
+protected:
+  virtual bool CustomCommandUseLocal() const { return true; }
+
+private:
+  std::string BuildFileName;
+  std::string HomeRelativeOutputPath;
+};
+
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 09d270d..1bc265a 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -89,6 +89,8 @@
 # include "cmExtraEclipseCDT4Generator.h"
 #endif
 
+#include "cmGlobalGhsMultiGenerator.h"
+
 #include <stdlib.h> // required for atoi
 
 #if defined( __APPLE__ )
@@ -1854,6 +1856,8 @@ void cmake::AddDefaultGenerators()
     cmGlobalUnixMakefileGenerator3::NewFactory());
   this->Generators.push_back(
     cmGlobalNinjaGenerator::NewFactory());
+  this->Generators.push_back(
+    cmGlobalGhsMultiGenerator::NewFactory());
 #if defined(CMAKE_USE_WMAKE)
   this->Generators.push_back(
     cmGlobalWatcomWMakeGenerator::NewFactory());
-- 
2.1.0

-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers

Reply via email to