Browse Source

Merge topic 'add-GreenHills-MULTI-generator'

66b641f4 Help: Add notes for topic 'add-GreenHills-MULTI-generator'
48004d9d Add a 'Green Hills MULTI' generator on Windows
051d8be1 cmLocalGenerator: Constify some cmTarget and cmGeneratorTarget arguments
Brad King 10 years ago
parent
commit
5e0e65c189
41 changed files with 1889 additions and 11 deletions
  1. 16 0
      Help/generator/Green Hills MULTI.rst
  2. 1 0
      Help/manual/cmake-generators.7.rst
  3. 5 0
      Help/manual/cmake-variables.7.rst
  4. 8 0
      Help/release/dev/add-GreenHills-MULTI-generator.rst
  5. 6 0
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst
  6. 7 0
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst
  7. 6 0
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst
  8. 7 0
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst
  9. 4 0
      Help/variable/CMAKE_MAKE_PROGRAM.rst
  10. 2 0
      Help/variable/CMAKE_SYSTEM_PROCESSOR.rst
  11. 4 0
      Help/variable/GHS-MULTI.rst
  12. 27 0
      Modules/Compiler/GHS-C.cmake
  13. 31 0
      Modules/Compiler/GHS-CXX.cmake
  14. 6 0
      Modules/Compiler/GHS-DetermineCompiler.cmake
  15. 4 1
      Modules/FindBoost.cmake
  16. 29 0
      Modules/Platform/GHS-MULTI-Initialize.cmake
  17. 27 0
      Modules/Platform/GHS-MULTI.cmake
  18. 9 0
      Source/CMakeLists.txt
  19. 44 0
      Source/cmGhsMultiGpj.cxx
  20. 34 0
      Source/cmGhsMultiGpj.h
  21. 600 0
      Source/cmGhsMultiTargetGenerator.cxx
  22. 119 0
      Source/cmGhsMultiTargetGenerator.h
  23. 548 0
      Source/cmGlobalGhsMultiGenerator.cxx
  24. 127 0
      Source/cmGlobalGhsMultiGenerator.h
  25. 1 0
      Source/cmGlobalNinjaGenerator.cxx
  26. 8 6
      Source/cmLocalGenerator.cxx
  27. 5 4
      Source/cmLocalGenerator.h
  28. 55 0
      Source/cmLocalGhsMultiGenerator.cxx
  29. 56 0
      Source/cmLocalGhsMultiGenerator.h
  30. 3 0
      Source/cmake.cxx
  31. 17 0
      Tests/CMakeLists.txt
  32. 4 0
      Tests/GhsMulti/CMakeLists.txt
  33. 4 0
      Tests/GhsMulti/ReturnNum/App/CMakeLists.txt
  34. 8 0
      Tests/GhsMulti/ReturnNum/App/Main.c
  35. 3 0
      Tests/GhsMulti/ReturnNum/CMakeLists.txt
  36. 12 0
      Tests/GhsMulti/ReturnNum/Int/AppDD.int
  37. 1 0
      Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt
  38. 35 0
      Tests/GhsMulti/ReturnNum/Int/Default.bsp
  39. 1 0
      Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt
  40. 4 0
      Tests/GhsMulti/ReturnNum/Lib/HelperFun.c
  41. 1 0
      Tests/GhsMulti/ReturnNum/Lib/HelperFun.h

+ 16 - 0
Help/generator/Green Hills MULTI.rst

@@ -0,0 +1,16 @@
+Green Hills MULTI
+-----------------
+
+Generates Green Hills MULTI project files (experimental, work-in-progress).
+
+Customizations are available through the following cache variables:
+
+* ``GHS_BSP_NAME``
+* ``GHS_CUSTOMIZATION``
+* ``GHS_GPJ_MACROS``
+* ``GHS_OS_DIR``
+
+.. note::
+  This generator is deemed experimental as of CMake |release|
+  and is still a work in progress.  Future versions of CMake
+  may make breaking changes as the generator matures.

+ 1 - 0
Help/manual/cmake-generators.7.rst

@@ -73,6 +73,7 @@ Visual Studio Generators
 .. toctree::
    :maxdepth: 1
 
+   /generator/Green Hills MULTI
    /generator/Visual Studio 6
    /generator/Visual Studio 7
    /generator/Visual Studio 7 .NET 2003

+ 5 - 0
Help/manual/cmake-variables.7.rst

@@ -182,6 +182,7 @@ Variables that Describe the System
    /variable/CMAKE_SYSTEM_VERSION
    /variable/CYGWIN
    /variable/ENV
+   /variable/GHS-MULTI
    /variable/MINGW
    /variable/MSVC10
    /variable/MSVC11
@@ -307,6 +308,10 @@ Variables for Languages
    /variable/CMAKE_LANG_FLAGS_RELEASE
    /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO
    /variable/CMAKE_LANG_FLAGS
+   /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG
+   /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL
+   /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE
+   /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO
    /variable/CMAKE_LANG_IGNORE_EXTENSIONS
    /variable/CMAKE_LANG_IMPLICIT_INCLUDE_DIRECTORIES
    /variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES

+ 8 - 0
Help/release/dev/add-GreenHills-MULTI-generator.rst

@@ -0,0 +1,8 @@
+add-GreenHills-MULTI-generator
+------------------------------
+
+* A new experimental :generator:`Green Hills MULTI` generator was
+  added on Windows.  `Green Hills MULTI`_ is an IDE for embedded
+  real-time systems.
+
+.. _`Green Hills MULTI`: http://www.ghs.com/products/MULTI_IDE.html

+ 6 - 0
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst

@@ -0,0 +1,6 @@
+CMAKE_<LANG>_GHS_KERNEL_FLAGS_DEBUG
+-----------------------------------
+
+GHS kernel flags for Debug build type or configuration.
+
+<LANG> flags used when CMAKE_BUILD_TYPE is Debug.

+ 7 - 0
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst

@@ -0,0 +1,7 @@
+CMAKE_<LANG>_GHS_KERNEL_FLAGS_MINSIZEREL
+----------------------------------------
+
+GHS kernel flags for MinSizeRel build type or configuration.
+
+<LANG> flags used when CMAKE_BUILD_TYPE is MinSizeRel.Short for
+minimum size release.

+ 6 - 0
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst

@@ -0,0 +1,6 @@
+CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELEASE
+-------------------------------------
+
+GHS kernel flags for Release build type or configuration.
+
+<LANG> flags used when CMAKE_BUILD_TYPE is Release

+ 7 - 0
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst

@@ -0,0 +1,7 @@
+CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELWITHDEBINFO
+--------------------------------------------
+
+GHS kernel flags for RelWithDebInfo type or configuration.
+
+<LANG> flags used when CMAKE_BUILD_TYPE is RelWithDebInfo.  Short for
+Release With Debug Information.

+ 4 - 0
Help/variable/CMAKE_MAKE_PROGRAM.rst

@@ -56,6 +56,10 @@ to configure the project:
   the CMake cache then CMake will use the specified value if
   possible.
 
+* The :generator:`Green Hills MULTI` generator sets this to ``gbuild``.
+  If a user or project explicitly adds ``CMAKE_MAKE_PROGRAM`` to
+  the CMake cache then CMake will use the specified value.
+
 The ``CMAKE_MAKE_PROGRAM`` variable is set for use by project code.
 The value is also used by the :manual:`cmake(1)` ``--build`` and
 :manual:`ctest(1)` ``--build-and-test`` tools to launch the native

+ 2 - 0
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

+ 4 - 0
Help/variable/GHS-MULTI.rst

@@ -0,0 +1,4 @@
+GHS-MULTI
+---------
+
+True when using Green Hills MULTI

+ 27 - 0
Modules/Compiler/GHS-C.cmake

@@ -0,0 +1,27 @@
+set(CMAKE_C_VERBOSE_FLAG "-v")
+
+set(CMAKE_C_FLAGS_INIT "")
+set(CMAKE_C_FLAGS_DEBUG_INIT "-Odebug -g")
+set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Ospace")
+set(CMAKE_C_FLAGS_RELEASE_INIT "-O")
+set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+
+set(CMAKE_C_GHS_KERNEL_FLAGS_DEBUG_INIT "-ldebug ${CMAKE_C_FLAGS_DEBUG_INIT}")
+set(CMAKE_C_GHS_KERNEL_FLAGS_MINSIZEREL_INIT "${CMAKE_C_FLAGS_MINSIZEREL_INIT}")
+set(CMAKE_C_GHS_KERNEL_FLAGS_RELEASE_INIT "${CMAKE_C_FLAGS_RELEASE_INIT}")
+set(CMAKE_C_GHS_KERNEL_FLAGS_RELWITHDEBINFO_INIT
+  "-ldebug ${CMAKE_C_FLAGS_RELWITHDEBINFO_INIT}")
+
+if(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
+  set (CMAKE_C_GHS_KERNEL_FLAGS_DEBUG "${CMAKE_C_GHS_KERNEL_FLAGS_DEBUG_INIT}"
+    CACHE STRING "Kernel flags used by the compiler during debug builds.")
+  set (CMAKE_C_GHS_KERNEL_FLAGS_MINSIZEREL
+    "${CMAKE_C_GHS_KERNEL_FLAGS_MINSIZEREL_INIT}" CACHE STRING
+    "Kernel flags used by the compiler during release builds for minimum size.")
+  set (CMAKE_C_GHS_KERNEL_FLAGS_RELEASE
+    "${CMAKE_C_GHS_KERNEL_FLAGS_RELEASE_INIT}"
+    CACHE STRING "Kernel flags used by the compiler during release builds.")
+  set (CMAKE_C_GHS_KERNEL_FLAGS_RELWITHDEBINFO
+    "${CMAKE_C_GHS_KERNEL_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING
+    "Kernel flags used by the compiler during release builds with debug info.")
+endif()

+ 31 - 0
Modules/Compiler/GHS-CXX.cmake

@@ -0,0 +1,31 @@
+set(CMAKE_CXX_VERBOSE_FLAG "-v")
+
+set(CMAKE_CXX_FLAGS_INIT "")
+set(CMAKE_CXX_FLAGS_DEBUG_INIT "-Odebug -g")
+set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Ospace")
+set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O -g")
+
+set(CMAKE_CXX_GHS_KERNEL_FLAGS_DEBUG_INIT
+  "-ldebug ${CMAKE_CXX_FLAGS_DEBUG_INIT}")
+set(CMAKE_CXX_GHS_KERNEL_FLAGS_MINSIZEREL_INIT
+  "${CMAKE_CXX_FLAGS_MINSIZEREL_INIT}")
+set(CMAKE_CXX_GHS_KERNEL_FLAGS_RELEASE_INIT
+  "${CMAKE_CXX_FLAGS_RELEASE_INIT}")
+set(CMAKE_CXX_GHS_KERNEL_FLAGS_RELWITHDEBINFO_INIT
+  "-ldebug ${CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT}")
+
+if(NOT CMAKE_NOT_USING_CONFIG_FLAGS)
+  set (CMAKE_CXX_GHS_KERNEL_FLAGS_DEBUG
+    "${CMAKE_CXX_GHS_KERNEL_FLAGS_DEBUG_INIT}"
+    CACHE STRING "Kernel flags used by the compiler during debug builds.")
+  set (CMAKE_CXX_GHS_KERNEL_FLAGS_MINSIZEREL
+    "${CMAKE_CXX_GHS_KERNEL_FLAGS_MINSIZEREL_INIT}" CACHE STRING
+    "Kernel flags used by the compiler during release builds for minimum size.")
+  set (CMAKE_CXX_GHS_KERNEL_FLAGS_RELEASE
+    "${CMAKE_CXX_GHS_KERNEL_FLAGS_RELEASE_INIT}"
+    CACHE STRING "Kernel flags used by the compiler during release builds.")
+  set (CMAKE_CXX_GHS_KERNEL_FLAGS_RELWITHDEBINFO
+    "${CMAKE_CXX_GHS_KERNEL_FLAGS_RELWITHDEBINFO_INIT}" CACHE STRING
+    "Kernel flags used by the compiler during release builds with debug info.")
+endif()

+ 6 - 0
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)")

+ 4 - 1
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()
 

+ 29 - 0
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)

+ 27 - 0
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)

+ 9 - 0
Source/CMakeLists.txt

@@ -480,6 +480,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 ()
@@ -507,6 +515,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)

+ 44 - 0
Source/cmGhsMultiGpj.cxx

@@ -0,0 +1,44 @@
+/*============================================================================
+  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 LIBRARY:
+      tag = "Library";
+      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;
+}

+ 34 - 0
Source/cmGhsMultiGpj.h

@@ -0,0 +1,34 @@
+/*============================================================================
+  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,
+    LIBRARY,
+    PROJECT,
+    PROGRAM,
+    REFERENCE,
+    SUBPROJECT
+  };
+
+  static void WriteGpjTag(Types const gpjType,
+                          cmGeneratedFileStream *filestream);
+};
+
+#endif // ! cmGhsMultiGpjType_h

+ 600 - 0
Source/cmGhsMultiTargetGenerator.cxx

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

+ 119 - 0
Source/cmGhsMultiTargetGenerator.h

@@ -0,0 +1,119 @@
+/*============================================================================
+  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 *target);
+
+  virtual ~cmGhsMultiTargetGenerator();
+
+  virtual void Generate();
+
+  bool IncludeThisTarget();
+  std::vector<cmSourceFile *> GetSources() const;
+  GhsMultiGpj::Types GetGpjTag() const;
+  static GhsMultiGpj::Types GetGpjTag(const cmTarget *target);
+  const char *GetAbsBuildFilePath() const
+  {
+    return this->AbsBuildFilePath.c_str();
+  }
+  const char *GetRelBuildFileName() const
+  {
+    return this->RelBuildFileName.c_str();
+  }
+  const char *GetAbsBuildFileName() const
+  {
+    return this->AbsBuildFileName.c_str();
+  }
+  const char *GetAbsOutputFileName() const
+  {
+    return this->AbsOutputFileName.c_str();
+  }
+
+  static std::string GetRelBuildFilePath(const cmTarget *target);
+  static std::string GetAbsPathToRoot(const cmTarget *target);
+  static std::string GetAbsBuildFilePath(const cmTarget *target);
+  static std::string GetRelBuildFileName(const cmTarget *target);
+  static std::string GetBuildFileName(const cmTarget *target);
+  static std::string AddSlashIfNeededToPath(std::string const &input);
+
+private:
+  cmGlobalGhsMultiGenerator *GetGlobalGenerator() const;
+  cmGeneratedFileStream *GetFolderBuildStreams()
+  {
+    return this->FolderBuildStreams[""];
+  };
+  bool IsTargetGroup() const { return this->TargetGroup; }
+
+  void WriteTypeSpecifics(const std::string &config, bool notKernel);
+  void WriteCompilerFlags(const std::string &config,
+    const std::string &language);
+  void WriteCompilerDefinitions(const std::string &config,
+                                const std::string &language);
+
+  void SetCompilerFlags(std::string const &config, const std::string &language,
+                        bool const notKernel);
+  std::string GetDefines(const std::string &langugae,
+                         std::string const &config);
+
+  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);
+  static bool DetermineIfTargetGroup(const cmTarget *target);
+  bool DetermineIfDynamicDownload(std::string const &config,
+                                  const std::string &language);
+
+  cmTarget *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;
+  bool TargetGroup;
+  bool DynamicDownload;
+  static std::string const DDOption;
+  std::map<std::string, std::string> FlagsByLanguage;
+  std::map<std::string, std::string> DefinesByLanguage;
+};
+
+#endif // ! cmGhsMultiTargetGenerator_h

+ 548 - 0
Source/cmGlobalGhsMultiGenerator.cxx

@@ -0,0 +1,548 @@
+/*============================================================================
+  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>
+#include <cmAlgorithms.h>
+
+const char *cmGlobalGhsMultiGenerator::FILE_EXTENSION = ".gpj";
+const char *cmGlobalGhsMultiGenerator::DEFAULT_MAKE_PROGRAM = "gbuild";
+
+cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator()
+  : OSDirRelative(false)
+{
+  this->GhsBuildCommandInitialized = false;
+}
+
+cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
+{
+  cmDeleteAll(TargetFolderBuildStreams);
+}
+
+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, work-in-progress).";
+}
+
+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", "GHS");
+  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", "GHS");
+  mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
+
+  if (!ghsCompRoot.empty())
+    {
+    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::vector<std::string> userPaths;
+  userPaths.push_back(this->GetCompRoot());
+  std::string makeProgram =
+    cmSystemTools::FindProgram(DEFAULT_MAKE_PROGRAM, userPaths);
+  if (makeProgram.empty())
+    {
+    makeProgram = DEFAULT_MAKE_PROGRAM;
+    }
+  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\\Uninstall\\"
+    "GreenHillsSoftwared771f1b4;InstallLocation",
+    output[0]);
+  cmsys::SystemTools::ReadRegistryValue(
+    "HKEY_LOCAL_"
+    "MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\"
+    "Windows\\CurrentVersion\\Uninstall\\"
+    "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()
+{
+  // Compute GHS MULTI's build file path.
+  std::string buildFilePath =
+    this->GetCMakeInstance()->GetHomeOutputDirectory();
+  buildFilePath += "/";
+  buildFilePath += "default";
+  buildFilePath += FILE_EXTENSION;
+
+  this->Open(std::string(""), buildFilePath, &this->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(this->trimQuotes(osDir));
+  cmSystemTools::ReplaceString(fOSDir, "\\", "/");
+  if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0]))
+    {
+    this->OSDirRelative = false;
+    }
+  else
+    {
+    this->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(this->trimQuotes(bspName));
+  cmSystemTools::ReplaceString(fBspName, "\\", "/");
+  this->WriteMacros();
+  this->WriteHighLevelDirectives();
+
+  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
+  this->WriteDisclaimer(this->GetBuildFileStream());
+  *this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
+  if (!fBspName.empty())
+    {
+    *this->GetBuildFileStream() << "    -bsp " << fBspName << std::endl;
+    }
+  this->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.empty())
+    {
+    this->OpenBuildFileStream();
+
+    // 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();
+      this->UpdateBuildFiles(&tgts);
+      }
+    }
+
+  cmDeleteAll(TargetFolderBuildStreams);
+  this->TargetFolderBuildStreams.clear();
+}
+
+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, this->GetGhsBuildCommand())
+    );
+
+  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)
+      {
+      *this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
+      }
+    }
+}
+
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
+{
+  *this->GetBuildFileStream() << "primaryTarget=arm_integrity.tgt"
+                              << std::endl;
+  char const *const customization =
+    this->GetCMakeInstance()->GetCacheDefinition("GHS_CUSTOMIZATION");
+  if (NULL != customization && strlen(customization) > 0)
+    {
+    *this->GetBuildFileStream() << "customization="
+                                << trimQuotes(customization)
+                                << std::endl;
+    this->GetCMakeInstance()->MarkCliAsUsed("GHS_CUSTOMIZATION");
+    }
+}
+
+void cmGlobalGhsMultiGenerator::WriteCompilerOptions(std::string const &fOSDir)
+{
+  *this->GetBuildFileStream() << "    -os_dir=\"" << fOSDir << "\""
+                              << 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, 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);
+  cmSystemTools::ConvertToUnixSlashes(workingRelPath);
+  if (!workingRelPath.empty())
+    {
+    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, cmGeneratedFileStream *> *fileMap)
+{
+  if (fileMap->end() == fileMap->find(fileName))
+    {
+    cmGeneratedFileStream *temp(new cmGeneratedFileStream);
+    temp->open(fileName.c_str());
+    (*fileMap)[mapKeyName] = temp;
+    }
+}
+
+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,
+  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]);
+  GhsMultiGpj::WriteGpjTag(projType, (*targetFolderBuildStreams)[pathUpTo]);
+  WriteDisclaimer((*targetFolderBuildStreams)[pathUpTo]);
+
+  // Add to main build file
+  if (isFirst)
+    {
+    *mainBuildFile << relFilename << " ";
+    GhsMultiGpj::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,
+  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]);
+    }
+}
+
+std::string
+cmGlobalGhsMultiGenerator::GetFileNameFromPath(std::string const &path)
+{
+  std::string output(path);
+  if (!path.empty())
+    {
+    cmSystemTools::ConvertToUnixSlashes(output);
+    std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(output);
+    output += "/" + splitPath.back() + FILE_EXTENSION;
+    }
+  return output;
+}
+
+void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
+  cmGeneratorTargetsType *tgts)
+{
+  for (cmGeneratorTargetsType::iterator tgtsI = tgts->begin();
+       tgtsI != tgts->end(); ++tgtsI)
+    {
+    const cmTarget *tgt(tgtsI->first);
+    if (IsTgtForBuild(tgt))
+      {
+      char const *rawFolderName = tgtsI->first->GetProperty("FOLDER");
+      if (NULL == rawFolderName)
+        {
+        rawFolderName = "";
+        }
+      std::string folderName(rawFolderName);
+      if (this->TargetFolderBuildStreams.end() ==
+          this->TargetFolderBuildStreams.find(folderName))
+        {
+        this->AddFilesUpToPath(
+          GetBuildFileStream(), &this->TargetFolderBuildStreams,
+          this->GetCMakeInstance()->GetHomeOutputDirectory(), folderName,
+          GhsMultiGpj::PROJECT);
+        }
+      std::vector<cmsys::String> splitPath = cmSystemTools::SplitString(
+            cmGhsMultiTargetGenerator::GetRelBuildFileName(tgt));
+      std::string foldNameRelBuildFile(*(splitPath.end() - 2) + "/" +
+                                       splitPath.back());
+      *this->TargetFolderBuildStreams[folderName] << foldNameRelBuildFile
+                                                  << " ";
+      GhsMultiGpj::WriteGpjTag(cmGhsMultiTargetGenerator::GetGpjTag(tgt),
+                               this->TargetFolderBuildStreams[folderName]);
+      }
+    }
+}
+
+bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmTarget *tgt)
+{
+  const std::string config =
+    tgt->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+  std::vector<cmSourceFile *> tgtSources;
+  tgt->GetSourceFiles(tgtSources, config);
+  bool tgtInBuild = true;
+  char const *excludeFromAll = tgt->GetProperty("EXCLUDE_FROM_ALL");
+  if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
+    '\0' == excludeFromAll[1])
+  {
+    tgtInBuild = false;
+  }
+  return !tgtSources.empty() && tgtInBuild;
+}
+
+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;
+}

+ 127 - 0
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();
+  ~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 this->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 this->TargetFolderBuildStreams[""];
+  }
+
+  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 this->LibDirs; }
+
+  static void AddFilesUpToPath(
+      cmGeneratedFileStream *mainBuildFile,
+      std::map<std::string, 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, cmGeneratedFileStream *> *fileMap);
+
+  static std::string trimQuotes(std::string const &str);
+  inline bool IsOSDirRelative() { return this->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();
+
+  void WriteMacros();
+  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, GhsMultiGpj::Types 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,
+      GhsMultiGpj::Types projType);
+  static std::string GetFileNameFromPath(std::string const &path);
+  void UpdateBuildFiles(cmGeneratorTargetsType *tgts);
+  bool IsTgtForBuild(const cmTarget *tgt);
+
+  std::vector<cmGeneratedFileStream *> TargetSubProjects;
+  std::map<std::string, cmGeneratedFileStream *> TargetFolderBuildStreams;
+
+  std::vector<std::string> LibDirs;
+
+  bool OSDirRelative;
+  bool GhsBuildCommandInitialized;
+  std::string GhsBuildCommand;
+  static const char *DEFAULT_MAKE_PROGRAM;
+};
+
+#endif

+ 1 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -576,6 +576,7 @@ bool cmGlobalNinjaGenerator::UsingMinGW = false;
 
 // Implemented by:
 //   cmGlobalUnixMakefileGenerator3
+//   cmGlobalGhsMultiGenerator
 //   cmGlobalVisualStudio10Generator
 //   cmGlobalVisualStudio6Generator
 //   cmGlobalVisualStudio7Generator

+ 8 - 6
Source/cmLocalGenerator.cxx

@@ -2003,7 +2003,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries,
 
 //----------------------------------------------------------------------------
 void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
-                                            cmGeneratorTarget* target,
+                                            cmGeneratorTarget const* target,
                                             const std::string& lang,
                                             const std::string& config)
 {
@@ -2190,7 +2190,7 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags,
 
 //----------------------------------------------------------------------------
 void cmLocalGenerator::
-AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
+AddCompilerRequirementFlag(std::string &flags, cmTarget const* target,
                            const std::string& lang)
 {
   if (lang.empty())
@@ -2312,7 +2312,8 @@ AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
     }
 }
 
-static void AddVisibilityCompileOption(std::string &flags, cmTarget* target,
+static void AddVisibilityCompileOption(std::string &flags,
+                                       cmTarget const* target,
                                        cmLocalGenerator *lg,
                                        const std::string& lang)
 {
@@ -2346,7 +2347,7 @@ static void AddVisibilityCompileOption(std::string &flags, cmTarget* target,
 }
 
 static void AddInlineVisibilityCompileOption(std::string &flags,
-                                       cmTarget* target,
+                                       cmTarget const* target,
                                        cmLocalGenerator *lg)
 {
   std::string compileOption
@@ -2367,7 +2368,7 @@ static void AddInlineVisibilityCompileOption(std::string &flags,
 
 //----------------------------------------------------------------------------
 void cmLocalGenerator
-::AddVisibilityPresetFlags(std::string &flags, cmTarget* target,
+::AddVisibilityPresetFlags(std::string &flags, cmTarget const* target,
                             const std::string& lang)
 {
   int targetType = target->GetType();
@@ -2393,7 +2394,8 @@ void cmLocalGenerator
 }
 
 //----------------------------------------------------------------------------
-void cmLocalGenerator::AddCMP0018Flags(std::string &flags, cmTarget* target,
+void cmLocalGenerator::AddCMP0018Flags(std::string &flags,
+                                       cmTarget const* target,
                                        std::string const& lang,
                                        const std::string& config)
 {

+ 5 - 4
Source/cmLocalGenerator.h

@@ -138,18 +138,19 @@ public:
   std::vector<cmLocalGenerator*>& GetChildren() { return this->Children; }
 
 
-  void AddArchitectureFlags(std::string& flags, cmGeneratorTarget* target,
+  void AddArchitectureFlags(std::string& flags,
+                            cmGeneratorTarget const* target,
                             const std::string&lang, const std::string& config);
 
   void AddLanguageFlags(std::string& flags, const std::string& lang,
                         const std::string& config);
-  void AddCMP0018Flags(std::string &flags, cmTarget* target,
+  void AddCMP0018Flags(std::string &flags, cmTarget const* target,
                        std::string const& lang, const std::string& config);
-  void AddVisibilityPresetFlags(std::string &flags, cmTarget* target,
+  void AddVisibilityPresetFlags(std::string &flags, cmTarget const* target,
                                 const std::string& lang);
   void AddConfigVariableFlags(std::string& flags, const std::string& var,
                               const std::string& config);
-  void AddCompilerRequirementFlag(std::string &flags, cmTarget* target,
+  void AddCompilerRequirementFlag(std::string &flags, cmTarget const* target,
                                   const std::string& lang);
   ///! Append flags to a string.
   virtual void AppendFlags(std::string& flags, const std::string& newFlags);

+ 55 - 0
Source/cmLocalGhsMultiGenerator.cxx

@@ -0,0 +1,55 @@
+/*============================================================================
+  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.empty())
+    {
+    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();
+}

+ 56 - 0
Source/cmLocalGhsMultiGenerator.h

@@ -0,0 +1,56 @@
+/*============================================================================
+  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 this->BuildFileName.c_str(); }
+
+protected:
+  virtual bool CustomCommandUseLocal() const { return true; }
+
+private:
+  std::string BuildFileName;
+  std::string HomeRelativeOutputPath;
+};
+
+#endif

+ 3 - 0
Source/cmake.cxx

@@ -64,6 +64,7 @@
 #    include "cmGlobalBorlandMakefileGenerator.h"
 #    include "cmGlobalNMakeMakefileGenerator.h"
 #    include "cmGlobalJOMMakefileGenerator.h"
+#    include "cmGlobalGhsMultiGenerator.h"
 #    define CMAKE_HAVE_VS_GENERATORS
 #  endif
 #  include "cmGlobalMSYSMakefileGenerator.h"
@@ -1756,6 +1757,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());

+ 17 - 0
Tests/CMakeLists.txt

@@ -1967,6 +1967,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}

+ 4 - 0
Tests/GhsMulti/CMakeLists.txt

@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.1)
+project(ReturnNum)
+
+add_subdirectory(ReturnNum)

+ 4 - 0
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")

+ 8 - 0
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;
+}

+ 3 - 0
Tests/GhsMulti/ReturnNum/CMakeLists.txt

@@ -0,0 +1,3 @@
+add_subdirectory(App)
+add_subdirectory(Int)
+add_subdirectory(Lib)

+ 12 - 0
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

+ 1 - 0
Tests/GhsMulti/ReturnNum/Int/CMakeLists.txt

@@ -0,0 +1 @@
+add_executable(AppDD AppDD.int Default.bsp)

+ 35 - 0
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

+ 1 - 0
Tests/GhsMulti/ReturnNum/Lib/CMakeLists.txt

@@ -0,0 +1 @@
+add_library(Lib HelperFun.c HelperFun.h)

+ 4 - 0
Tests/GhsMulti/ReturnNum/Lib/HelperFun.c

@@ -0,0 +1,4 @@
+int giveNum(void)
+{
+    return 1;
+}

+ 1 - 0
Tests/GhsMulti/ReturnNum/Lib/HelperFun.h

@@ -0,0 +1 @@
+int giveNum(void);