On 03/19/2015 09:57 AM, Geoffrey Viola wrote:
> I moved it under
> #if defined(_WIN32) && !defined(__CYGWIN__)
> # if !defined(CMAKE_BOOT_MINGW)

The #include line needs to be moved similarly.  I made that fix and
a few whitespace fixes.  I've attached a patch with those revisions.

I noticed while making those fixes that you're using auto_ptr inside
a map value.  The auto_ptr is documented as not suitable for use
in containers in general.  For TargetFolderBuildStreams you could
just use a normal pointer and then cleanup in the generator
destructor using cmDeleteAll.

Thanks,
-Brad

>From 9ef934f7b3abcd8560197fa16ad6b06eb5708d3b Mon Sep 17 00:00:00 2001
Message-Id: <9ef934f7b3abcd8560197fa16ad6b06eb5708d3b.1427119119.git.brad.k...@kitware.com>
From: Geoff Viola <[email protected]>
Date: Mon, 26 Jan 2015 21:38:27 -0700
Subject: [PATCH] Added-some-support-for-a-Green-Hills-MULTI

---
 Help/generator/Green Hills MULTI.rst         |  11 +
 Help/manual/cmake-generators.7.rst           |   1 +
 Help/manual/cmake-variables.7.rst            |   1 +
 Help/variable/CMAKE_MAKE_PROGRAM.rst         |   2 +
 Help/variable/CMAKE_SYSTEM_PROCESSOR.rst     |   2 +
 Help/variable/GHS-MULTI.rst                  |   4 +
 Modules/Compiler/GHS-DetermineCompiler.cmake |   6 +
 Modules/FindBoost.cmake                      |   5 +-
 Modules/Platform/GHS-MULTI-Initialize.cmake  |  29 ++
 Modules/Platform/GHS-MULTI.cmake             |  27 ++
 Source/CMakeLists.txt                        |   9 +
 Source/cmGhsMultiGpj.cxx                     |  39 +++
 Source/cmGhsMultiGpj.h                       |  31 ++
 Source/cmGhsMultiTargetGenerator.cxx         | 431 ++++++++++++++++++++++++++
 Source/cmGhsMultiTargetGenerator.h           |  92 ++++++
 Source/cmGlobalGhsMultiGenerator.cxx         | 443 +++++++++++++++++++++++++++
 Source/cmGlobalGhsMultiGenerator.h           | 127 ++++++++
 Source/cmGlobalNinjaGenerator.cxx            |   1 +
 Source/cmLocalGhsMultiGenerator.cxx          |  48 +++
 Source/cmLocalGhsMultiGenerator.h            |  54 ++++
 Source/cmake.cxx                             |   3 +
 Tests/CMakeLists.txt                         |  17 +
 Tests/GhsMulti/CMakeLists.txt                |   4 +
 Tests/GhsMulti/ReturnNum/App/CMakeLists.txt  |   4 +
 Tests/GhsMulti/ReturnNum/App/Main.c          |   8 +
 Tests/GhsMulti/ReturnNum/CMakeLists.txt      |   3 +
 Tests/GhsMulti/ReturnNum/Int/AppDD.int       |  12 +
 Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt  |   1 +
 Tests/GhsMulti/ReturnNum/Int/Default.bsp     |  35 +++
 Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt  |   1 +
 Tests/GhsMulti/ReturnNum/Lib/HelperFun.c     |   4 +
 Tests/GhsMulti/ReturnNum/Lib/HelperFun.h     |   1 +
 32 files changed, 1455 insertions(+), 1 deletion(-)
 create mode 100644 Help/generator/Green Hills MULTI.rst
 create mode 100644 Help/variable/GHS-MULTI.rst
 create mode 100644 Modules/Compiler/GHS-DetermineCompiler.cmake
 create mode 100644 Modules/Platform/GHS-MULTI-Initialize.cmake
 create mode 100644 Modules/Platform/GHS-MULTI.cmake
 create mode 100644 Source/cmGhsMultiGpj.cxx
 create mode 100644 Source/cmGhsMultiGpj.h
 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
 create mode 100644 Tests/GhsMulti/CMakeLists.txt
 create mode 100644 Tests/GhsMulti/ReturnNum/App/CMakeLists.txt
 create mode 100644 Tests/GhsMulti/ReturnNum/App/Main.c
 create mode 100644 Tests/GhsMulti/ReturnNum/CMakeLists.txt
 create mode 100644 Tests/GhsMulti/ReturnNum/Int/AppDD.int
 create mode 100644 Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt
 create mode 100644 Tests/GhsMulti/ReturnNum/Int/Default.bsp
 create mode 100644 Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt
 create mode 100644 Tests/GhsMulti/ReturnNum/Lib/HelperFun.c
 create mode 100644 Tests/GhsMulti/ReturnNum/Lib/HelperFun.h

diff --git a/Help/generator/Green Hills MULTI.rst b/Help/generator/Green Hills MULTI.rst
new file mode 100644
index 0000000..79695f1
--- /dev/null
+++ b/Help/generator/Green Hills MULTI.rst	
@@ -0,0 +1,11 @@
+Green Hills MULTI
+-----------------
+
+Generates Green Hills MULTI project files.
+
+Customizations are available through the following cache variables:
+
+* ``GHS_BSP_NAME``
+* ``GHS_CUSTOMIZATION``
+* ``GHS_GPJ_MACROS``
+* ``GHS_OS_DIR``
diff --git a/Help/manual/cmake-generators.7.rst b/Help/manual/cmake-generators.7.rst
index 804229b..ce9f5c8 100644
--- a/Help/manual/cmake-generators.7.rst
+++ b/Help/manual/cmake-generators.7.rst
@@ -56,6 +56,7 @@ one may launch CMake from any environment.
 .. toctree::
    :maxdepth: 1
 
+   /generator/Green Hills MULTI
    /generator/Visual Studio 6
    /generator/Visual Studio 7
    /generator/Visual Studio 7 .NET 2003
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index c342dbe..5282872 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -181,6 +181,7 @@ Variables that Describe the System
    /variable/CMAKE_SYSTEM_VERSION
    /variable/CYGWIN
    /variable/ENV
+   /variable/GHS-MULTI
    /variable/MINGW
    /variable/MSVC10
    /variable/MSVC11
diff --git a/Help/variable/CMAKE_MAKE_PROGRAM.rst b/Help/variable/CMAKE_MAKE_PROGRAM.rst
index f1d88a5..1cc22b5 100644
--- a/Help/variable/CMAKE_MAKE_PROGRAM.rst
+++ b/Help/variable/CMAKE_MAKE_PROGRAM.rst
@@ -8,6 +8,8 @@ name if it is expected to be in the ``PATH``.
 The tool selected depends on the :variable:`CMAKE_GENERATOR` used
 to configure the project:
 
+* The Green Hills MULTI generator sets this to ``GHS-MULTI``
+
 * The Makefile generators set this to ``make``, ``gmake``, or
   a generator-specific tool (e.g. ``nmake`` for "NMake Makefiles").
 
diff --git a/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
index 8ad89f1..2f5313b 100644
--- a/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
+++ b/Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
@@ -6,3 +6,5 @@ The name of the CPU CMake is building for.
 This variable is the same as :variable:`CMAKE_HOST_SYSTEM_PROCESSOR` if
 you build for the host system instead of the target system when
 cross compiling.
+
+* The Green Hills MULTI generator sets this to ``ARM`` by default
diff --git a/Help/variable/GHS-MULTI.rst b/Help/variable/GHS-MULTI.rst
new file mode 100644
index 0000000..0f91be8
--- /dev/null
+++ b/Help/variable/GHS-MULTI.rst
@@ -0,0 +1,4 @@
+GHS-MULTI
+---------
+
+True when using Green Hills MULTI
diff --git a/Modules/Compiler/GHS-DetermineCompiler.cmake b/Modules/Compiler/GHS-DetermineCompiler.cmake
new file mode 100644
index 0000000..56d24e2
--- /dev/null
+++ b/Modules/Compiler/GHS-DetermineCompiler.cmake
@@ -0,0 +1,6 @@
+set(_compiler_id_pp_test "defined(__INTEGRITY)")
+
+set(_compiler_id_version_compute "
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__INTEGRITY_MAJOR_VERSION)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__INTEGRITY_MINOR_VERSION)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__INTEGRITY_PATCH_VERSION)")
diff --git a/Modules/FindBoost.cmake b/Modules/FindBoost.cmake
index 466090b..c844aed 100644
--- a/Modules/FindBoost.cmake
+++ b/Modules/FindBoost.cmake
@@ -405,6 +405,8 @@ function(_Boost_GUESS_COMPILER_PREFIX _ret)
     else()
       set (_boost_COMPILER "-il")
     endif()
+  elseif (GHSMULTI)
+    set(_boost_COMPILER "-ghs")
   elseif (MSVC14)
     set(_boost_COMPILER "-vc140")
   elseif (MSVC12)
@@ -777,7 +779,8 @@ endif()
 # ------------------------------------------------------------------------
 
 set(Boost_LIB_PREFIX "")
-if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN)
+if ( (GHSMULTI AND Boost_USE_STATIC_LIBS) OR
+    (WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) )
   set(Boost_LIB_PREFIX "lib")
 endif()
 
diff --git a/Modules/Platform/GHS-MULTI-Initialize.cmake b/Modules/Platform/GHS-MULTI-Initialize.cmake
new file mode 100644
index 0000000..342ad21
--- /dev/null
+++ b/Modules/Platform/GHS-MULTI-Initialize.cmake
@@ -0,0 +1,29 @@
+
+#=============================================================================
+# Copyright 2015 Geoffrey Viola <[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.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+#Setup Greenhills MULTI specific compilation information
+find_path(GHS_INT_DIRECTORY INTEGRITY.ld PATHS
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\GreenHillsSoftware6433c345;InstallLocation]" #int1122
+  "C:/ghs/int1122"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\GreenHillsSoftware289b6625;InstallLocation]" #int1104
+  "C:/ghs/int1104"
+  DOC "Path to integrity directory"
+  )
+set(GHS_OS_DIR ${GHS_INT_DIRECTORY} CACHE PATH "OS directory")
+set(GHS_PRIMARY_TARGET "arm_integrity.tgt" CACHE STRING "target for compilation")
+set(GHS_BSP_NAME "simarm" CACHE STRING "BSP name")
+set(GHS_CUSTOMIZATION "" CACHE FILEPATH "optional GHS customization")
+mark_as_advanced(GHS_CUSTOMIZATION)
+set(GHS_GPJ_MACROS "" CACHE STRING "optional GHS macros generated in the .gpjs for legacy reasons")
+mark_as_advanced(GHS_GPJ_MACROS)
diff --git a/Modules/Platform/GHS-MULTI.cmake b/Modules/Platform/GHS-MULTI.cmake
new file mode 100644
index 0000000..211cf3e
--- /dev/null
+++ b/Modules/Platform/GHS-MULTI.cmake
@@ -0,0 +1,27 @@
+
+#=============================================================================
+# Copyright 2015 Geoffrey Viola <[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.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# This module is shared by multiple languages; use include blocker.
+
+if(__GHSMULTI)
+  return()
+endif()
+set(__GHSMULTI 1)
+
+set(GHSMULTI 1)
+
+set(CMAKE_FIND_LIBRARY_PREFIXES "")
+set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
+
+include(Platform/WindowsPaths)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 04f6a81..064b827 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -472,6 +472,14 @@ if (WIN32)
       cmVisualStudioSlnParser.cxx
       cmVisualStudioWCEPlatformParser.h
       cmVisualStudioWCEPlatformParser.cxx
+      cmGlobalGhsMultiGenerator.cxx
+      cmGlobalGhsMultiGenerator.h
+      cmLocalGhsMultiGenerator.cxx
+      cmLocalGhsMultiGenerator.h
+      cmGhsMultiTargetGenerator.cxx
+      cmGhsMultiTargetGenerator.h
+      cmGhsMultiGpj.cxx
+      cmGhsMultiGpj.h
       )
   endif()
 endif ()
@@ -499,6 +507,7 @@ set(SRCS ${SRCS}
   cmNinjaUtilityTargetGenerator.cxx
   cmNinjaUtilityTargetGenerator.h
   )
+
 if(WIN32 AND NOT CYGWIN)
   set_source_files_properties(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
   add_executable(cmcldeps cmcldeps.cxx)
diff --git a/Source/cmGhsMultiGpj.cxx b/Source/cmGhsMultiGpj.cxx
new file mode 100644
index 0000000..d630faa
--- /dev/null
+++ b/Source/cmGhsMultiGpj.cxx
@@ -0,0 +1,39 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 "cmGhsMultiGpj.h"
+
+#include "cmGeneratedFileStream.h"
+
+void GhsMultiGpj::WriteGpjTag(Types const gpjType,
+                              cmGeneratedFileStream *const filestream) {
+  char const *tag;
+  switch (gpjType) {
+  case INTERGRITY_APPLICATION:
+    tag = "INTEGRITY Application";
+    break;
+  case PROJECT:
+    tag = "Project";
+    break;
+  case PROGRAM:
+    tag = "Program";
+    break;
+  case REFERENCE:
+    tag = "Reference";
+    break;
+  case SUBPROJECT:
+    tag = "Subproject";
+    break;
+  default:
+    tag = "";
+  }
+  *filestream << "[" << tag << "]" << std::endl;
+}
diff --git a/Source/cmGhsMultiGpj.h b/Source/cmGhsMultiGpj.h
new file mode 100644
index 0000000..225ec47
--- /dev/null
+++ b/Source/cmGhsMultiGpj.h
@@ -0,0 +1,31 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 cmGhsMultiGpj_h
+#define cmGhsMultiGpj_h
+
+class cmGeneratedFileStream;
+
+class GhsMultiGpj {
+public:
+  enum Types {
+    INTERGRITY_APPLICATION,
+    PROJECT,
+    PROGRAM,
+    REFERENCE,
+    SUBPROJECT
+  };
+
+  static void WriteGpjTag(Types const gpjType,
+                          cmGeneratedFileStream *filestream);
+};
+
+#endif // ! cmGhsMultiGpjType_h
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
new file mode 100644
index 0000000..f9b0548
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -0,0 +1,431 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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>
+
+std::string const cmGhsMultiTargetGenerator::DDOption("-dynamic");
+
+cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmTarget const *target)
+    : Target(target), LocalGenerator(static_cast<cmLocalGhsMultiGenerator *>(
+                          target->GetMakefile()->GetLocalGenerator())),
+      Makefile(target->GetMakefile()), TargetGroup(DetermineIfTargetGroup()),
+      DynamicDownload(false) {
+  std::string BuildFileName;
+  BuildFileName = this->Target->GetName();
+  BuildFileName += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+
+  char const *folderProp = this->Target->GetProperty("FOLDER");
+  RelBuildFilePath = NULL == 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());
+    }
+    cmGlobalGhsMultiGenerator::Open(std::string(""), this->AbsBuildFileName,
+                                    &FolderBuildStreams);
+    cmGlobalGhsMultiGenerator::OpenBuildFileStream(GetFolderBuildStreams());
+    std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+    if (0 == config.length()) {
+      config = "RELEASE";
+    }
+    const std::string language(this->Target->GetLinkerLanguage(config));
+    config = cmSystemTools::UpperCase(config);
+    DynamicDownload = DetermineIfDynamicDownload(config, language);
+    if (DynamicDownload) {
+      *this->GetFolderBuildStreams() << "#component integrity_dynamic_download"
+                                     << std::endl;
+    }
+    GhsMultiGpj::WriteGpjTag(GetGpjTag(), this->GetFolderBuildStreams());
+    cmGlobalGhsMultiGenerator::WriteDisclaimer(GetFolderBuildStreams());
+
+    bool const notKernel = IsNotKernel(config, language);
+    WriteTypeSpecifics(config, notKernel);
+    WriteDebugOptions(config, notKernel);
+    WriteCompilerOptions(config, language);
+    WriteCompilerFlags();
+    WriteCompilerDefinitions(config, language);
+    WriteIncludes(config, language);
+    WriteTargetLinkLibraries();
+    WriteCustomCommands();
+    if (DynamicDownload) {
+      *this->GetFolderBuildStreams() << "    " << DDOption << std::endl;
+    }
+
+    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<cmSourceFile *> cmGhsMultiTargetGenerator::GetSources() const {
+  std::vector<cmSourceFile *> output;
+  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  this->Target->GetSourceFiles(output, config);
+  return output;
+}
+
+GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const {
+  GhsMultiGpj::Types output;
+  if (IsTargetGroup()) {
+    output = GhsMultiGpj::Types::INTERGRITY_APPLICATION;
+  } else {
+    output = GhsMultiGpj::Types::PROGRAM;
+  }
+  return output;
+}
+
+cmGlobalGhsMultiGenerator *
+cmGhsMultiTargetGenerator::GetGlobalGenerator() const {
+  return static_cast<cmGlobalGhsMultiGenerator *>(
+      LocalGenerator->GetGlobalGenerator());
+}
+
+void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string &config,
+                                                   bool const notKernel) {
+  std::string outputDir(GetOutputDirectory(config));
+  std::string outputFilename(GetOutputFilename(config));
+
+  if (Target->GetType() == cmTarget::TargetType::STATIC_LIBRARY) {
+    *GetFolderBuildStreams() << "    -relobj" << std::endl;
+    *GetFolderBuildStreams() << "    {optgroup=GhsCommonOptions} -o \""
+                             << outputDir << outputFilename << ".a\""
+                             << std::endl;
+  } else if (Target->GetType() == cmTarget::TargetType::EXECUTABLE) {
+    if (notKernel && !IsTargetGroup()) {
+      *GetFolderBuildStreams() << "    -relprog" << std::endl;
+    }
+    if (IsTargetGroup()) {
+      *GetFolderBuildStreams() << "    -non_shared" << std::endl;
+      *GetFolderBuildStreams() << "    -o \"" << outputDir << outputFilename
+                               << ".elf\"" << std::endl;
+    } else {
+      *GetFolderBuildStreams() << "    {optgroup=GhsCommonOptions} -o \""
+                               << outputDir << outputFilename << ".as\""
+                               << std::endl;
+    }
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteDebugOptions(std::string const &config,
+                                                  bool const notKernel) {
+  if ("DEBUG" == config) {
+    if (notKernel) {
+      *GetFolderBuildStreams() << "    -G" << std::endl;
+      *GetFolderBuildStreams() << "    -Onone" << std::endl;
+    } else {
+      *GetFolderBuildStreams() << "    -ldebug" << std::endl;
+    }
+  } else if (notKernel) {
+    *GetFolderBuildStreams() << "    -O" << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerOptions(
+    std::string const &config, const std::string &language) {
+  std::vector<std::string> options;
+  Target->GetCompileOptions(options, config, language);
+  bool hasStartfileDirProp = false;
+  std::string const startFilePropName("-startfile_dir=");
+  for (std::vector<std::string>::const_iterator options_i = options.begin();
+       options_i != options.end(); ++options_i) {
+    std::string option = *options_i;
+    if (DDOption != option) {
+      if (option.length() >= startFilePropName.length() &&
+          startFilePropName == option.substr(0, startFilePropName.length())) {
+        hasStartfileDirProp = true;
+      }
+      cmSystemTools::ConvertToUnixSlashes(option);
+      *this->GetFolderBuildStreams() << "    " << option << std::endl;
+    }
+  }
+
+  // If this property is relative, make it relative to the root lists file
+  if (!hasStartfileDirProp && GetGlobalGenerator()->IsOSDirRelative()) {
+    *this->GetFolderBuildStreams() << "    " << startFilePropName << "\""
+                                   << this->Makefile->GetHomeOutputDirectory()
+                                   << "/$(__LIBS_DIR_BASE)/$(__BSP_NAME)\""
+                                   << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerFlags() {
+  char const *const compileFlags = Target->GetProperty("COMPILE_FLAGS");
+  if (NULL != compileFlags) {
+    *this->GetFolderBuildStreams() << "    " << compileFlags << std::endl;
+  }
+}
+
+void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
+    const std::string &config, const std::string &language) {
+  std::vector<std::string> compileDefinitions;
+  this->Target->GetCompileDefinitions(compileDefinitions, config, language);
+  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,
+                                              const std::string &language) {
+  std::vector<std::string> includes =
+      Target->GetIncludeDirectories(config, language);
+  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 (NULL != 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,
+        GhsMultiGpj::Types::SUBPROJECT, RelBuildFilePath);
+
+    if ((*si)->GetExtension() == ".int") {
+      *this->FolderBuildStreams[sgPath] << "\"" << (*si)->GetFullPath() << "\""
+                                        << std::endl;
+    } else {
+      *this->FolderBuildStreams[sgPath] << (*si)->GetFullPath() << std::endl;
+    }
+
+    if ("ld" != (*si)->GetExtension() && "int" != (*si)->GetExtension() &&
+        "bsp" != (*si)->GetExtension()) {
+      WriteObjectLangOverride(this->FolderBuildStreams[sgPath].get(), (*si));
+
+      WriteObjectDir(this->FolderBuildStreams[sgPath].get(),
+                     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);
+  if (workingDir.size() > 0 && '/' != workingDir.back()) {
+    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 =
+      Target->GetProperty("RUNTIME_OUTPUT_DIRECTORY");
+  if (NULL != runtimeOutputProp) {
+    outputDir = runtimeOutputProp;
+  }
+
+  std::string configCapped(cmSystemTools::UpperCase(config));
+  const char *runtimeOutputSProp =
+      Target->GetProperty("RUNTIME_OUTPUT_DIRECTORY_" + configCapped);
+  if (NULL != runtimeOutputSProp) {
+    outputDir = runtimeOutputSProp;
+  }
+  cmSystemTools::ConvertToUnixSlashes(outputDir);
+
+  if (outputDir.length() > 0 && ('/' != (*outputDir.rbegin()))) {
+    outputDir += "/";
+  }
+
+  return outputDir;
+}
+
+std::string
+cmGhsMultiTargetGenerator::GetOutputFilename(const std::string &config) const {
+  std::string outputFilename(Target->GetName());
+
+  const char *outputNameProp = Target->GetProperty("OUTPUT_NAME");
+  if (NULL != outputNameProp) {
+    outputFilename = outputNameProp;
+  }
+
+  std::string configCapped(cmSystemTools::UpperCase(config));
+  const char *outputNameSProp =
+      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<std::string> options;
+  Target->GetCompileOptions(options, config, language);
+  output =
+      options.end() == std::find(options.begin(), options.end(), "-kernel");
+  return output;
+}
+
+bool cmGhsMultiTargetGenerator::DetermineIfTargetGroup() {
+  bool output = false;
+  std::vector<cmSourceFile *> sources = GetSources();
+  for (std::vector<cmSourceFile *>::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<std::string> options;
+  bool output = false;
+  Target->GetCompileOptions(options, config, language);
+  for (std::vector<std::string>::const_iterator options_i = options.begin();
+       options_i != options.end(); ++options_i) {
+    std::string option = *options_i;
+    if (DDOption == option) {
+      output = true;
+    }
+  }
+  return output;
+}
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
new file mode 100644
index 0000000..3f53a58
--- /dev/null
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -0,0 +1,92 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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"
+#include "cmGhsMultiGpj.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;
+  GhsMultiGpj::Types GetGpjTag() 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[""].get();
+  };
+  bool IsTargetGroup() const { return TargetGroup; }
+
+  void WriteTypeSpecifics(const std::string &config, bool notKernel);
+  void WriteDebugOptions(std::string const &config, bool notKernel);
+  void WriteCompilerOptions(const std::string &config,
+                            const std::string &language);
+  void WriteCompilerFlags();
+  void WriteCompilerDefinitions(const std::string &config,
+                                const std::string &language);
+  void WriteIncludes(const std::string &config, const std::string &language);
+  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);
+  std::string GetOutputDirectory(const std::string &config) const;
+  std::string GetOutputFilename(const std::string &config) const;
+
+  bool IsNotKernel(std::string const &config, const std::string &language);
+  bool DetermineIfTargetGroup();
+  bool DetermineIfDynamicDownload(std::string const &config,
+                                  const std::string &language);
+
+  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, cmsys::auto_ptr<cmGeneratedFileStream>>
+      FolderBuildStreams;
+  bool TargetGroup;
+  bool DynamicDownload;
+  static std::string const DDOption;
+};
+
+#endif // ! cmGhsMultiTargetGenerator_h
diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..4312e23
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.cxx
@@ -0,0 +1,443 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 "cmGlobalGhsMultiGenerator.h"
+#include "cmLocalGhsMultiGenerator.h"
+#include "cmMakefile.h"
+#include "cmVersion.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGhsMultiTargetGenerator.h"
+#include <cmsys/SystemTools.hxx>
+
+const char *cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+
+cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator() : OSDirRelative(false) {
+  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 = 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_SYSTEM_NAME", "GHS-MULTI");
+  mf->AddDefinition("CMAKE_SYSTEM_PROCESSOR", "ARM");
+
+  const std::string ghsCompRoot(GetCompRoot());
+  mf->AddDefinition("GHS_COMP_ROOT", ghsCompRoot.c_str());
+  std::string ghsCompRootStart =
+      0 == ghsCompRootStart.size() ? "" : ghsCompRoot + "/";
+  mf->AddDefinition("CMAKE_C_COMPILER",
+                    std::string(ghsCompRootStart + "ccarm.exe").c_str());
+  mf->AddDefinition("CMAKE_C_COMPILER_ID_RUN", "TRUE");
+  mf->AddDefinition("CMAKE_C_COMPILER_ID", "GHSC");
+  mf->AddDefinition("CMAKE_C_COMPILER_FORCED", "TRUE");
+
+  mf->AddDefinition("CMAKE_CXX_COMPILER",
+                    std::string(ghsCompRootStart + "cxarm.exe").c_str());
+  mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE");
+  mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHSCXX");
+  mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
+
+  if (ghsCompRoot.length() > 0) {
+    static const char *compPreFix = "comp_";
+    std::string compFilename =
+        cmsys::SystemTools::FindLastString(ghsCompRoot.c_str(), compPreFix);
+    cmsys::SystemTools::ReplaceString(compFilename, compPreFix, "");
+    mf->AddDefinition("CMAKE_SYSTEM_VERSION", compFilename.c_str());
+  }
+
+  mf->AddDefinition("GHSMULTI", "1"); // identifier for user CMake files
+  this->cmGlobalGenerator::EnableLanguage(l, mf, optional);
+}
+
+void cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile *mf) {
+  // The GHS generator knows how to lookup its build tool
+  // directly instead of needing a helper module to do it, so we
+  // do not actually need to put CMAKE_MAKE_PROGRAM into the cache.
+  if (cmSystemTools::IsOff(mf->GetDefinition("CMAKE_MAKE_PROGRAM"))) {
+    mf->AddDefinition("CMAKE_MAKE_PROGRAM", this->GetGhsBuildCommand().c_str());
+  }
+}
+
+std::string const &cmGlobalGhsMultiGenerator::GetGhsBuildCommand() {
+  if (!this->GhsBuildCommandInitialized) {
+    this->GhsBuildCommandInitialized = true;
+    this->GhsBuildCommand = this->FindGhsBuildCommand();
+  }
+  return this->GhsBuildCommand;
+}
+
+std::string cmGlobalGhsMultiGenerator::FindGhsBuildCommand() {
+  std::string makeProgram = cmSystemTools::FindProgram("gbuild");
+  if (makeProgram.empty()) {
+    makeProgram = "gbuild";
+  }
+  return makeProgram;
+}
+
+std::string cmGlobalGhsMultiGenerator::GetCompRoot() {
+  std::string output;
+
+  const std::vector<std::string> potentialDirsHardPaths(GetCompRootHardPaths());
+  const std::vector<std::string> potentialDirsRegistry(GetCompRootRegistry());
+
+  std::vector<std::string> potentialDirsComplete;
+  potentialDirsComplete.insert(potentialDirsComplete.end(),
+                               potentialDirsHardPaths.begin(),
+                               potentialDirsHardPaths.end());
+  potentialDirsComplete.insert(potentialDirsComplete.end(),
+                               potentialDirsRegistry.begin(),
+                               potentialDirsRegistry.end());
+
+  // Use latest version
+  std::string outputDirName;
+  for (std::vector<std::string>::const_iterator potentialDirsCompleteIt =
+           potentialDirsComplete.begin();
+       potentialDirsCompleteIt != potentialDirsComplete.end();
+       ++potentialDirsCompleteIt) {
+    const std::string dirName(
+        cmsys::SystemTools::GetFilenameName(*potentialDirsCompleteIt));
+    if (dirName.compare(outputDirName) > 0) {
+      output = *potentialDirsCompleteIt;
+      outputDirName = dirName;
+    }
+  }
+
+  return output;
+}
+
+std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootHardPaths() {
+  std::vector<std::string> output;
+  cmSystemTools::Glob("C:/ghs", "comp_[^;]+", output);
+  for (std::vector<std::string>::iterator outputIt = output.begin();
+       outputIt != output.end(); ++outputIt) {
+    *outputIt = "C:/ghs/" + *outputIt;
+  }
+  return output;
+}
+
+std::vector<std::string> cmGlobalGhsMultiGenerator::GetCompRootRegistry() {
+  std::vector<std::string> output(2);
+  cmsys::SystemTools::ReadRegistryValue(
+      "HKEY_LOCAL_"
+      "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Unin"
+      "stall\\"
+      "GreenHillsSoftwared771f1b4;InstallLocation",
+      output[0]);
+  cmsys::SystemTools::ReadRegistryValue(
+      "HKEY_LOCAL_"
+      "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Unin"
+      "stall\\"
+      "GreenHillsSoftware9881cef6;InstallLocation",
+      output[1]);
+  return output;
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+    std::string const &filepath, cmGeneratedFileStream **filestream) {
+  // Get a stream where to generate things.
+  if (NULL == *filestream) {
+    *filestream = new cmGeneratedFileStream(filepath.c_str());
+    if (NULL != *filestream) {
+      OpenBuildFileStream(*filestream);
+    }
+  }
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+    cmGeneratedFileStream *filestream) {
+  *filestream << "#!gbuild" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
+    cmMakefile *const makefile) {
+  // Compute GHS MULTI's build file path.
+  std::string buildFilePath =
+      this->GetCMakeInstance()->GetHomeOutputDirectory();
+  buildFilePath += "/";
+  buildFilePath += "default";
+  buildFilePath += FILE_EXTENSION;
+
+  Open(std::string(""), buildFilePath, &TargetFolderBuildStreams);
+  OpenBuildFileStream(GetBuildFileStream());
+
+  char const *osDir =
+      this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR");
+  if (NULL == osDir) {
+    osDir = "";
+    cmSystemTools::Error("GHS_OS_DIR cache variable must be set");
+  } else {
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_OS_DIR");
+  }
+  std::string fOSDir(trimQuotes(osDir));
+  cmSystemTools::ReplaceString(fOSDir, "\\", "/");
+  if (fOSDir.length() > 0 && ('c' == fOSDir[0] || 'C' == fOSDir[0])) {
+    OSDirRelative = false;
+  } else {
+    OSDirRelative = true;
+  }
+
+  char const *bspName =
+      this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
+  if (NULL == bspName) {
+    bspName = "";
+    cmSystemTools::Error("GHS_BSP_NAME cache variable must be set");
+  } else {
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
+  }
+  std::string fBspName(trimQuotes(bspName));
+  cmSystemTools::ReplaceString(fBspName, "\\", "/");
+  WriteMacros();
+  WriteHighLevelDirectives();
+
+  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::Types::PROJECT, GetBuildFileStream());
+  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 = NULL;
+  } else {
+    cmSystemTools::Error("Build file stream was not open.");
+  }
+}
+
+void cmGlobalGhsMultiGenerator::Generate() {
+  this->cmGlobalGenerator::Generate();
+
+  if (this->LocalGenerators.size() > 0) {
+    cmLocalGenerator *sampLG = this->LocalGenerators[0];
+    this->OpenBuildFileStream(sampLG->GetMakefile());
+
+    // 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::GenerateBuildCommand(
+    std::vector<std::string> &makeCommand, const std::string &makeProgram,
+    const std::string & /*projectName*/, const std::string & /*projectDir*/,
+    const std::string &targetName, const std::string & /*config*/,
+    bool /*fast*/, bool /*verbose*/,
+    std::vector<std::string> const &makeOptions) {
+  makeCommand.push_back(this->SelectMakeProgram(makeProgram));
+
+  makeCommand.insert(makeCommand.end(), makeOptions.begin(), makeOptions.end());
+  if (!targetName.empty()) {
+    if (targetName == "clean") {
+      makeCommand.push_back("-clean");
+    } else {
+      makeCommand.push_back(targetName);
+    }
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteMacros() {
+  char const *ghsGpjMacros =
+      this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
+  if (NULL != ghsGpjMacros) {
+    std::vector<std::string> expandedList;
+    cmSystemTools::ExpandListArgument(std::string(ghsGpjMacros), expandedList);
+    for (std::vector<std::string>::const_iterator expandedListI =
+             expandedList.begin();
+         expandedListI != expandedList.end(); ++expandedListI) {
+      *GetBuildFileStream() << "macro " << *expandedListI << std::endl;
+    }
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives() {
+  *GetBuildFileStream() << "primaryTarget=arm_integrity.tgt" << std::endl;
+  char const *const customization =
+      this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
+  if (NULL != customization && strlen(customization) > 0) {
+    *GetBuildFileStream() << "customization=" << trimQuotes(customization)
+                          << std::endl;
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
+  }
+}
+
+void cmGlobalGhsMultiGenerator::WriteCompilerOptions(
+    std::string const &fOSDir) {
+  *GetBuildFileStream() << "    -os_dir=\"" << fOSDir << "\"" << 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 \"" << GetActualName() << "\""
+        << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+        << cmVersion::GetMinorVersion() << std::endl
+        << "#" << std::endl;
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPath(
+    cmGeneratedFileStream *mainBuildFile,
+    std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *
+        targetFolderBuildStreams,
+    char const *homeOutputDirectory, std::string const &path,
+    GhsMultiGpj::Types 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::Open(
+    std::string const &mapKeyName, std::string const &fileName,
+    std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *fileMap) {
+  if (fileMap->end() == fileMap->find(fileName)) {
+    cmsys::auto_ptr<cmGeneratedFileStream> temp(new cmGeneratedFileStream);
+    temp->open(fileName.c_str());
+    (*fileMap)[mapKeyName] = temp;
+  }
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPathNewBuildFile(
+    cmGeneratedFileStream *mainBuildFile,
+    std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *
+        targetFolderBuildStreams,
+    char const *homeOutputDirectory, std::string const &pathUpTo,
+    bool const isFirst, std::string const &relPath,
+    GhsMultiGpj::Types const projType) {
+  // create folders up to file path
+  std::string absPath = std::string(homeOutputDirectory) + "/" + relPath;
+  std::string newPath = absPath + pathUpTo;
+  if (!cmSystemTools::FileExists(newPath.c_str())) {
+    cmSystemTools::MakeDirectory(newPath.c_str());
+  }
+
+  // Write out to filename for first time
+  std::string relFilename(GetFileNameFromPath(pathUpTo));
+  std::string absFilename = absPath + relFilename;
+  Open(pathUpTo, absFilename, targetFolderBuildStreams);
+  OpenBuildFileStream((*targetFolderBuildStreams)[pathUpTo].get());
+  GhsMultiGpj::WriteGpjTag(projType,
+                           (*targetFolderBuildStreams)[pathUpTo].get());
+  WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo].get());
+
+  // Add to main build file
+  if (isFirst) {
+    *mainBuildFile << relFilename << " ";
+    GhsMultiGpj::WriteGpjTag(projType, mainBuildFile);
+  }
+}
+
+void cmGlobalGhsMultiGenerator::AddFilesUpToPathAppendNextFile(
+    std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *
+        targetFolderBuildStreams,
+    std::string const &pathUpTo,
+    std::vector<cmsys::String>::const_iterator splitPathI,
+    std::vector<cmsys::String>::const_iterator end,
+    GhsMultiGpj::Types 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 = GetFileNameFromPath(nextFilename);
+    *(*targetFolderBuildStreams)[pathUpTo] << nextFilename << " ";
+    GhsMultiGpj::WriteGpjTag(projType,
+                             (*targetFolderBuildStreams)[pathUpTo].get());
+  }
+}
+
+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() + 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 (NULL == rawFolderName) {
+        rawFolderName = "";
+      }
+      std::string folderName(rawFolderName);
+      if (TargetFolderBuildStreams.end() ==
+          TargetFolderBuildStreams.find(folderName)) {
+        AddFilesUpToPath(GetBuildFileStream(), &TargetFolderBuildStreams,
+                         this->GetCMakeInstance()->GetHomeOutputDirectory(),
+                         folderName, GhsMultiGpj::Types::PROJECT);
+      }
+      std::vector<cmsys::String> splitPath =
+          cmSystemTools::SplitString(gmtg.GetRelBuildFileName());
+      std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" +
+                                       splitPath.back());
+      *TargetFolderBuildStreams[folderName] << foldNameRelBuildFile << " ";
+      GhsMultiGpj::WriteGpjTag(gmtg.GetGpjTag(),
+                               TargetFolderBuildStreams[folderName].get());
+    }
+  }
+}
+
+std::string cmGlobalGhsMultiGenerator::trimQuotes(std::string const &str) {
+  std::string result;
+  result.reserve(str.size());
+  for (const char *ch = str.c_str(); *ch != '\0'; ++ch) {
+    if (*ch != '"') {
+      result += *ch;
+    }
+  }
+  return result;
+}
diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h
new file mode 100644
index 0000000..cf699ae
--- /dev/null
+++ b/Source/cmGlobalGhsMultiGenerator.h
@@ -0,0 +1,127 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 cmGhsMultiGenerator_h
+#define cmGhsMultiGenerator_h
+
+#include "cmGlobalGeneratorFactory.h"
+#include "cmGlobalGenerator.h"
+#include "cmGhsMultiGpj.h"
+
+class cmGeneratedFileStream;
+
+class cmGlobalGhsMultiGenerator : public cmGlobalGenerator {
+public:
+  /// 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 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);
+  /*
+  * Determine what program to use for building the project.
+  */
+  virtual void FindMakeProgram(cmMakefile *);
+
+  cmGeneratedFileStream *GetBuildFileStream() {
+    return TargetFolderBuildStreams[""].get();
+  }
+
+  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, cmsys::auto_ptr<cmGeneratedFileStream>> *
+          targetFolderBuildStreams,
+      char const *homeOutputDirectory, std::string const &path,
+      GhsMultiGpj::Types projType, std::string const &relPath = "");
+  static void
+  Open(std::string const &mapKeyName, std::string const &fileName,
+       std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *fileMap);
+
+  static std::string trimQuotes(std::string const &str);
+  inline bool IsOSDirRelative() { return OSDirRelative; }
+
+protected:
+  virtual void Generate();
+  virtual void GenerateBuildCommand(
+      std::vector<std::string> &makeCommand, const std::string &makeProgram,
+      const std::string &projectName, const std::string &projectDir,
+      const std::string &targetName, const std::string &config, bool fast,
+      bool verbose,
+      std::vector<std::string> const &makeOptions = std::vector<std::string>());
+
+private:
+  std::string const &GetGhsBuildCommand();
+  std::string FindGhsBuildCommand();
+  std::string GetCompRoot();
+  std::vector<std::string> GetCompRootHardPaths();
+  std::vector<std::string> GetCompRootRegistry();
+  void OpenBuildFileStream(cmMakefile *makefile);
+
+  void WriteMacros();
+  void WriteHighLevelDirectives();
+  void WriteCompilerOptions(std::string const &fOSDir);
+
+  static void AddFilesUpToPathNewBuildFile(
+      cmGeneratedFileStream *mainBuildFile,
+      std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *
+          targetFolderBuildStreams,
+      char const *homeOutputDirectory, std::string const &pathUpTo,
+      bool isFirst, std::string const &relPath, GhsMultiGpj::Types projType);
+  static void AddFilesUpToPathAppendNextFile(
+      std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>> *
+          targetFolderBuildStreams,
+      std::string const &pathUpTo,
+      std::vector<cmsys::String>::const_iterator splitPathI,
+      std::vector<cmsys::String>::const_iterator end,
+      GhsMultiGpj::Types projType);
+  static std::string GetFileNameFromPath(std::string const &path);
+  void UpdateBuildFiles(cmGeneratorTargetsType const &tgts);
+
+  std::vector<cmGeneratedFileStream *> TargetSubProjects;
+  std::map<std::string, cmsys::auto_ptr<cmGeneratedFileStream>>
+      TargetFolderBuildStreams;
+
+  std::vector<std::string> LibDirs;
+
+  bool OSDirRelative;
+  bool GhsBuildCommandInitialized;
+  std::string GhsBuildCommand;
+};
+
+#endif
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index f74f1e0..2ade825 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -576,6 +576,7 @@ bool cmGlobalNinjaGenerator::UsingMinGW = false;
 
 // Implemented by:
 //   cmGlobalUnixMakefileGenerator3
+//   cmGlobalGhsMultiGenerator
 //   cmGlobalVisualStudio10Generator
 //   cmGlobalVisualStudio6Generator
 //   cmGlobalVisualStudio7Generator
diff --git a/Source/cmLocalGhsMultiGenerator.cxx b/Source/cmLocalGhsMultiGenerator.cxx
new file mode 100644
index 0000000..b700143
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.cxx
@@ -0,0 +1,48 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 "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..c97b03f
--- /dev/null
+++ b/Source/cmLocalGhsMultiGenerator.h
@@ -0,0 +1,54 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2015 Geoffrey Viola <[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 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 51df7f2..631397b 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -63,6 +63,7 @@
 #    include "cmGlobalBorlandMakefileGenerator.h"
 #    include "cmGlobalNMakeMakefileGenerator.h"
 #    include "cmGlobalJOMMakefileGenerator.h"
+#    include "cmGlobalGhsMultiGenerator.h"
 #    define CMAKE_HAVE_VS_GENERATORS
 #  endif
 #  include "cmGlobalMSYSMakefileGenerator.h"
@@ -1841,6 +1842,8 @@ void cmake::AddDefaultGenerators()
     cmGlobalNMakeMakefileGenerator::NewFactory());
   this->Generators.push_back(
     cmGlobalJOMMakefileGenerator::NewFactory());
+  this->Generators.push_back(
+    cmGlobalGhsMultiGenerator::NewFactory());
 # endif
   this->Generators.push_back(
     cmGlobalMSYSMakefileGenerator::NewFactory());
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 49fd02b..87727c7 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -1938,6 +1938,23 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     endif()
   endif()
 
+  if (CMake_TEST_GreenHillsMULTI)
+    macro(add_test_GhsMulti name primaryTarget bspName)
+      add_test(NAME GhsMulti.${name} COMMAND ${CMAKE_CTEST_COMMAND}
+        --build-and-test
+        "${CMake_SOURCE_DIR}/Tests/GhsMulti"
+        "${CMake_BINARY_DIR}/Tests/GhsMulti/${name}"
+        --build-generator "Green Hills MULTI"
+        --build-project ReturnNum
+        --build-config $<CONFIGURATION>
+        --build-options -DGHS_PRIMARY_TARGET=${primaryTarget}
+        -DGHS_BSP_NAME=${bspName}
+        )
+    endmacro ()
+    add_test_GhsMulti("arm_integrity_simarm" "arm_integrity.tgt" "simarm")
+    add_test_GhsMulti("arm64_integrity_simarm" "arm64_integrity.tgt" "simarm")
+  endif ()
+
   if(tegra AND NOT "${CMake_SOURCE_DIR};${CMake_BINARY_DIR}" MATCHES " ")
     macro(add_test_VSNsightTegra name generator)
       add_test(NAME VSNsightTegra.${name} COMMAND ${CMAKE_CTEST_COMMAND}
diff --git a/Tests/GhsMulti/CMakeLists.txt b/Tests/GhsMulti/CMakeLists.txt
new file mode 100644
index 0000000..6e15ba9
--- /dev/null
+++ b/Tests/GhsMulti/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(ReturnNum)
+
+add_subdirectory(ReturnNum)
diff --git a/Tests/GhsMulti/ReturnNum/App/CMakeLists.txt b/Tests/GhsMulti/ReturnNum/App/CMakeLists.txt
new file mode 100644
index 0000000..2adbd4e
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/App/CMakeLists.txt
@@ -0,0 +1,4 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
+add_executable(App Main.c)
+target_link_libraries(App Lib)
+target_compile_options(App PUBLIC "-non_shared")
diff --git a/Tests/GhsMulti/ReturnNum/App/Main.c b/Tests/GhsMulti/ReturnNum/App/Main.c
new file mode 100644
index 0000000..1133834
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/App/Main.c
@@ -0,0 +1,8 @@
+#include "HelperFun.h"
+
+int main(int argc, const char* argv[])
+{
+    int out;
+    out = giveNum();
+    return out;
+}
diff --git a/Tests/GhsMulti/ReturnNum/CMakeLists.txt b/Tests/GhsMulti/ReturnNum/CMakeLists.txt
new file mode 100644
index 0000000..7bcc5f9
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory(App)
+add_subdirectory(Int)
+add_subdirectory(Lib)
diff --git a/Tests/GhsMulti/ReturnNum/Int/AppDD.int b/Tests/GhsMulti/ReturnNum/Int/AppDD.int
new file mode 100644
index 0000000..9e22b5e
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Int/AppDD.int
@@ -0,0 +1,12 @@
+# Input File for the Integrate utility for use with the INTEGRITY real-time
+#  operating system by Green Hills Software.
+# Before editing this file, refer to the Integrate Reference Manual.
+
+Kernel
+    Filename    DynamicDownload
+EndKernel
+
+AddressSpace        App
+  Filename      "App/App.as"
+  Language C
+EndAddressSpace
diff --git a/Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt b/Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt
new file mode 100644
index 0000000..44c5de1
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt
@@ -0,0 +1 @@
+add_executable(AppDD AppDD.int Default.bsp)
diff --git a/Tests/GhsMulti/ReturnNum/Int/Default.bsp b/Tests/GhsMulti/ReturnNum/Int/Default.bsp
new file mode 100644
index 0000000..224ec29
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Int/Default.bsp
@@ -0,0 +1,35 @@
+# Target description File for the Integrate utility for use with the
+# INTEGRITY real-time operating system by Green Hills Software.
+# Before editing this file, refer to your Integrate documentation.
+# default.bsp is appropriate for INTEGRITY applications which are
+# fully linked with the kernel (for RAM or ROM) or dynamically downloaded.
+#
+# MinimumAddress must match the value of .ramend in the linker directives
+# file used for the KernelSpace program - see default.ld for more info.
+# The MaximumAddress used here allows memory mappings to be specified
+# for up to the 16 MB mark in RAM.   Intex will not permit programs
+# that require more memory for its mappings.    If the board has less
+# memory,  this number can be reduced by the user.
+
+Target
+	MinimumAddress				.ramend
+	MaximumAddress				.ramlimit
+	Clock					StandardTick
+	EndClock
+        Clock                                   HighResTimer
+        EndClock
+	IODevice				"SerialDev0"
+	InitialKernelObjects 			200
+	DefaultStartIt				false
+	DefaultMaxPriority			255
+	DefaultPriority				127
+	DefaultWeight				1
+	DefaultMaxWeight			255
+	DefaultHeapSize				0x10000
+	LastVirtualAddress			0x3fffffff
+	PageSize				0x1000
+	ArchitectedPageSize			0x1000
+	ArchitectedPageSize			0x10000
+	ArchitectedPageSize			0x100000
+	DefaultMemoryRegionSize			0x20000
+EndTarget
diff --git a/Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt b/Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt
new file mode 100644
index 0000000..9c822da
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt
@@ -0,0 +1 @@
+add_library(Lib HelperFun.c HelperFun.h)
\ No newline at end of file
diff --git a/Tests/GhsMulti/ReturnNum/Lib/HelperFun.c b/Tests/GhsMulti/ReturnNum/Lib/HelperFun.c
new file mode 100644
index 0000000..d7515d7
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Lib/HelperFun.c
@@ -0,0 +1,4 @@
+int giveNum(void)
+{
+    return 1;
+}
diff --git a/Tests/GhsMulti/ReturnNum/Lib/HelperFun.h b/Tests/GhsMulti/ReturnNum/Lib/HelperFun.h
new file mode 100644
index 0000000..00971b0
--- /dev/null
+++ b/Tests/GhsMulti/ReturnNum/Lib/HelperFun.h
@@ -0,0 +1 @@
+int giveNum(void);
-- 
2.1.4

-- 

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