Browse Source

Merge topic 'GHS_updates'

21ab58d3f8 GHS: Update test suite
72e0c115b7 GHS: Add Compiler ID detection
436cc5e991 GHS: try_compile() now uses GHS platform variables
4a1ec0de3d GHS: Fix toolset selection
1a66acdef2 GHS: Append ".gpj" to target name when generating build command
0c9e47d7cd GHS: Integrity Application updates
8044318431 GHS: Add support for some of the source file properties
73092b2213 GHS: Add support for object libraries
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !2231
Brad King 6 years ago
parent
commit
65a3abf999
100 changed files with 1705 additions and 1009 deletions
  1. 3 0
      Help/command/try_compile.rst
  2. 27 13
      Help/generator/Green Hills MULTI.rst
  3. 1 0
      Help/manual/cmake-properties.7.rst
  4. 0 5
      Help/manual/cmake-variables.7.rst
  5. 10 0
      Help/prop_tgt/GHS_INTEGRITY_APP.rst
  6. 1 0
      Help/variable/CMAKE_LANG_COMPILER_ID.rst
  7. 0 5
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_CONFIG.rst
  8. 0 5
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst
  9. 0 5
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst
  10. 0 5
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst
  11. 0 5
      Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst
  12. 1 1
      Help/variable/GHS-MULTI.rst
  13. 1 0
      Modules/CMakeCompilerIdDetection.cmake
  14. 1 0
      Modules/CMakeDetermineCCompiler.cmake
  15. 1 0
      Modules/CMakeDetermineCXXCompiler.cmake
  16. 2 0
      Modules/CMakeDetermineCompilerABI.cmake
  17. 64 21
      Modules/CMakeDetermineCompilerId.cmake
  18. 28 0
      Modules/CMakePlatformId.h.in
  19. 2 0
      Modules/CMakeTestCCompiler.cmake
  20. 2 0
      Modules/CMakeTestCXXCompiler.cmake
  21. 20 0
      Modules/CMakeTestCompilerCommon.cmake
  22. 0 20
      Modules/Compiler/GHS-C.cmake
  23. 0 24
      Modules/Compiler/GHS-CXX.cmake
  24. 7 4
      Modules/Compiler/GHS-DetermineCompiler.cmake
  25. 3 3
      Modules/Compiler/GHS.cmake
  26. 8 0
      Modules/CompilerId/GHS_default.gpj.in
  27. 3 0
      Modules/CompilerId/GHS_lib.gpj.in
  28. 7 1
      Modules/Platform/GHS-MULTI-Initialize.cmake
  29. 16 0
      Source/cmCoreTryCompile.cxx
  30. 17 14
      Source/cmGhsMultiGpj.cxx
  31. 4 2
      Source/cmGhsMultiGpj.h
  32. 362 436
      Source/cmGhsMultiTargetGenerator.cxx
  33. 26 74
      Source/cmGhsMultiTargetGenerator.h
  34. 2 1
      Source/cmGlobalGenerator.cxx
  35. 231 274
      Source/cmGlobalGhsMultiGenerator.cxx
  36. 49 50
      Source/cmGlobalGhsMultiGenerator.h
  37. 74 7
      Source/cmLocalGhsMultiGenerator.cxx
  38. 11 0
      Source/cmLocalGhsMultiGenerator.h
  39. 10 0
      Source/cmState.cxx
  40. 3 0
      Source/cmState.h
  41. 93 21
      Tests/CMakeLists.txt
  42. 0 4
      Tests/GhsMulti/CMakeLists.txt
  43. 92 0
      Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt
  44. 32 0
      Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in
  45. 4 0
      Tests/GhsMulti/GhsMultiCompilerOptions/test.c
  46. 30 0
      Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt
  47. 4 0
      Tests/GhsMulti/GhsMultiCopyFile/test.c
  48. 5 3
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
  49. 4 0
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c
  50. 0 1
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c
  51. 4 0
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c
  52. 0 1
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c
  53. 0 1
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c
  54. 0 1
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c
  55. 4 0
      Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c
  56. 17 0
      Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt
  57. 4 0
      Tests/GhsMulti/GhsMultiExclude/exe1.c
  58. 4 0
      Tests/GhsMulti/GhsMultiExclude/lib1.c
  59. 54 0
      Tests/GhsMulti/GhsMultiExclude/verify.cmake
  60. 19 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt
  61. 5 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c
  62. 4 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c
  63. 1 1
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt
  64. 0 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c
  65. 3 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt
  66. 1 1
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int
  67. 1 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt
  68. 1 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt
  69. 0 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c
  70. 0 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h
  71. 20 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt
  72. 5 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c
  73. 5 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c
  74. 15 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c
  75. 8 0
      Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int
  76. 8 0
      Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt
  77. 92 0
      Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt
  78. 43 0
      Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in
  79. 6 0
      Tests/GhsMulti/GhsMultiLinkTest/exe1.c
  80. 6 0
      Tests/GhsMulti/GhsMultiLinkTest/exe1.h
  81. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func2.c
  82. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func3.c
  83. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func4.c
  84. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func5.c
  85. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func6.c
  86. 4 0
      Tests/GhsMulti/GhsMultiLinkTest/func7.c
  87. 9 0
      Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt
  88. 12 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt
  89. 6 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c
  90. 6 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h
  91. 7 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt
  92. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c
  93. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c
  94. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c
  95. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c
  96. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c
  97. 4 0
      Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c
  98. 17 0
      Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt
  99. 5 0
      Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c
  100. 4 0
      Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c

+ 3 - 0
Help/command/try_compile.rst

@@ -168,3 +168,6 @@ then the language standard variables are honored:
 
 Their values are used to set the corresponding target properties in
 the generated project (unless overridden by an explicit option).
+
+For the :generator:`Green Hills MULTI` generator the GHS toolset and target
+system customization cache variables are also propagated into the test project.

+ 27 - 13
Help/generator/Green Hills MULTI.rst

@@ -3,49 +3,63 @@ Green Hills MULTI
 
 Generates Green Hills MULTI project files (experimental, work-in-progress).
 
+The buildsystem has predetermined build-configuration settings that can be controlled
+via the :variable:`CMAKE_BUILD_TYPE` variable.
+
 Customizations that are used to pick toolset and target system:
 
 The ``-A <arch>`` can be supplied for setting the target architecture.
 ``<arch>`` usually is one of "arm", "ppc", "86", etcetera.  If the target architecture
 is not specified then the default architecture of "arm" will be used.
 
-The ``-T <toolset>`` can be supplied for setting the toolset to be used.
-All toolsets are expected to be located at ``GHS_TOOLSET_ROOT``.
-If the toolset is not specified then the latest toolset will be used.
+The ``-T <toolset>`` option can be used to set the directory location of the toolset.
+Both absolute and relative paths are valid. Relative paths use ``GHS_TOOLSET_ROOT``
+as the root. If the toolset is not specified then the latest toolset found in
+``GHS_TOOLSET_ROOT`` will be used.
+
+Cache variables that are used for toolset and target system customization:
 
 * ``GHS_TARGET_PLATFORM``
 
-Default to ``integrity``.
-Usual values are ``integrity``, ``threadx``, ``uvelosity``,
-``velosity``, ``vxworks``, ``standalone``.
+  | Defaults to ``integrity``.
+  | Usual values are ``integrity``, ``threadx``, ``uvelosity``, ``velosity``,
+    ``vxworks``, ``standalone``.
 
 * ``GHS_PRIMARY_TARGET``
 
-Sets ``primaryTarget`` field in project file.
-Defaults to ``<arch>_<GHS_TARGET_PLATFORM>.tgt``.
+  | Sets ``primaryTarget`` entry in project file.
+  | Defaults to ``<arch>_<GHS_TARGET_PLATFORM>.tgt``.
 
 * ``GHS_TOOLSET_ROOT``
 
-Default to ``C:/ghs``.  Root path for ``toolset``.
+  | Root path for ``toolset`` searches.
+  | Defaults to ``C:/ghs``.
 
 * ``GHS_OS_ROOT``
 
-Default to ``C:/ghs``.  Root path for RTOS searches.
+  | Root path for RTOS searches.
+  | Defaults to ``C:/ghs``.
 
 * ``GHS_OS_DIR``
 
-Default to latest platform OS installation at ``GHS_OS_ROOT``.  Set this value if
-a specific RTOS is to be used.
+  | Sets ``-os_dir`` entry in project file.
+  | Defaults to latest platform OS installation at ``GHS_OS_ROOT``.  Set this value if
+    a specific RTOS is to be used.
 
 * ``GHS_BSP_NAME``
 
-Defaults to ``sim<arch>`` if not set by user.
+  | Sets ``-bsp`` entry in project file.
+  | Defaults to ``sim<arch>`` for ``integrity`` platforms.
 
 Customizations are available through the following cache variables:
 
 * ``GHS_CUSTOMIZATION``
 * ``GHS_GPJ_MACROS``
 
+The following properties are available:
+
+* :prop_tgt:`GHS_INTEGRITY_APP`
+
 .. note::
   This generator is deemed experimental as of CMake |release|
   and is still a work in progress.  Future versions of CMake

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

@@ -194,6 +194,7 @@ Properties on Targets
    /prop_tgt/FRAMEWORK
    /prop_tgt/FRAMEWORK_VERSION
    /prop_tgt/GENERATOR_FILE_NAME
+   /prop_tgt/GHS_INTEGRITY_APP
    /prop_tgt/GNUtoMS
    /prop_tgt/HAS_CXX
    /prop_tgt/IMPLICIT_DEPENDS_INCLUDE_TRANSFORM

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

@@ -482,11 +482,6 @@ Variables for Languages
    /variable/CMAKE_LANG_FLAGS_RELEASE_INIT
    /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO
    /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT
-   /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_CONFIG
-   /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

+ 10 - 0
Help/prop_tgt/GHS_INTEGRITY_APP.rst

@@ -0,0 +1,10 @@
+GHS_INTEGRITY_APP
+-----------------
+
+``ON`` / ``OFF`` boolean to determine if an executable target should
+be treated as an `Integrity Application`.
+
+If no value is set and if a `.int` file is added as a source file to the
+executable target it will be treated as an `Integrity Application`.
+
+Supported on :generator:`Green Hills MULTI`.

+ 1 - 0
Help/variable/CMAKE_LANG_COMPILER_ID.rst

@@ -19,6 +19,7 @@ include:
   Embarcadero, Borland = Embarcadero (embarcadero.com)
   G95 = G95 Fortran (g95.org)
   GNU = GNU Compiler Collection (gcc.gnu.org)
+  GHS = Green Hills Software (www.ghs.com)
   HP = Hewlett-Packard Compiler (hp.com)
   IAR = IAR Systems (iar.com)
   Intel = Intel Compiler (intel.com)

+ 0 - 5
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_CONFIG.rst

@@ -1,5 +0,0 @@
-CMAKE_<LANG>_GHS_KERNEL_FLAGS_<CONFIG>
---------------------------------------
-
-GHS kernel flags for language ``<LANG>`` when building for the ``<CONFIG>``
-configuration.

+ 0 - 5
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG.rst

@@ -1,5 +0,0 @@
-CMAKE_<LANG>_GHS_KERNEL_FLAGS_DEBUG
------------------------------------
-
-This variable is the ``Debug`` variant of the
-:variable:`CMAKE_<LANG>_GHS_KERNEL_FLAGS_<CONFIG>` variable.

+ 0 - 5
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL.rst

@@ -1,5 +0,0 @@
-CMAKE_<LANG>_GHS_KERNEL_FLAGS_MINSIZEREL
-----------------------------------------
-
-This variable is the ``MinSizeRel`` variant of the
-:variable:`CMAKE_<LANG>_GHS_KERNEL_FLAGS_<CONFIG>` variable.

+ 0 - 5
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE.rst

@@ -1,5 +0,0 @@
-CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELEASE
--------------------------------------
-
-This variable is the ``Release`` variant of the
-:variable:`CMAKE_<LANG>_GHS_KERNEL_FLAGS_<CONFIG>` variable.

+ 0 - 5
Help/variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELWITHDEBINFO.rst

@@ -1,5 +0,0 @@
-CMAKE_<LANG>_GHS_KERNEL_FLAGS_RELWITHDEBINFO
---------------------------------------------
-
-This variable is the ``RelWithDebInfo`` variant of the
-:variable:`CMAKE_<LANG>_GHS_KERNEL_FLAGS_<CONFIG>` variable.

+ 1 - 1
Help/variable/GHS-MULTI.rst

@@ -1,4 +1,4 @@
 GHS-MULTI
 ---------
 
-True when using Green Hills MULTI
+``True`` when using :generator:`Green Hills MULTI` generator.

+ 1 - 0
Modules/CMakeCompilerIdDetection.cmake

@@ -63,6 +63,7 @@ function(compiler_id_detection outvar lang)
       Cray
       TI
       Fujitsu
+      GHS
     )
     if (lang STREQUAL C)
       list(APPEND ordered_compilers

+ 1 - 0
Modules/CMakeDetermineCCompiler.cmake

@@ -31,6 +31,7 @@ if(NOT CMAKE_C_COMPILER_NAMES)
 endif()
 
 if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
 elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
   set(CMAKE_C_COMPILER_XCODE_TYPE sourcecode.c.c)
   _cmake_find_compiler_path(C)

+ 1 - 0
Modules/CMakeDetermineCXXCompiler.cmake

@@ -30,6 +30,7 @@ if(NOT CMAKE_CXX_COMPILER_NAMES)
 endif()
 
 if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
+elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
 elseif("${CMAKE_GENERATOR}" MATCHES "Xcode")
   set(CMAKE_CXX_COMPILER_XCODE_TYPE sourcecode.cpp.cpp)
   _cmake_find_compiler_path(CXX)

+ 2 - 0
Modules/CMakeDetermineCompilerABI.cmake

@@ -7,6 +7,7 @@
 # code.
 
 include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake)
+include(CMakeTestCompilerCommon)
 
 function(CMAKE_DETERMINE_COMPILER_ABI lang src)
   if(NOT DEFINED CMAKE_${lang}_ABI_COMPILED)
@@ -23,6 +24,7 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src)
       # from which we might detect implicit link libraries.
       list(APPEND CMAKE_FLAGS "-DCMAKE_${lang}_STANDARD_LIBRARIES=")
     endif()
+    __TestCompiler_setTryCompileTargetType()
     try_compile(CMAKE_${lang}_ABI_COMPILED
       ${CMAKE_BINARY_DIR} ${src}
       CMAKE_FLAGS ${CMAKE_FLAGS}

+ 64 - 21
Modules/CMakeDetermineCompilerId.cmake

@@ -52,6 +52,13 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
     endforeach()
   endif()
 
+  # If the compiler is still unknown, fallback to GHS
+  if(NOT CMAKE_${lang}_COMPILER_ID  AND "${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+    set(CMAKE_${lang}_COMPILER_ID GHS)
+    file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+        "The ${lang} compiler identification is falling back to GHS.\n\n")
+  endif()
+
   # CUDA < 7.5 is missing version macros
   if(lang STREQUAL "CUDA"
      AND CMAKE_${lang}_COMPILER_ID STREQUAL "NVIDIA"
@@ -391,6 +398,40 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS}
       separate_arguments(CMAKE_${lang}_XCODE_ARCHS)
       set(CMAKE_${lang}_XCODE_ARCHS "${CMAKE_${lang}_XCODE_ARCHS}" PARENT_SCOPE)
     endif()
+  elseif("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+    set(id_dir ${CMAKE_${lang}_COMPILER_ID_DIR})
+    set(id_src "${src}")
+    if (GHS_PRIMARY_TARGET)
+      set(ghs_primary_target "${GHS_PRIMARY_TARGET}")
+    else()
+      set(ghs_primary_target "${CMAKE_GENERATOR_PLATFORM}_${GHS_TARGET_PLATFORM}.tgt")
+    endif()
+    if ("${GHS_TARGET_PLATFORM}" MATCHES "integrity")
+        set(bsp_name "macro GHS_BSP=${GHS_BSP_NAME}")
+        set(os_dir "macro GHS_OS=${GHS_OS_DIR}")
+    endif()
+    set(command "${CMAKE_MAKE_PROGRAM}" "-commands" "-top" "GHS_default.gpj")
+    configure_file(${CMAKE_ROOT}/Modules/CompilerId/GHS_default.gpj.in
+      ${id_dir}/GHS_default.gpj @ONLY)
+    configure_file(${CMAKE_ROOT}/Modules/CompilerId/GHS_lib.gpj.in
+      ${id_dir}/GHS_lib.gpj @ONLY)
+    execute_process(COMMAND ${command}
+      WORKING_DIRECTORY ${id_dir}
+      OUTPUT_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+      ERROR_VARIABLE CMAKE_${lang}_COMPILER_ID_OUTPUT
+      RESULT_VARIABLE CMAKE_${lang}_COMPILER_ID_RESULT
+      )
+    # Match the compiler location line printed out.
+    set(ghs_toolpath "${CMAKE_MAKE_PROGRAM}")
+    string(REPLACE "/gbuild.exe" "/" ghs_toolpath ${ghs_toolpath})
+    string(REPLACE / "\\\\" ghs_toolpath ${ghs_toolpath})
+    if("${CMAKE_${lang}_COMPILER_ID_OUTPUT}" MATCHES "(${ghs_toolpath}[^ ]*)")
+      set(_comp "${CMAKE_MATCH_1}.exe")
+      if(EXISTS "${_comp}")
+        file(TO_CMAKE_PATH "${_comp}" _comp)
+        set(CMAKE_${lang}_COMPILER_ID_TOOL "${_comp}" PARENT_SCOPE)
+      endif()
+    endif()
   else()
     execute_process(
       COMMAND "${CMAKE_${lang}_COMPILER}"
@@ -550,7 +591,7 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
         set(ARCHITECTURE_ID "${CMAKE_MATCH_1}")
       endif()
       if("${info}" MATCHES "INFO:compiler_version\\[([^]\"]*)\\]")
-        string(REGEX REPLACE "^0+([0-9])" "\\1" COMPILER_VERSION "${CMAKE_MATCH_1}")
+        string(REGEX REPLACE "^0+([0-9]+)" "\\1" COMPILER_VERSION "${CMAKE_MATCH_1}")
         string(REGEX REPLACE "\\.0+([0-9])" ".\\1" COMPILER_VERSION "${COMPILER_VERSION}")
       endif()
       if("${info}" MATCHES "INFO:compiler_version_internal\\[([^]\"]*)\\]")
@@ -602,26 +643,28 @@ function(CMAKE_DETERMINE_COMPILER_ID_CHECK lang file)
     if(WIN32)
       # The offset to the PE signature is stored at 0x3c.
       file(READ ${file} peoffsethex LIMIT 1 OFFSET 60 HEX)
-      string(SUBSTRING "${peoffsethex}" 0 1 peoffsethex1)
-      string(SUBSTRING "${peoffsethex}" 1 1 peoffsethex2)
-      set(peoffsetexpression "${peoffsethex1} * 16 + ${peoffsethex2}")
-      string(REPLACE "a" "10" peoffsetexpression "${peoffsetexpression}")
-      string(REPLACE "b" "11" peoffsetexpression "${peoffsetexpression}")
-      string(REPLACE "c" "12" peoffsetexpression "${peoffsetexpression}")
-      string(REPLACE "d" "13" peoffsetexpression "${peoffsetexpression}")
-      string(REPLACE "e" "14" peoffsetexpression "${peoffsetexpression}")
-      string(REPLACE "f" "15" peoffsetexpression "${peoffsetexpression}")
-      math(EXPR peoffset "${peoffsetexpression}")
-
-      file(READ ${file} peheader LIMIT 6 OFFSET ${peoffset} HEX)
-      if(peheader STREQUAL "50450000a201")
-        set(ARCHITECTURE_ID "SH3")
-      elseif(peheader STREQUAL "50450000a301")
-        set(ARCHITECTURE_ID "SH3DSP")
-      elseif(peheader STREQUAL "50450000a601")
-        set(ARCHITECTURE_ID "SH4")
-      elseif(peheader STREQUAL "50450000a801")
-        set(ARCHITECTURE_ID "SH5")
+      if(NOT peoffsethex STREQUAL "")
+        string(SUBSTRING "${peoffsethex}" 0 1 peoffsethex1)
+        string(SUBSTRING "${peoffsethex}" 1 1 peoffsethex2)
+        set(peoffsetexpression "${peoffsethex1} * 16 + ${peoffsethex2}")
+        string(REPLACE "a" "10" peoffsetexpression "${peoffsetexpression}")
+        string(REPLACE "b" "11" peoffsetexpression "${peoffsetexpression}")
+        string(REPLACE "c" "12" peoffsetexpression "${peoffsetexpression}")
+        string(REPLACE "d" "13" peoffsetexpression "${peoffsetexpression}")
+        string(REPLACE "e" "14" peoffsetexpression "${peoffsetexpression}")
+        string(REPLACE "f" "15" peoffsetexpression "${peoffsetexpression}")
+        math(EXPR peoffset "${peoffsetexpression}")
+
+        file(READ ${file} peheader LIMIT 6 OFFSET ${peoffset} HEX)
+        if(peheader STREQUAL "50450000a201")
+          set(ARCHITECTURE_ID "SH3")
+        elseif(peheader STREQUAL "50450000a301")
+          set(ARCHITECTURE_ID "SH3DSP")
+        elseif(peheader STREQUAL "50450000a601")
+          set(ARCHITECTURE_ID "SH4")
+        elseif(peheader STREQUAL "50450000a801")
+          set(ARCHITECTURE_ID "SH5")
+        endif()
       endif()
     endif()
 

+ 28 - 0
Modules/CMakePlatformId.h.in

@@ -91,6 +91,14 @@
 #  define PLATFORM_ID
 # endif
 
+#elif defined(__INTEGRITY)
+# if defined(INT_178B)
+#  define PLATFORM_ID "Integrity178"
+
+# else /* regular Integrity */
+#  define PLATFORM_ID "Integrity"
+# endif
+
 #else /* unknown platform */
 # define PLATFORM_ID
 
@@ -151,6 +159,26 @@
 # elif defined(__ICCAVR__)
 #  define ARCHITECTURE_ID "AVR"
 
+# else /* unknown architecture */
+#  define ARCHITECTURE_ID ""
+# endif
+
+#elif defined(__ghs__)
+# if defined(__PPC64__)
+#  define ARCHITECTURE_ID "PPC64"
+
+# elif defined(__ppc__)
+#  define ARCHITECTURE_ID "PPC"
+
+# elif defined(__ARM__)
+#  define ARCHITECTURE_ID "ARM"
+
+# elif defined(__x86_64__)
+#  define ARCHITECTURE_ID "x64"
+
+# elif defined(__i386__)
+#  define ARCHITECTURE_ID "X86"
+
 # else /* unknown architecture */
 #  define ARCHITECTURE_ID ""
 # endif

+ 2 - 0
Modules/CMakeTestCCompiler.cmake

@@ -22,6 +22,7 @@ unset(CMAKE_C_COMPILER_WORKS CACHE)
 # any makefiles or projects.
 if(NOT CMAKE_C_COMPILER_WORKS)
   PrintTestCompilerStatus("C" "")
+  __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCCompiler.c
     "#ifdef __cplusplus\n"
     "# error \"The CMAKE_C_COMPILER is set to a C++ compiler\"\n"
@@ -41,6 +42,7 @@ if(NOT CMAKE_C_COMPILER_WORKS)
   set(CMAKE_C_COMPILER_WORKS ${CMAKE_C_COMPILER_WORKS})
   unset(CMAKE_C_COMPILER_WORKS CACHE)
   set(C_TEST_WAS_RUN 1)
+  __TestCompiler_restoreTryCompileTargetType()
 endif()
 
 if(NOT CMAKE_C_COMPILER_WORKS)

+ 2 - 0
Modules/CMakeTestCXXCompiler.cmake

@@ -22,6 +22,7 @@ unset(CMAKE_CXX_COMPILER_WORKS CACHE)
 # any makefiles or projects.
 if(NOT CMAKE_CXX_COMPILER_WORKS)
   PrintTestCompilerStatus("CXX" "")
+  __TestCompiler_setTryCompileTargetType()
   file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCXXCompiler.cxx
     "#ifndef __cplusplus\n"
     "# error \"The CMAKE_CXX_COMPILER is set to a C compiler\"\n"
@@ -34,6 +35,7 @@ if(NOT CMAKE_CXX_COMPILER_WORKS)
   set(CMAKE_CXX_COMPILER_WORKS ${CMAKE_CXX_COMPILER_WORKS})
   unset(CMAKE_CXX_COMPILER_WORKS CACHE)
   set(CXX_TEST_WAS_RUN 1)
+  __TestCompiler_restoreTryCompileTargetType()
 endif()
 
 if(NOT CMAKE_CXX_COMPILER_WORKS)

+ 20 - 0
Modules/CMakeTestCompilerCommon.cmake

@@ -5,3 +5,23 @@
 function(PrintTestCompilerStatus LANG MSG)
   message(STATUS "Check for working ${LANG} compiler: ${CMAKE_${LANG}_COMPILER}${MSG}")
 endfunction()
+
+# if required set the target type if not already explicitly set
+macro(__TestCompiler_setTryCompileTargetType)
+  if(NOT CMAKE_TRY_COMPILE_TARGET_TYPE)
+    if("${CMAKE_GENERATOR}" MATCHES "Green Hills MULTI")
+      #prefer static libraries to avoid linking issues
+      set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+      set(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE 1)
+    endif()
+  endif()
+endmacro()
+
+# restore the original value
+# -- not necessary if __TestCompiler_setTryCompileTargetType() was used in function scope
+macro(__TestCompiler_restoreTryCompileTargetType)
+  if(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE)
+    unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
+    unset(__CMAKE_TEST_COMPILER_TARGET_TYPE_RESTORE)
+  endif()
+endmacro()

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

@@ -8,23 +8,3 @@ string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " -Odebug -g")
 string(APPEND CMAKE_C_FLAGS_MINSIZEREL_INIT " -Ospace")
 string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " -O")
 string(APPEND 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()

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

@@ -8,27 +8,3 @@ string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " -Odebug -g")
 string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL_INIT " -Ospace")
 string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " -O")
 string(APPEND 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()

+ 7 - 4
Modules/Compiler/GHS-DetermineCompiler.cmake

@@ -1,6 +1,9 @@
-set(_compiler_id_pp_test "defined(__INTEGRITY)")
+set(_compiler_id_pp_test "defined(__ghs__)")
 
 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)")
+/* __GHS_VERSION_NUMBER = VVVVRP */
+# ifdef __GHS_VERSION_NUMBER
+# define @PREFIX@COMPILER_VERSION_MAJOR @MACRO_DEC@(__GHS_VERSION_NUMBER / 100)
+# define @PREFIX@COMPILER_VERSION_MINOR @MACRO_DEC@(__GHS_VERSION_NUMBER / 10 % 10)
+# define @PREFIX@COMPILER_VERSION_PATCH @MACRO_DEC@(__GHS_VERSION_NUMBER      % 10)
+# endif")

+ 3 - 3
Modules/Compiler/GHS.cmake

@@ -3,6 +3,6 @@ if(__COMPILER_GHS)
 endif()
 set(__COMPILER_GHS 1)
 
-set(CMAKE_EXECUTABLE_SUFFIX ".as")
-set(CMAKE_LIBRARY_PATH_TERMINATOR "\n")
-set(CMAKE_LIBRARY_PATH_FLAG "  -L")
+set(CMAKE_EXECUTABLE_SUFFIX "")
+set(CMAKE_LIBRARY_PATH_TERMINATOR "")
+set(CMAKE_LIBRARY_PATH_FLAG "")

+ 8 - 0
Modules/CompilerId/GHS_default.gpj.in

@@ -0,0 +1,8 @@
+#!gbuild
+@bsp_name@
+@os_dir@
+primaryTarget=@ghs_primary_target@
+[Project]
+     {isdefined(GHS_BSP)} -bsp $GHS_BSP
+     {isdefined(GHS_OS)} -os_dir $GHS_OS
+GHS_lib.gpj [Library]

+ 3 - 0
Modules/CompilerId/GHS_lib.gpj.in

@@ -0,0 +1,3 @@
+#!gbuild
+[Library]
+@id_src@

+ 7 - 1
Modules/Platform/GHS-MULTI-Initialize.cmake

@@ -9,6 +9,9 @@ mark_as_advanced(GHS_OS_ROOT)
 set(GHS_OS_DIR "NOTFOUND" CACHE PATH "GHS platform OS directory")
 mark_as_advanced(GHS_OS_DIR)
 
+set(GHS_OS_DIR_OPTION "-os_dir " CACHE STRING "GHS compiler os option")
+mark_as_advanced(GHS_OS_DIR)
+
 #set GHS_OS_DIR if not set by user
 if ( NOT GHS_OS_DIR )
   if (EXISTS ${GHS_OS_ROOT})
@@ -23,8 +26,11 @@ if ( NOT GHS_OS_DIR )
     endif ()
 
     #filter based on platform name
-    if (GHS_TARGET_PLATFORM STREQUAL "integrity")
+    if (GHS_TARGET_PLATFORM MATCHES "integrity")
       list(FILTER GHS_CANDIDATE_OS_DIRS INCLUDE REGEX "int[0-9][0-9][0-9][0-9a-z].*")
+    else() #fall-back for standalone
+      unset(GHS_CANDIDATE_OS_DIRS)
+      set(GHS_OS_DIR "IGNORE")
     endif ()
 
     if (GHS_CANDIDATE_OS_DIRS)

+ 16 - 0
Source/cmCoreTryCompile.cxx

@@ -57,6 +57,12 @@ static std::string const kCMAKE_TRY_COMPILE_PLATFORM_VARIABLES =
   "CMAKE_TRY_COMPILE_PLATFORM_VARIABLES";
 static std::string const kCMAKE_WARN_DEPRECATED = "CMAKE_WARN_DEPRECATED";
 
+/* GHS Multi platform variables */
+static std::set<std::string> ghs_platform_vars{
+  "GHS_TARGET_PLATFORM", "GHS_PRIMARY_TARGET", "GHS_TOOLSET_ROOT",
+  "GHS_OS_ROOT",         "GHS_OS_DIR",         "GHS_BSP_NAME"
+};
+
 static void writeProperty(FILE* fout, std::string const& targetName,
                           std::string const& prop, std::string const& value)
 {
@@ -869,6 +875,16 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
     projectName = "CMAKE_TRY_COMPILE";
   }
 
+  if (this->Makefile->GetState()->UseGhsMultiIDE()) {
+    // Forward the GHS variables to the inner project cache.
+    for (std::string const& var : ghs_platform_vars) {
+      if (const char* val = this->Makefile->GetDefinition(var)) {
+        std::string flag = "-D" + var + "=" + val;
+        cmakeFlags.push_back(std::move(flag));
+      }
+    }
+  }
+
   bool erroroc = cmSystemTools::GetErrorOccuredFlag();
   cmSystemTools::ResetErrorOccuredFlag();
   std::string output;

+ 17 - 14
Source/cmGhsMultiGpj.cxx

@@ -4,31 +4,34 @@
 
 #include "cmGeneratedFileStream.h"
 
-void GhsMultiGpj::WriteGpjTag(Types const gpjType,
-                              cmGeneratedFileStream* const filestream)
+static const char* GHS_TAG[] = { "[INTEGRITY Application]",
+                                 "[Library]",
+                                 "[Project]",
+                                 "[Program]",
+                                 "[Reference]",
+                                 "[Subproject]" };
+
+const char* GhsMultiGpj::GetGpjTag(Types const gpjType)
 {
   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";
+      tag = GHS_TAG[gpjType];
       break;
     default:
       tag = "";
   }
-  *filestream << "[" << tag << "]" << std::endl;
+  return tag;
+}
+
+void GhsMultiGpj::WriteGpjTag(Types const gpjType, std::ostream& fout)
+{
+  char const* tag;
+  tag = GhsMultiGpj::GetGpjTag(gpjType);
+  fout << tag << std::endl;
 }

+ 4 - 2
Source/cmGhsMultiGpj.h

@@ -4,6 +4,7 @@
 #define cmGhsMultiGpj_h
 
 #include "cmConfigure.h" // IWYU pragma: keep
+#include <iosfwd>
 
 class cmGeneratedFileStream;
 
@@ -20,8 +21,9 @@ public:
     SUBPROJECT
   };
 
-  static void WriteGpjTag(Types const gpjType,
-                          cmGeneratedFileStream* filestream);
+  static void WriteGpjTag(Types const gpjType, std::ostream& fout);
+
+  static const char* GetGpjTag(Types const gpjType);
 };
 
 #endif // ! cmGhsMultiGpjType_h

+ 362 - 436
Source/cmGhsMultiTargetGenerator.cxx

@@ -2,6 +2,7 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGhsMultiTargetGenerator.h"
 
+#include "cmComputeLinkInformation.h"
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGhsMultiGenerator.h"
@@ -9,177 +10,128 @@
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
 #include "cmSourceFile.h"
+#include "cmSourceGroup.h"
 #include "cmTarget.h"
-#include <assert.h>
-
-std::string const cmGhsMultiTargetGenerator::DDOption("-dynamic");
 
 cmGhsMultiTargetGenerator::cmGhsMultiTargetGenerator(cmGeneratorTarget* target)
   : GeneratorTarget(target)
   , LocalGenerator(
       static_cast<cmLocalGhsMultiGenerator*>(target->GetLocalGenerator()))
   , Makefile(target->Target->GetMakefile())
-  , TargetGroup(DetermineIfTargetGroup(target))
-  , DynamicDownload(false)
-{
-  this->RelBuildFilePath = this->GetRelBuildFilePath(target);
-
-  this->RelOutputFileName = this->RelBuildFilePath + 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()
+  , Name(target->GetName())
 {
-  cmDeleteAll(this->FolderBuildStreams);
-}
-
-std::string cmGhsMultiTargetGenerator::GetRelBuildFilePath(
-  const cmGeneratorTarget* target)
-{
-  std::string output = target->GetEffectiveFolderName();
-  cmSystemTools::ConvertToUnixSlashes(output);
-  if (!output.empty()) {
-    output += "/";
+  // Store the configuration name that is being used
+  if (const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE")) {
+    // Use the build type given by the user.
+    this->ConfigName = config;
+  } else {
+    // No configuration type given.
+    this->ConfigName.clear();
   }
-  output += target->GetName() + "/";
-  return output;
-}
-
-std::string cmGhsMultiTargetGenerator::GetAbsPathToRoot(
-  const cmGeneratorTarget* target)
-{
-  return target->GetLocalGenerator()->GetBinaryDirectory();
 }
 
-std::string cmGhsMultiTargetGenerator::GetAbsBuildFilePath(
-  const cmGeneratorTarget* target)
-{
-  std::string output;
-  output = cmGhsMultiTargetGenerator::GetAbsPathToRoot(target);
-  output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output);
-  output += cmGhsMultiTargetGenerator::GetRelBuildFilePath(target);
-  return output;
-}
-
-std::string cmGhsMultiTargetGenerator::GetRelBuildFileName(
-  const cmGeneratorTarget* target)
-{
-  std::string output;
-  output = cmGhsMultiTargetGenerator::GetRelBuildFilePath(target);
-  output = cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(output);
-  output += cmGhsMultiTargetGenerator::GetBuildFileName(target);
-  return output;
-}
-
-std::string cmGhsMultiTargetGenerator::GetBuildFileName(
-  const cmGeneratorTarget* target)
-{
-  std::string output;
-  output = target->GetName();
-  output += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
-  return output;
-}
-
-std::string cmGhsMultiTargetGenerator::AddSlashIfNeededToPath(
-  std::string const& input)
+cmGhsMultiTargetGenerator::~cmGhsMultiTargetGenerator()
 {
-  std::string output(input);
-  if (!cmHasLiteralSuffix(output, "/")) {
-    output += "/";
-  }
-  return output;
 }
 
 void cmGhsMultiTargetGenerator::Generate()
 {
-  std::vector<cmSourceFile*> objectSources = this->GetSources();
-  if (!objectSources.empty() && this->IncludeThisTarget()) {
-    if (!cmSystemTools::FileExists(this->AbsBuildFilePath.c_str())) {
-      cmSystemTools::MakeDirectory(this->AbsBuildFilePath.c_str());
+  // Determine type of target for this project
+  switch (this->GeneratorTarget->GetType()) {
+    case cmStateEnums::EXECUTABLE: {
+      // Get the name of the executable to generate.
+      std::string targetName;
+      std::string targetNameImport;
+      std::string targetNamePDB;
+      this->GeneratorTarget->GetExecutableNames(
+        targetName, this->TargetNameReal, targetNameImport, targetNamePDB,
+        this->ConfigName);
+      if (cmGhsMultiTargetGenerator::DetermineIfIntegrityApp()) {
+        this->TagType = GhsMultiGpj::INTERGRITY_APPLICATION;
+      } else {
+        this->TagType = GhsMultiGpj::PROGRAM;
+      }
+      break;
+    }
+    case cmStateEnums::STATIC_LIBRARY: {
+      std::string targetName;
+      std::string targetNameSO;
+      std::string targetNameImport;
+      std::string targetNamePDB;
+      this->GeneratorTarget->GetLibraryNames(
+        targetName, targetNameSO, this->TargetNameReal, targetNameImport,
+        targetNamePDB, this->ConfigName);
+      this->TagType = GhsMultiGpj::LIBRARY;
+      break;
+    }
+    case cmStateEnums::SHARED_LIBRARY: {
+      std::string msg = "add_library(<name> SHARED ...) not supported: ";
+      msg += this->Name;
+      cmSystemTools::Message(msg.c_str());
+      return;
     }
-    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";
+    case cmStateEnums::OBJECT_LIBRARY: {
+      std::string targetName;
+      std::string targetNameSO;
+      std::string targetNameImport;
+      std::string targetNamePDB;
+      this->GeneratorTarget->GetLibraryNames(
+        targetName, targetNameSO, this->TargetNameReal, targetNameImport,
+        targetNamePDB, this->ConfigName);
+      this->TagType = GhsMultiGpj::SUBPROJECT;
+      break;
     }
-    const std::string language(
-      this->GeneratorTarget->GetLinkerLanguage(config));
-    config = cmSystemTools::UpperCase(config);
-    this->DynamicDownload = this->DetermineIfDynamicDownload(config, language);
-    if (this->DynamicDownload) {
-      *this->GetFolderBuildStreams()
-        << "#component integrity_dynamic_download" << std::endl;
+    case cmStateEnums::MODULE_LIBRARY: {
+      std::string msg = "add_library(<name> MODULE ...) not supported: ";
+      msg += this->Name;
+      cmSystemTools::Message(msg.c_str());
+      return;
     }
-    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->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
-      this->WriteTargetLinkLibraries(config, language);
+    case cmStateEnums::UTILITY: {
+      std::string msg = "add_custom_target(<name> ...) not supported: ";
+      msg += this->Name;
+      cmSystemTools::Message(msg.c_str());
+      return;
     }
-    this->WriteCustomCommands();
+    default:
+      return;
+  }
 
-    std::map<const cmSourceFile*, std::string> objectNames =
-      cmGhsMultiTargetGenerator::GetObjectNames(
-        &objectSources, this->LocalGenerator, this->GeneratorTarget);
+  // Tell the global generator the name of the project file
+  this->GeneratorTarget->Target->SetProperty("GENERATOR_FILE_NAME",
+                                             this->Name.c_str());
+  this->GeneratorTarget->Target->SetProperty(
+    "GENERATOR_FILE_NAME_EXT", GhsMultiGpj::GetGpjTag(this->TagType));
 
-    this->WriteSources(objectSources, objectNames);
-  }
+  this->GenerateTarget();
 }
 
-bool cmGhsMultiTargetGenerator::IncludeThisTarget()
+void cmGhsMultiTargetGenerator::GenerateTarget()
 {
-  bool output = true;
-  char const* excludeFromAll =
-    this->GeneratorTarget->GetProperty("EXCLUDE_FROM_ALL");
-  if (NULL != excludeFromAll && '1' == excludeFromAll[0] &&
-      '\0' == excludeFromAll[1]) {
-    output = false;
-  }
-  return output;
-}
+  // Open the filestream in copy-if-different mode.
+  std::string fname = this->LocalGenerator->GetCurrentBinaryDirectory();
+  fname += "/";
+  fname += this->Name;
+  fname += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+  cmGeneratedFileStream fout(fname.c_str());
+  fout.SetCopyIfDifferent(true);
 
-std::vector<cmSourceFile*> cmGhsMultiTargetGenerator::GetSources() const
-{
-  std::vector<cmSourceFile*> output;
-  std::string config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE");
-  this->GeneratorTarget->GetSourceFiles(output, config);
-  return output;
-}
+  this->GetGlobalGenerator()->WriteFileHeader(fout);
+  GhsMultiGpj::WriteGpjTag(this->TagType, fout);
 
-GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag() const
-{
-  return cmGhsMultiTargetGenerator::GetGpjTag(this->GeneratorTarget);
-}
+  const std::string language(
+    this->GeneratorTarget->GetLinkerLanguage(this->ConfigName));
 
-GhsMultiGpj::Types cmGhsMultiTargetGenerator::GetGpjTag(
-  const cmGeneratorTarget* target)
-{
-  GhsMultiGpj::Types output;
-  if (cmGhsMultiTargetGenerator::DetermineIfTargetGroup(target)) {
-    output = GhsMultiGpj::INTERGRITY_APPLICATION;
-  } else if (target->GetType() == cmStateEnums::STATIC_LIBRARY) {
-    output = GhsMultiGpj::LIBRARY;
-  } else {
-    output = GhsMultiGpj::PROGRAM;
-  }
-  return output;
+  this->WriteTargetSpecifics(fout, this->ConfigName);
+  this->SetCompilerFlags(this->ConfigName, language);
+  this->WriteCompilerFlags(fout, this->ConfigName, language);
+  this->WriteCompilerDefinitions(fout, this->ConfigName, language);
+  this->WriteIncludes(fout, this->ConfigName, language);
+  this->WriteTargetLinkLine(fout, this->ConfigName);
+  this->WriteCustomCommands(fout);
+  this->WriteSources(fout);
+  this->WriteReferences(fout);
+  fout.Close();
 }
 
 cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
@@ -189,41 +141,27 @@ cmGlobalGhsMultiGenerator* cmGhsMultiTargetGenerator::GetGlobalGenerator()
     this->LocalGenerator->GetGlobalGenerator());
 }
 
-void cmGhsMultiTargetGenerator::WriteTypeSpecifics(const std::string& config,
-                                                   bool const notKernel)
+void cmGhsMultiTargetGenerator::WriteTargetSpecifics(std::ostream& fout,
+                                                     const std::string& config)
 {
-  std::string outputDir(this->GetOutputDirectory(config));
-  std::string outputFilename(this->GetOutputFilename(config));
-
-  if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) {
-    std::string const& static_library_suffix =
-      this->Makefile->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX");
-    *this->GetFolderBuildStreams()
-      << "    -o \"" << outputDir << outputFilename << static_library_suffix
-      << "\"" << std::endl;
-  } else if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
-    if (notKernel && !this->IsTargetGroup()) {
-      *this->GetFolderBuildStreams() << "    -relprog" << std::endl;
-    }
-    if (this->IsTargetGroup()) {
-      *this->GetFolderBuildStreams()
-        << "    -o \"" << outputDir << outputFilename << ".elf\"" << std::endl;
-      *this->GetFolderBuildStreams()
-        << "    :extraOutputFile=\"" << outputDir << outputFilename
-        << ".elf.ael\"" << std::endl;
-    } else {
-      std::string const executable_suffix =
-        this->Makefile->GetSafeDefinition("CMAKE_EXECUTABLE_SUFFIX");
-      *this->GetFolderBuildStreams()
-        << "    -o \"" << outputDir << outputFilename << executable_suffix
-        << "\"" << std::endl;
-    }
+  std::string outpath;
+  std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
+
+  if (this->TagType != GhsMultiGpj::SUBPROJECT) {
+    // set target binary file destination
+    outpath = this->GeneratorTarget->GetDirectory(config);
+    outpath = this->LocalGenerator->ConvertToRelativePath(rootpath, outpath);
+    fout << "    :binDirRelative=\"" << outpath << "\"" << std::endl;
+    fout << "    -o \"" << this->TargetNameReal << "\"" << std::endl;
   }
+
+  // set target object file destination
+  outpath = this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+  fout << "    :outputDirRelative=\"" << outpath << "\"" << std::endl;
 }
 
 void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
-                                                 const std::string& language,
-                                                 bool const notKernel)
+                                                 const std::string& language)
 {
   std::map<std::string, std::string>::iterator i =
     this->FlagsByLanguage.find(language);
@@ -231,14 +169,9 @@ void cmGhsMultiTargetGenerator::SetCompilerFlags(std::string const& config,
     std::string flags;
     const char* lang = language.c_str();
 
-    if (notKernel) {
-      this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
-                                             lang, config);
-    } else {
-      this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget,
-                                             lang + std::string("_GHS_KERNEL"),
-                                             config);
-    }
+    this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, lang,
+                                           config);
+
     this->LocalGenerator->AddCMP0018Flags(flags, this->GeneratorTarget, lang,
                                           config);
     this->LocalGenerator->AddVisibilityPresetFlags(
@@ -281,21 +214,25 @@ std::string cmGhsMultiTargetGenerator::GetDefines(const std::string& language,
   return i->second;
 }
 
-void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::string const&,
+void cmGhsMultiTargetGenerator::WriteCompilerFlags(std::ostream& fout,
+                                                   std::string const&,
                                                    const std::string& language)
 {
   std::map<std::string, std::string>::iterator flagsByLangI =
     this->FlagsByLanguage.find(language);
   if (flagsByLangI != this->FlagsByLanguage.end()) {
     if (!flagsByLangI->second.empty()) {
-      *this->GetFolderBuildStreams()
-        << "    " << flagsByLangI->second << std::endl;
+      std::vector<std::string> ghsCompFlags =
+        cmSystemTools::ParseArguments(flagsByLangI->second.c_str());
+      for (auto& f : ghsCompFlags) {
+        fout << "    " << f << std::endl;
+      }
     }
   }
 }
 
 void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
-  const std::string& config, const std::string& language)
+  std::ostream& fout, const std::string& config, const std::string& language)
 {
   std::vector<std::string> compileDefinitions;
   this->GeneratorTarget->GetCompileDefinitions(compileDefinitions, config,
@@ -303,11 +240,12 @@ void cmGhsMultiTargetGenerator::WriteCompilerDefinitions(
   for (std::vector<std::string>::const_iterator cdI =
          compileDefinitions.begin();
        cdI != compileDefinitions.end(); ++cdI) {
-    *this->GetFolderBuildStreams() << "    -D" << (*cdI) << std::endl;
+    fout << "    -D" << (*cdI) << std::endl;
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config,
+void cmGhsMultiTargetGenerator::WriteIncludes(std::ostream& fout,
+                                              const std::string& config,
                                               const std::string& language)
 {
   std::vector<std::string> includes;
@@ -316,80 +254,73 @@ void cmGhsMultiTargetGenerator::WriteIncludes(const std::string& config,
 
   for (std::vector<std::string>::const_iterator includes_i = includes.begin();
        includes_i != includes.end(); ++includes_i) {
-    *this->GetFolderBuildStreams()
-      << "    -I\"" << *includes_i << "\"" << std::endl;
+    fout << "    -I\"" << *includes_i << "\"" << std::endl;
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteTargetLinkLibraries(
-  std::string const& config, std::string const& language)
+void cmGhsMultiTargetGenerator::WriteTargetLinkLine(std::ostream& fout,
+                                                    std::string const& config)
 {
-  // library directories
-  cmTargetDependSet tds =
-    this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
-  for (cmTargetDependSet::iterator tdsI = tds.begin(); tdsI != tds.end();
-       ++tdsI) {
-    const cmGeneratorTarget* tg = *tdsI;
-    *this->GetFolderBuildStreams()
-      << "    -L\"" << GetAbsBuildFilePath(tg) << "\"" << std::endl;
+  if (this->TagType == GhsMultiGpj::INTERGRITY_APPLICATION) {
+    return;
   }
-  // library targets
-  cmTarget::LinkLibraryVectorType llv =
-    this->GeneratorTarget->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) {
-      libName = tg->GetName() + ".a";
-    }
-    *this->GetFolderBuildStreams()
-      << "    -l\"" << libName << "\"" << std::endl;
+
+  std::string linkLibraries;
+  std::string flags;
+  std::string linkFlags;
+  std::string frameworkPath;
+  std::string linkPath;
+
+  std::unique_ptr<cmLinkLineComputer> linkLineComputer(
+    this->GetGlobalGenerator()->CreateLinkLineComputer(
+      this->LocalGenerator,
+      this->LocalGenerator->GetStateSnapshot().GetDirectory()));
+
+  this->LocalGenerator->GetTargetFlags(
+    linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
+    frameworkPath, linkPath, this->GeneratorTarget);
+
+  // write out link options
+  std::vector<std::string> lopts =
+    cmSystemTools::ParseArguments(linkFlags.c_str());
+  for (auto& l : lopts) {
+    fout << "    " << l << std::endl;
   }
 
-  if (!this->TargetGroup) {
-    std::string linkLibraries;
-    std::string flags;
-    std::string linkFlags;
-    std::string frameworkPath;
-    std::string linkPath;
-    std::string createRule =
-      this->GeneratorTarget->GetCreateRuleVariable(language, config);
-    bool useWatcomQuote =
-      this->Makefile->IsOn(createRule + "_USE_WATCOM_QUOTE");
-    std::unique_ptr<cmLinkLineComputer> linkLineComputer(
-      this->GetGlobalGenerator()->CreateLinkLineComputer(
-        this->LocalGenerator,
-        this->LocalGenerator->GetStateSnapshot().GetDirectory()));
-    linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
-
-    this->LocalGenerator->GetTargetFlags(
-      linkLineComputer.get(), config, linkLibraries, flags, linkFlags,
-      frameworkPath, linkPath, this->GeneratorTarget);
-    linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
-
-    if (!linkPath.empty()) {
-      linkPath = " " + linkPath.substr(0U, linkPath.size() - 1U);
-      *this->GetFolderBuildStreams() << linkPath;
-    }
+  // write out link search paths
+  // must be quoted for paths that contain spaces
+  std::vector<std::string> lpath =
+    cmSystemTools::ParseArguments(linkPath.c_str());
+  for (auto& l : lpath) {
+    fout << "    -L\"" << l << "\"" << std::endl;
+  }
+
+  // write out link libs
+  // must be quoted for filepaths that contains spaces
+  std::string cbd = this->LocalGenerator->GetCurrentBinaryDirectory();
 
-    if (!linkFlags.empty()) {
-      *this->GetFolderBuildStreams() << "    " << linkFlags << std::endl;
+  std::vector<std::string> llibs =
+    cmSystemTools::ParseArguments(linkLibraries.c_str());
+  for (auto& l : llibs) {
+    if (l.compare(0, 2, "-l") == 0) {
+      fout << "    \"" << l << "\"" << std::endl;
+    } else {
+      std::string rl = cmSystemTools::CollapseCombinedPath(cbd, l);
+      fout << "    -l\"" << rl << "\"" << std::endl;
     }
   }
 }
 
-void cmGhsMultiTargetGenerator::WriteCustomCommands()
+void cmGhsMultiTargetGenerator::WriteCustomCommands(std::ostream& fout)
 {
-  WriteCustomCommandsHelper(this->GeneratorTarget->GetPreBuildCommands(),
+  WriteCustomCommandsHelper(fout, this->GeneratorTarget->GetPreBuildCommands(),
                             cmTarget::PRE_BUILD);
-  WriteCustomCommandsHelper(this->GeneratorTarget->GetPostBuildCommands(),
-                            cmTarget::POST_BUILD);
+  WriteCustomCommandsHelper(
+    fout, this->GeneratorTarget->GetPostBuildCommands(), cmTarget::POST_BUILD);
 }
 
 void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
-  std::vector<cmCustomCommand> const& commandsSet,
+  std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
   cmTarget::CustomCommandType const commandType)
 {
   for (std::vector<cmCustomCommand>::const_iterator commandsSetI =
@@ -400,10 +331,10 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
          commandI != commands.end(); ++commandI) {
       switch (commandType) {
         case cmTarget::PRE_BUILD:
-          *this->GetFolderBuildStreams() << "    :preexecShellSafe=";
+          fout << "    :preexecShellSafe=";
           break;
         case cmTarget::POST_BUILD:
-          *this->GetFolderBuildStreams() << "    :postexecShellSafe=";
+          fout << "    :postexecShellSafe=";
           break;
         default:
           assert("Only pre and post are supported");
@@ -414,242 +345,237 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
         std::string subCommandE =
           this->LocalGenerator->EscapeForShell(*commandLineI, true);
         if (!command.empty()) {
-          *this->GetFolderBuildStreams()
-            << (command.begin() == commandLineI ? "'" : " ");
+          fout << (command.begin() == commandLineI ? "'" : " ");
           // Need to double escape backslashes
           cmSystemTools::ReplaceString(subCommandE, "\\", "\\\\");
         }
-        *this->GetFolderBuildStreams() << subCommandE;
+        fout << subCommandE;
       }
       if (!command.empty()) {
-        *this->GetFolderBuildStreams() << "'" << std::endl;
+        fout << "'" << std::endl;
       }
     }
   }
 }
 
-std::map<const cmSourceFile*, std::string>
-cmGhsMultiTargetGenerator::GetObjectNames(
-  std::vector<cmSourceFile*>* const objectSources,
-  cmLocalGhsMultiGenerator* const localGhsMultiGenerator,
-  cmGeneratorTarget* const generatorTarget)
+void cmGhsMultiTargetGenerator::WriteSourceProperty(std::ostream& fout,
+                                                    const cmSourceFile* sf,
+                                                    std::string propName,
+                                                    std::string propFlag)
 {
-  std::map<std::string, std::vector<cmSourceFile*>> filenameToSource;
-  std::map<cmSourceFile*, std::string> sourceToFilename;
-  for (std::vector<cmSourceFile*>::const_iterator sf = objectSources->begin();
-       sf != objectSources->end(); ++sf) {
-    const std::string filename =
-      cmSystemTools::GetFilenameName((*sf)->GetFullPath());
-    const std::string lower_filename = cmSystemTools::LowerCase(filename);
-    filenameToSource[lower_filename].push_back(*sf);
-    sourceToFilename[*sf] = lower_filename;
-  }
-
-  std::vector<cmSourceFile*> duplicateSources;
-  for (std::map<std::string, std::vector<cmSourceFile*>>::const_iterator
-         msvSourceI = filenameToSource.begin();
-       msvSourceI != filenameToSource.end(); ++msvSourceI) {
-    if (msvSourceI->second.size() > 1) {
-      duplicateSources.insert(duplicateSources.end(),
-                              msvSourceI->second.begin(),
-                              msvSourceI->second.end());
+  const char* prop = sf->GetProperty(propName);
+  if (prop) {
+    std::vector<std::string> list;
+    cmSystemTools::ExpandListArgument(prop, list);
+    for (auto& p : list) {
+      fout << "    " << propFlag << p << std::endl;
     }
   }
-
-  std::map<const cmSourceFile*, std::string> objectNamesCorrected;
-
-  for (std::vector<cmSourceFile*>::const_iterator sf =
-         duplicateSources.begin();
-       sf != duplicateSources.end(); ++sf) {
-    std::string const longestObjectDirectory(
-      cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory(
-        localGhsMultiGenerator, generatorTarget, *sf));
-    std::string objFilenameName =
-      localGhsMultiGenerator->GetObjectFileNameWithoutTarget(
-        **sf, longestObjectDirectory);
-    cmsys::SystemTools::ReplaceString(objFilenameName, "/", "_");
-    objectNamesCorrected[*sf] = objFilenameName;
-  }
-
-  return objectNamesCorrected;
 }
 
-void cmGhsMultiTargetGenerator::WriteSources(
-  std::vector<cmSourceFile*> const& objectSources,
-  std::map<const cmSourceFile*, std::string> const& objectNames)
+void cmGhsMultiTargetGenerator::WriteSources(std::ostream& fout_proj)
 {
-  for (const cmSourceFile* sf : objectSources) {
-    std::vector<cmSourceGroup> sourceGroups(this->Makefile->GetSourceGroups());
-    std::string const& sourceFullPath = sf->GetFullPath();
-    cmSourceGroup* sourceGroup =
-      this->Makefile->FindSourceGroup(sourceFullPath, sourceGroups);
-    std::string sgPath = sourceGroup->GetFullName();
-    cmSystemTools::ConvertToUnixSlashes(sgPath);
-    cmGlobalGhsMultiGenerator::AddFilesUpToPath(
-      this->GetFolderBuildStreams(), &this->FolderBuildStreams,
-      this->LocalGenerator->GetBinaryDirectory().c_str(), sgPath,
-      GhsMultiGpj::SUBPROJECT, this->RelBuildFilePath);
-
-    std::string fullSourcePath(sf->GetFullPath());
-    if (sf->GetExtension() == "int" || sf->GetExtension() == "bsp") {
-      *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl;
-    } else {
-      // WORKAROUND: GHS MULTI needs the path to use backslashes without quotes
-      //  to open files in search as of version 6.1.6
-      cmsys::SystemTools::ReplaceString(fullSourcePath, "/", "\\");
-      *this->FolderBuildStreams[sgPath] << fullSourcePath << std::endl;
-    }
+  /* vector of all sources for this target */
+  std::vector<cmSourceFile*> sources;
+  this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
 
-    if ("ld" != sf->GetExtension() && "int" != sf->GetExtension() &&
-        "bsp" != sf->GetExtension()) {
-      this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], sf);
-      if (objectNames.end() != objectNames.find(sf)) {
-        *this->FolderBuildStreams[sgPath]
-          << "    -o \"" << objectNames.find(sf)->second << "\"" << std::endl;
-      }
+  /* vector of all groups defined for this target
+   * -- but the vector is not expanded with sub groups or in any useful order
+   */
+  std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups();
 
-      this->WriteObjectDir(this->FolderBuildStreams[sgPath],
-                           this->AbsBuildFilePath + sgPath);
-    }
+  /* for each source file assign it to its group */
+  std::map<std::string, std::vector<cmSourceFile*>> groupFiles;
+  std::set<std::string> groupNames;
+  for (auto& sf : sources) {
+    cmSourceGroup* sourceGroup =
+      this->Makefile->FindSourceGroup(sf->GetFullPath(), sourceGroups);
+    std::string gn = sourceGroup->GetFullName();
+    groupFiles[gn].push_back(sf);
+    groupNames.insert(gn);
   }
-}
 
-void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
-  cmGeneratedFileStream* fileStream, const cmSourceFile* sourceFile)
-{
-  const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
-  if (NULL != rawLangProp) {
-    std::string sourceLangProp(rawLangProp);
-    std::string extension(sourceFile->GetExtension());
-    if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
-      *fileStream << "    -dotciscxx" << std::endl;
+  /* list of known groups and the order they are displayed in a project file */
+  const std::vector<std::string> standardGroups = {
+    "Header Files", "Source Files",     "CMake Rules",
+    "Object Files", "Object Libraries", "Resources"
+  };
+
+  /* list of groups in the order they are displayed in a project file*/
+  std::vector<std::string> groupFilesList(groupFiles.size());
+
+  /* put the groups in the order they should be listed
+   * - standard groups first, and then everything else
+   *   in the order used by std::map.
+   */
+  int i = 0;
+  for (const std::string& gn : standardGroups) {
+    auto n = groupNames.find(gn);
+    if (n != groupNames.end()) {
+      groupFilesList[i] = *n;
+      i += 1;
+      groupNames.erase(gn);
     }
   }
-}
 
-void cmGhsMultiTargetGenerator::WriteObjectDir(
-  cmGeneratedFileStream* fileStream, std::string const& dir)
-{
-  std::string workingDir(dir);
-  cmSystemTools::ConvertToUnixSlashes(workingDir);
-  if (!workingDir.empty()) {
-    workingDir += "/";
+  { /* catch-all group - is last item */
+    std::string gn = "";
+    auto n = groupNames.find(gn);
+    if (n != groupNames.end()) {
+      groupFilesList.back() = *n;
+      groupNames.erase(gn);
+    }
   }
-  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->GeneratorTarget->GetProperty("RUNTIME_OUTPUT_DIRECTORY");
-  if (NULL != runtimeOutputProp) {
-    outputDir = runtimeOutputProp;
+  for (auto& n : groupNames) {
+    groupFilesList[i] = n;
+    i += 1;
   }
 
-  std::string configCapped(cmSystemTools::UpperCase(config));
-  const char* runtimeOutputSProp = this->GeneratorTarget->GetProperty(
-    "RUNTIME_OUTPUT_DIRECTORY_" + configCapped);
-  if (NULL != runtimeOutputSProp) {
-    outputDir = runtimeOutputSProp;
+  /* sort the files within each group */
+  for (auto& n : groupFilesList) {
+    std::sort(groupFiles[n].begin(), groupFiles[n].end(),
+              [](cmSourceFile* l, cmSourceFile* r) {
+                return l->GetFullPath() < r->GetFullPath();
+              });
   }
-  cmSystemTools::ConvertToUnixSlashes(outputDir);
 
-  if (!outputDir.empty()) {
-    outputDir += "/";
-  }
+  /* list of open project files */
+  std::vector<cmGeneratedFileStream*> gfiles;
+
+  /* write files into the proper project file
+   * -- groups go into main project file
+   *    unless FOLDER property or variable is set.
+   */
+  for (auto& sg : groupFilesList) {
+    std::ostream* fout;
+    bool useProjectFile =
+      cmSystemTools::IsOn(
+        this->GeneratorTarget->GetProperty("GHS_NO_SOURCE_GROUP_FILE")) ||
+      cmSystemTools::IsOn(
+        this->Makefile->GetDefinition("GHS_NO_SOURCE_GROUP_FILE"));
+    if (useProjectFile || sg.empty()) {
+      fout = &fout_proj;
+    } else {
+      // Open the filestream in copy-if-different mode.
+      std::string gname = sg;
+      cmsys::SystemTools::ReplaceString(gname, "\\", "_");
+      std::string lpath =
+        this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
+      lpath += "/";
+      lpath += gname;
+      lpath += cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+      std::string fpath = this->LocalGenerator->GetCurrentBinaryDirectory();
+      fpath += "/";
+      fpath += lpath;
+      cmGeneratedFileStream* f = new cmGeneratedFileStream(fpath.c_str());
+      f->SetCopyIfDifferent(true);
+      gfiles.push_back(f);
+      fout = f;
+      this->GetGlobalGenerator()->WriteFileHeader(*f);
+      GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, *f);
+      fout_proj << lpath << " ";
+      GhsMultiGpj::WriteGpjTag(GhsMultiGpj::SUBPROJECT, fout_proj);
+    }
 
-  return outputDir;
-}
+    if (useProjectFile) {
+      if (sg.empty()) {
+        *fout << "{comment} Others" << std::endl;
+      } else {
+        *fout << "{comment} " << sg << std::endl;
+      }
+    }
 
-std::string cmGhsMultiTargetGenerator::GetOutputFilename(
-  const std::string& config) const
-{
-  std::string outputFilename(this->GeneratorTarget->GetName());
+    /* output rule for each source file */
+    for (const cmSourceFile* si : groupFiles[sg]) {
 
-  const char* outputNameProp =
-    this->GeneratorTarget->GetProperty("OUTPUT_NAME");
-  if (NULL != outputNameProp) {
-    outputFilename = outputNameProp;
-  }
+      // Convert filename to native system
+      // WORKAROUND: GHS MULTI 6.1.4 and 6.1.6 are known to need backslash on
+      // windows when opening some files from the search window.
+      std::string fname(si->GetFullPath());
+      cmSystemTools::ConvertToOutputSlashes(fname);
+      *fout << fname << std::endl;
+
+      if ("ld" != si->GetExtension() && "int" != si->GetExtension() &&
+          "bsp" != si->GetExtension()) {
+        this->WriteObjectLangOverride(*fout, si);
+      }
+
+      this->WriteSourceProperty(*fout, si, "INCLUDE_DIRECTORIES", "-I");
+      this->WriteSourceProperty(*fout, si, "COMPILE_DEFINITIONS", "-D");
+      this->WriteSourceProperty(*fout, si, "COMPILE_OPTIONS", "");
 
-  std::string configCapped(cmSystemTools::UpperCase(config));
-  const char* outputNameSProp =
-    this->GeneratorTarget->GetProperty(configCapped + "_OUTPUT_NAME");
-  if (NULL != outputNameSProp) {
-    outputFilename = outputNameSProp;
+      /* to avoid clutter in the gui only print out the objectName if it has
+       * been renamed */
+      std::string objectName = this->GeneratorTarget->GetObjectName(si);
+      if (!objectName.empty() &&
+          this->GeneratorTarget->HasExplicitObjectName(si)) {
+        *fout << "    -o " << objectName << std::endl;
+      }
+    }
   }
 
-  return outputFilename;
+  for (cmGeneratedFileStream* f : gfiles) {
+    f->Close();
+  }
 }
 
-std::string cmGhsMultiTargetGenerator::ComputeLongestObjectDirectory(
-  cmLocalGhsMultiGenerator const* localGhsMultiGenerator,
-  cmGeneratorTarget* const generatorTarget, cmSourceFile* const sourceFile)
+void cmGhsMultiTargetGenerator::WriteObjectLangOverride(
+  std::ostream& fout, const cmSourceFile* sourceFile)
 {
-  std::string dir_max;
-  dir_max +=
-    localGhsMultiGenerator->GetMakefile()->GetCurrentBinaryDirectory();
-  dir_max += "/";
-  dir_max += generatorTarget->Target->GetName();
-  dir_max += "/";
-  std::vector<cmSourceGroup> sourceGroups(
-    localGhsMultiGenerator->GetMakefile()->GetSourceGroups());
-  std::string const& sourceFullPath = sourceFile->GetFullPath();
-  cmSourceGroup* sourceGroup =
-    localGhsMultiGenerator->GetMakefile()->FindSourceGroup(sourceFullPath,
-                                                           sourceGroups);
-  std::string const& sgPath = sourceGroup->GetFullName();
-  dir_max += sgPath;
-  dir_max += "/Objs/libs/";
-  dir_max += generatorTarget->Target->GetName();
-  dir_max += "/";
-  return dir_max;
+  const char* rawLangProp = sourceFile->GetProperty("LANGUAGE");
+  if (NULL != rawLangProp) {
+    std::string sourceLangProp(rawLangProp);
+    std::string extension(sourceFile->GetExtension());
+    if ("CXX" == sourceLangProp && ("c" == extension || "C" == extension)) {
+      fout << "    -dotciscxx" << std::endl;
+    }
+  }
 }
 
-bool cmGhsMultiTargetGenerator::IsNotKernel(std::string const& config,
-                                            const std::string& language)
+void cmGhsMultiTargetGenerator::WriteReferences(std::ostream& fout)
 {
-  bool output;
-  std::vector<std::string> options;
-  this->GeneratorTarget->GetCompileOptions(options, config, language);
-  output =
-    options.end() == std::find(options.begin(), options.end(), "-kernel");
-  return output;
-}
+  // This only applies to INTEGRITY Applications
+  if (this->TagType != GhsMultiGpj::INTERGRITY_APPLICATION) {
+    return;
+  }
 
-bool cmGhsMultiTargetGenerator::DetermineIfTargetGroup(
-  const cmGeneratorTarget* target)
-{
-  bool output = false;
-  std::vector<cmSourceFile*> sources;
-  std::string config =
-    target->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;
-    }
+  // Get the targets that this one depends upon
+  cmTargetDependSet unordered =
+    this->GetGlobalGenerator()->GetTargetDirectDepends(this->GeneratorTarget);
+  cmGlobalGhsMultiGenerator::OrderedTargetDependSet ordered(unordered,
+                                                            this->Name);
+  for (auto& t : ordered) {
+    std::string tname = t->GetName();
+    std::string tpath = t->LocalGenerator->GetCurrentBinaryDirectory();
+    std::string rootpath = this->LocalGenerator->GetCurrentBinaryDirectory();
+    std::string outpath =
+      this->LocalGenerator->ConvertToRelativePath(rootpath, tpath) + "/" +
+      tname + "REF" + cmGlobalGhsMultiGenerator::FILE_EXTENSION;
+
+    fout << outpath;
+    fout << "    ";
+    GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fout);
+
+    // Tell the global generator that a refernce project needs to be created
+    t->Target->SetProperty("GHS_REFERENCE_PROJECT", "ON");
   }
-  return output;
 }
 
-bool cmGhsMultiTargetGenerator::DetermineIfDynamicDownload(
-  std::string const& config, const std::string& language)
+bool cmGhsMultiTargetGenerator::DetermineIfIntegrityApp(void)
 {
-  std::vector<std::string> options;
-  bool output = false;
-  this->GeneratorTarget->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;
+  const char* p = this->GeneratorTarget->GetProperty("ghs_integrity_app");
+  if (p) {
+    return cmSystemTools::IsOn(
+      this->GeneratorTarget->GetProperty("ghs_integrity_app"));
+  } else {
+    std::vector<cmSourceFile*> sources;
+    this->GeneratorTarget->GetSourceFiles(sources, this->ConfigName);
+    for (auto& sf : sources) {
+      if ("int" == sf->GetExtension()) {
+        return true;
+      }
     }
+    return false;
   }
-  return output;
 }

+ 26 - 74
Source/cmGhsMultiTargetGenerator.h

@@ -24,97 +24,49 @@ public:
 
   virtual void Generate();
 
-  bool IncludeThisTarget();
-  std::vector<cmSourceFile*> GetSources() const;
-  GhsMultiGpj::Types GetGpjTag() const;
-  static GhsMultiGpj::Types GetGpjTag(const cmGeneratorTarget* 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 cmGeneratorTarget* target);
-  static std::string GetAbsPathToRoot(const cmGeneratorTarget* target);
-  static std::string GetAbsBuildFilePath(const cmGeneratorTarget* target);
-  static std::string GetRelBuildFileName(const cmGeneratorTarget* target);
-  static std::string GetBuildFileName(const cmGeneratorTarget* 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,
+
+  void GenerateTarget();
+
+  void WriteTargetSpecifics(std::ostream& fout, const std::string& config);
+
+  void WriteCompilerFlags(std::ostream& fout, const std::string& config,
                           const std::string& language);
-  void WriteCompilerDefinitions(const std::string& config,
+  void WriteCompilerDefinitions(std::ostream& fout, const std::string& config,
                                 const std::string& language);
 
-  void SetCompilerFlags(std::string const& config, const std::string& language,
-                        bool const notKernel);
+  void SetCompilerFlags(std::string const& config,
+                        const std::string& language);
+
   std::string GetDefines(const std::string& langugae,
                          std::string const& config);
 
-  void WriteIncludes(const std::string& config, const std::string& language);
-  void WriteTargetLinkLibraries(std::string const& config,
-                                std::string const& language);
-  void WriteCustomCommands();
+  void WriteIncludes(std::ostream& fout, const std::string& config,
+                     const std::string& language);
+  void WriteTargetLinkLine(std::ostream& fout, std::string const& config);
+  void WriteCustomCommands(std::ostream& fout);
   void WriteCustomCommandsHelper(
-    std::vector<cmCustomCommand> const& commandsSet,
+    std::ostream& fout, std::vector<cmCustomCommand> const& commandsSet,
     cmTarget::CustomCommandType commandType);
-  void WriteSources(
-    std::vector<cmSourceFile*> const& objectSources,
-    std::map<const cmSourceFile*, std::string> const& objectNames);
-  static std::map<const cmSourceFile*, std::string> GetObjectNames(
-    std::vector<cmSourceFile*>* objectSources,
-    cmLocalGhsMultiGenerator* localGhsMultiGenerator,
-    cmGeneratorTarget* generatorTarget);
-  static void WriteObjectLangOverride(cmGeneratedFileStream* fileStream,
+  void WriteSources(std::ostream& fout_proj);
+  void WriteSourceProperty(std::ostream& fout, const cmSourceFile* sf,
+                           std::string propName, std::string propFlag);
+  void WriteReferences(std::ostream& fout);
+  static void WriteObjectLangOverride(std::ostream& fout,
                                       const 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;
-  static std::string ComputeLongestObjectDirectory(
-    cmLocalGhsMultiGenerator const* localGhsMultiGenerator,
-    cmGeneratorTarget* generatorTarget, cmSourceFile* const sourceFile);
-
-  bool IsNotKernel(std::string const& config, const std::string& language);
-  static bool DetermineIfTargetGroup(const cmGeneratorTarget* target);
-  bool DetermineIfDynamicDownload(std::string const& config,
-                                  const std::string& language);
 
+  bool DetermineIfIntegrityApp(void);
   cmGeneratorTarget* GeneratorTarget;
   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;
+
+  std::string TargetNameReal;
+  GhsMultiGpj::Types TagType;
+  std::string const Name;
+  std::string ConfigName; /* CMAKE_BUILD_TYPE */
 };
 
 #endif // ! cmGhsMultiTargetGenerator_h

+ 2 - 1
Source/cmGlobalGenerator.cxx

@@ -302,7 +302,8 @@ bool cmGlobalGenerator::CheckTargetsForMissingSources() const
     for (cmGeneratorTarget* target : targets) {
       if (target->GetType() == cmStateEnums::TargetType::GLOBAL_TARGET ||
           target->GetType() == cmStateEnums::TargetType::INTERFACE_LIBRARY ||
-          target->GetType() == cmStateEnums::TargetType::UTILITY) {
+          target->GetType() == cmStateEnums::TargetType::UTILITY ||
+          cmSystemTools::IsOn(target->GetProperty("ghs_integrity_app"))) {
         continue;
       }
 

+ 231 - 274
Source/cmGlobalGhsMultiGenerator.cxx

@@ -11,6 +11,7 @@
 #include "cmGhsMultiTargetGenerator.h"
 #include "cmLocalGhsMultiGenerator.h"
 #include "cmMakefile.h"
+#include "cmState.h"
 #include "cmVersion.h"
 #include "cmake.h"
 
@@ -20,13 +21,12 @@ const char* cmGlobalGhsMultiGenerator::DEFAULT_TOOLSET_ROOT = "C:/ghs";
 
 cmGlobalGhsMultiGenerator::cmGlobalGhsMultiGenerator(cmake* cm)
   : cmGlobalGenerator(cm)
-  , OSDirRelative(false)
 {
+  cm->GetState()->SetGhsMultiIDE(true);
 }
 
 cmGlobalGhsMultiGenerator::~cmGlobalGhsMultiGenerator()
 {
-  cmDeleteAll(TargetFolderBuildStreams);
 }
 
 cmLocalGenerator* cmGlobalGhsMultiGenerator::CreateLocalGenerator(
@@ -42,46 +42,59 @@ void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry)
     "Generates Green Hills MULTI files (experimental, work-in-progress).";
 }
 
+void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory(
+  cmGeneratorTarget* gt) const
+{
+  // Compute full path to object file directory for this target.
+  std::string dir;
+  dir += gt->LocalGenerator->GetCurrentBinaryDirectory();
+  dir += "/";
+  dir += gt->LocalGenerator->GetTargetDirectory(gt);
+  dir += "/";
+  gt->ObjectDirectory = dir;
+}
+
 bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
                                                     cmMakefile* mf)
 {
-  std::string tsp;      /* toolset path */
-  std::string tsn = ts; /* toolset name */
+  std::string tsp; /* toolset path */
 
-  GetToolset(mf, tsp, tsn);
+  this->GetToolset(mf, tsp, ts);
 
   /* no toolset was found */
-  if (tsn.empty()) {
+  if (tsp.empty()) {
     return false;
   } else if (ts.empty()) {
     std::string message;
     message =
       "Green Hills MULTI: -T <toolset> not specified; defaulting to \"";
-    message += tsn;
+    message += tsp;
     message += "\"";
     cmSystemTools::Message(message.c_str());
 
-    /* store the toolset for later use
+    /* store the full toolset for later use
      * -- already done if -T<toolset> was specified
      */
-    mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsn.c_str(),
-                           "Name of generator toolset.",
+    mf->AddCacheDefinition("CMAKE_GENERATOR_TOOLSET", tsp.c_str(),
+                           "Location of generator toolset.",
                            cmStateEnums::INTERNAL);
   }
 
   /* set the build tool to use */
+  std::string gbuild(tsp + ((tsp.back() == '/') ? "" : "/") +
+                     DEFAULT_BUILD_PROGRAM);
   const char* prevTool = mf->GetDefinition("CMAKE_MAKE_PROGRAM");
-  std::string gbuild(tsp + "/" + tsn + "/" + DEFAULT_BUILD_PROGRAM);
 
   /* check if the toolset changed from last generate */
   if (prevTool != NULL && (gbuild != prevTool)) {
-    std::string message = "generator toolset: ";
+    std::string message = "toolset build tool: ";
     message += gbuild;
-    message += "\nDoes not match the toolset used previously: ";
+    message += "\nDoes not match the previously used build tool: ";
     message += prevTool;
     message += "\nEither remove the CMakeCache.txt file and CMakeFiles "
                "directory or choose a different binary directory.";
     cmSystemTools::Error(message.c_str());
+    return false;
   } else {
     /* store the toolset that is being used for this build */
     mf->AddCacheDefinition("CMAKE_MAKE_PROGRAM", gbuild.c_str(),
@@ -89,25 +102,7 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorToolset(std::string const& ts,
                            true);
   }
 
-  mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsn.c_str());
-
-  // FIXME: compiler detection not implemented
-  // gbuild uses the primaryTarget setting in the top-level project
-  // file to determine which compiler to use. Because compiler
-  // detection is not implemented these variables must be
-  // set to skip past these tests. However cmake will verify that
-  // the executable pointed to by CMAKE_<LANG>_COMPILER exists.
-  // To pass this additional check gbuild is used as a place holder for the
-  // actual compiler.
-  mf->AddDefinition("CMAKE_C_COMPILER", gbuild.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", gbuild.c_str());
-  mf->AddDefinition("CMAKE_CXX_COMPILER_ID_RUN", "TRUE");
-  mf->AddDefinition("CMAKE_CXX_COMPILER_ID", "GHS");
-  mf->AddDefinition("CMAKE_CXX_COMPILER_FORCED", "TRUE");
+  mf->AddDefinition("CMAKE_SYSTEM_VERSION", tsp.c_str());
 
   return true;
 }
@@ -130,6 +125,8 @@ bool cmGlobalGhsMultiGenerator::SetGeneratorPlatform(std::string const& p,
 
   const char* tgtPlatform = mf->GetDefinition("GHS_TARGET_PLATFORM");
   if (tgtPlatform == nullptr) {
+    cmSystemTools::Message("Green Hills MULTI: GHS_TARGET_PLATFORM not "
+                           "specified; defaulting to \"integrity\"");
     tgtPlatform = "integrity";
   }
 
@@ -160,11 +157,11 @@ bool cmGlobalGhsMultiGenerator::FindMakeProgram(cmMakefile* /*mf*/)
 }
 
 void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
-                                           std::string& ts)
+                                           const std::string& ts)
 {
   const char* ghsRoot = mf->GetDefinition("GHS_TOOLSET_ROOT");
 
-  if (!ghsRoot) {
+  if (!ghsRoot || ghsRoot[0] == '\0') {
     ghsRoot = DEFAULT_TOOLSET_ROOT;
   }
   tsd = ghsRoot;
@@ -173,129 +170,208 @@ void cmGlobalGhsMultiGenerator::GetToolset(cmMakefile* mf, std::string& tsd,
     std::vector<std::string> output;
 
     // Use latest? version
+    if (tsd.back() != '/') {
+      tsd += "/";
+    }
     cmSystemTools::Glob(tsd, "comp_[^;]+", output);
 
     if (output.empty()) {
-      cmSystemTools::Error("GHS toolset not found in ", tsd.c_str());
-      ts = "";
+      std::string msg =
+        "No GHS toolsets found in GHS_TOOLSET_ROOT \"" + tsd + "\".";
+      cmSystemTools::Error(msg.c_str());
+      tsd = "";
     } else {
-      ts = output.back();
+      tsd += output.back();
     }
   } else {
-    std::string tryPath = tsd + std::string("/") + ts;
+    std::string tryPath;
+    /* CollapseCombinedPath will check if ts is an absolute path */
+    tryPath = cmSystemTools::CollapseCombinedPath(tsd, ts);
     if (!cmSystemTools::FileExists(tryPath)) {
-      cmSystemTools::Error("GHS toolset \"", ts.c_str(), "\" not found in ",
-                           tsd.c_str());
-      ts = "";
+      std::string msg = "GHS toolset \"" + tryPath + "\" not found.";
+      cmSystemTools::Error(msg.c_str());
+      tsd = "";
+    } else {
+      tsd = tryPath;
     }
   }
 }
 
-void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
-  std::string const& filepath, cmGeneratedFileStream** filestream)
+void cmGlobalGhsMultiGenerator::WriteFileHeader(std::ostream& fout)
 {
-  // Get a stream where to generate things.
-  if (NULL == *filestream) {
-    *filestream = new cmGeneratedFileStream(filepath.c_str());
-    if (NULL != *filestream) {
-      OpenBuildFileStream(*filestream);
-    }
-  }
+  fout << "#!gbuild" << std::endl;
+  fout << "#" << std::endl
+       << "# CMAKE generated file: DO NOT EDIT!" << std::endl
+       << "# Generated by \"" << this->GetActualName() << "\""
+       << " Generator, CMake Version " << cmVersion::GetMajorVersion() << "."
+       << cmVersion::GetMinorVersion() << std::endl
+       << "#" << std::endl
+       << std::endl;
 }
 
-void cmGlobalGhsMultiGenerator::OpenBuildFileStream(
-  cmGeneratedFileStream* filestream)
+void cmGlobalGhsMultiGenerator::WriteTopLevelProject(
+  std::ostream& fout, cmLocalGenerator* root,
+  std::vector<cmLocalGenerator*>& generators)
 {
-  *filestream << "#!gbuild" << std::endl;
-}
+  WriteFileHeader(fout);
 
-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));
-  std::replace(fOSDir.begin(), fOSDir.end(), '\\', '/');
-  if (!fOSDir.empty() && ('c' == fOSDir[0] || 'C' == fOSDir[0])) {
-    this->OSDirRelative = false;
-  } else {
-    this->OSDirRelative = true;
+  this->WriteMacros(fout);
+  this->WriteHighLevelDirectives(fout);
+  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, fout);
+
+  fout << "# Top Level Project File" << std::endl;
+
+  // Specify BSP option if supplied by user
+  // -- not all platforms require this entry in the project file
+  //    integrity platforms require this field; use default if needed
+  std::string platform;
+  if (const char* p =
+        this->GetCMakeInstance()->GetCacheDefinition("GHS_TARGET_PLATFORM")) {
+    platform = p;
   }
 
   std::string bspName;
-  char const* bspCache =
-    this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME");
-  if (bspCache) {
+  if (char const* bspCache =
+        this->GetCMakeInstance()->GetCacheDefinition("GHS_BSP_NAME")) {
     bspName = bspCache;
     this->GetCMakeInstance()->MarkCliAsUsed("GHS_BSP_NAME");
+  } else {
+    bspName = "IGNORE";
   }
-  if (bspName.empty() || bspName.compare("IGNORE") == 0) {
+
+  if (platform.find("integrity") != std::string::npos &&
+      cmSystemTools::IsOff(bspName.c_str())) {
     const char* a =
       this->GetCMakeInstance()->GetCacheDefinition("CMAKE_GENERATOR_PLATFORM");
     bspName = "sim";
     bspName += (a ? a : "");
   }
 
-  this->WriteMacros();
-  this->WriteHighLevelDirectives();
+  if (!cmSystemTools::IsOff(bspName.c_str())) {
+    fout << "    -bsp " << bspName << std::endl;
+  }
+
+  // Specify OS DIR if supplied by user
+  // -- not all platforms require this entry in the project file
+  std::string osDir;
+  std::string osDirOption;
+  if (char const* osDirCache =
+        this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR")) {
+    osDir = osDirCache;
+  }
+
+  if (char const* osDirOptionCache =
+        this->GetCMakeInstance()->GetCacheDefinition("GHS_OS_DIR_OPTION")) {
+    osDirOption = osDirOptionCache;
+  }
 
-  GhsMultiGpj::WriteGpjTag(GhsMultiGpj::PROJECT, this->GetBuildFileStream());
-  this->WriteDisclaimer(this->GetBuildFileStream());
-  *this->GetBuildFileStream() << "# Top Level Project File" << std::endl;
-  *this->GetBuildFileStream() << "    -bsp " << bspName << std::endl;
+  if (!cmSystemTools::IsOff(osDir.c_str()) ||
+      platform.find("integrity") != std::string::npos) {
+    std::replace(osDir.begin(), osDir.end(), '\\', '/');
+    fout << "    " << osDirOption << "\"" << osDir << "\"" << std::endl;
+  }
 
-  this->WriteCompilerOptions(fOSDir);
+  WriteSubProjects(fout, root, generators);
 }
 
-void cmGlobalGhsMultiGenerator::CloseBuildFileStream(
-  cmGeneratedFileStream** filestream)
+void cmGlobalGhsMultiGenerator::WriteSubProjects(
+  std::ostream& fout, cmLocalGenerator* root,
+  std::vector<cmLocalGenerator*>& generators)
 {
-  if (filestream) {
-    delete *filestream;
-    *filestream = NULL;
-  } else {
-    cmSystemTools::Error("Build file stream was not open.");
+  // Collect all targets under this root generator and the transitive
+  // closure of their dependencies.
+  TargetDependSet projectTargets;
+  TargetDependSet originalTargets;
+  this->GetTargetSets(projectTargets, originalTargets, root, generators);
+  OrderedTargetDependSet orderedProjectTargets(projectTargets, "");
+
+  // write out all the sub-projects
+  std::string rootBinaryDir = root->GetCurrentBinaryDirectory();
+  for (cmGeneratorTarget const* target : orderedProjectTargets) {
+    if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+      continue;
+    }
+
+    const char* projName = target->GetProperty("GENERATOR_FILE_NAME");
+    const char* projType = target->GetProperty("GENERATOR_FILE_NAME_EXT");
+    if (projName && projType) {
+      cmLocalGenerator* lg = target->GetLocalGenerator();
+      std::string dir = lg->GetCurrentBinaryDirectory();
+      dir = root->ConvertToRelativePath(rootBinaryDir, dir.c_str());
+      if (dir == ".") {
+        dir.clear();
+      } else {
+        if (dir.back() != '/') {
+          dir += "/";
+        }
+      }
+
+      if (cmSystemTools::IsOn(target->GetProperty("EXCLUDE_FROM_ALL"))) {
+        fout << "{comment} ";
+      }
+      std::string projFile = dir + projName + FILE_EXTENSION;
+      fout << projFile;
+      fout << " " << projType << std::endl;
+
+      if (cmSystemTools::IsOn(target->GetProperty("GHS_REFERENCE_PROJECT"))) {
+        // create reference project
+        std::string fname = dir;
+        fname += target->GetName();
+        fname += "REF";
+        fname += FILE_EXTENSION;
+
+        cmGeneratedFileStream fref(fname.c_str());
+        fref.SetCopyIfDifferent(true);
+
+        this->WriteFileHeader(fref);
+        GhsMultiGpj::WriteGpjTag(GhsMultiGpj::REFERENCE, fref);
+        fref << "    :reference=" << projFile << std::endl;
+
+        fref.Close();
+      }
+    }
   }
 }
 
 void cmGlobalGhsMultiGenerator::Generate()
 {
+  // first do the superclass method
   this->cmGlobalGenerator::Generate();
 
-  if (!this->LocalGenerators.empty()) {
-    this->OpenBuildFileStream();
+  // output top-level projects
+  for (auto& it : this->ProjectMap) {
+    this->OutputTopLevelProject(it.second[0], it.second);
+  }
+}
 
-    // Build all the folder build files
-    for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) {
-      cmLocalGhsMultiGenerator* lg =
-        static_cast<cmLocalGhsMultiGenerator*>(this->LocalGenerators[i]);
-      const std::vector<cmGeneratorTarget*>& tgts = lg->GetGeneratorTargets();
-      this->UpdateBuildFiles(tgts);
-    }
+void cmGlobalGhsMultiGenerator::OutputTopLevelProject(
+  cmLocalGenerator* root, std::vector<cmLocalGenerator*>& generators)
+{
+  if (generators.empty()) {
+    return;
   }
 
-  cmDeleteAll(TargetFolderBuildStreams);
-  this->TargetFolderBuildStreams.clear();
+  /* Name top-level projects as filename.top.gpj to avoid name clashes
+   * with target projects.  This avoid the issue where the project has
+   * the same name as the executable target.
+   */
+  std::string fname = root->GetCurrentBinaryDirectory();
+  fname += "/";
+  fname += root->GetProjectName();
+  fname += ".top";
+  fname += FILE_EXTENSION;
+
+  cmGeneratedFileStream fout(fname.c_str());
+  fout.SetCopyIfDifferent(true);
+
+  this->WriteTopLevelProject(fout, root, generators);
+
+  fout.Close();
 }
 
 void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
   std::vector<std::string>& makeCommand, const std::string& makeProgram,
-  const std::string& /*projectName*/, const std::string& /*projectDir*/,
+  const std::string& projectName, const std::string& projectDir,
   const std::string& targetName, const std::string& /*config*/, bool /*fast*/,
   int jobs, bool /*verbose*/, std::vector<std::string> const& makeOptions)
 {
@@ -313,16 +389,34 @@ void cmGlobalGhsMultiGenerator::GenerateBuildCommand(
 
   makeCommand.insert(makeCommand.end(), makeOptions.begin(),
                      makeOptions.end());
+
+  /* determine which top-project file to use */
+  std::string proj = projectName + ".top" + FILE_EXTENSION;
+  std::vector<std::string> files;
+  cmSystemTools::Glob(projectDir, ".*\\.top\\.gpj", files);
+  if (!files.empty()) {
+    auto p = std::find(files.begin(), files.end(), proj);
+    if (p == files.end()) {
+      proj = files.at(0);
+    }
+  }
+
+  makeCommand.push_back("-top");
+  makeCommand.push_back(proj);
   if (!targetName.empty()) {
     if (targetName == "clean") {
       makeCommand.push_back("-clean");
     } else {
-      makeCommand.push_back(targetName);
+      if (targetName.compare(targetName.size() - 4, 4, ".gpj") == 0) {
+        makeCommand.push_back(targetName);
+      } else {
+        makeCommand.push_back(targetName + ".gpj");
+      }
     }
   }
 }
 
-void cmGlobalGhsMultiGenerator::WriteMacros()
+void cmGlobalGhsMultiGenerator::WriteMacros(std::ostream& fout)
 {
   char const* ghsGpjMacros =
     this->GetCMakeInstance()->GetCacheDefinition("GHS_GPJ_MACROS");
@@ -332,12 +426,12 @@ void cmGlobalGhsMultiGenerator::WriteMacros()
     for (std::vector<std::string>::const_iterator expandedListI =
            expandedList.begin();
          expandedListI != expandedList.end(); ++expandedListI) {
-      *this->GetBuildFileStream() << "macro " << *expandedListI << std::endl;
+      fout << "macro " << *expandedListI << std::endl;
     }
   }
 }
 
-void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
+void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives(std::ostream& fout)
 {
   /* set primary target */
   std::string tgt;
@@ -357,183 +451,46 @@ void cmGlobalGhsMultiGenerator::WriteHighLevelDirectives()
     tgt += ".tgt";
   }
 
-  *this->GetBuildFileStream() << "primaryTarget=" << tgt << std::endl;
+  fout << "primaryTarget=" << 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;
+    fout << "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 cmGlobalGhsMultiGenerator::trimQuotes(std::string const& str)
 {
-  std::string workingPath(path);
-  cmSystemTools::ConvertToUnixSlashes(workingPath);
-  std::vector<std::string> splitPath = cmSystemTools::SplitString(workingPath);
-  std::string workingRelPath(relPath);
-  cmSystemTools::ConvertToUnixSlashes(workingRelPath);
-  if (!workingRelPath.empty()) {
-    workingRelPath += "/";
-  }
-  std::string pathUpTo;
-  for (std::vector<std::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);
+  std::string result;
+  result.reserve(str.size());
+  for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
+    if (*ch != '"') {
+      result += *ch;
     }
-    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<std::string>::const_iterator splitPathI,
-  std::vector<std::string>::const_iterator end,
-  GhsMultiGpj::Types const projType)
-{
-  std::vector<std::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]);
   }
+  return result;
 }
 
-std::string cmGlobalGhsMultiGenerator::GetFileNameFromPath(
-  std::string const& path)
+bool cmGlobalGhsMultiGenerator::TargetCompare::operator()(
+  cmGeneratorTarget const* l, cmGeneratorTarget const* r) const
 {
-  std::string output(path);
-  if (!path.empty()) {
-    cmSystemTools::ConvertToUnixSlashes(output);
-    std::vector<std::string> splitPath = cmSystemTools::SplitString(output);
-    output += "/" + splitPath.back() + FILE_EXTENSION;
+  // Make sure a given named target is ordered first,
+  // e.g. to set ALL_BUILD as the default active project.
+  // When the empty string is named this is a no-op.
+  if (r->GetName() == this->First) {
+    return false;
   }
-  return output;
-}
-
-void cmGlobalGhsMultiGenerator::UpdateBuildFiles(
-  const std::vector<cmGeneratorTarget*>& tgts)
-{
-  for (std::vector<cmGeneratorTarget*>::const_iterator tgtsI = tgts.begin();
-       tgtsI != tgts.end(); ++tgtsI) {
-    const cmGeneratorTarget* tgt = *tgtsI;
-    if (IsTgtForBuild(tgt)) {
-      std::string folderName = tgt->GetEffectiveFolderName();
-      if (this->TargetFolderBuildStreams.end() ==
-          this->TargetFolderBuildStreams.find(folderName)) {
-        this->AddFilesUpToPath(
-          GetBuildFileStream(), &this->TargetFolderBuildStreams,
-          this->GetCMakeInstance()->GetHomeOutputDirectory().c_str(),
-          folderName, GhsMultiGpj::PROJECT);
-      }
-      std::vector<std::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]);
-    }
+  if (l->GetName() == this->First) {
+    return true;
   }
+  return l->GetName() < r->GetName();
 }
 
-bool cmGlobalGhsMultiGenerator::IsTgtForBuild(const cmGeneratorTarget* tgt)
+cmGlobalGhsMultiGenerator::OrderedTargetDependSet::OrderedTargetDependSet(
+  TargetDependSet const& targets, std::string const& first)
+  : derived(TargetCompare(first))
 {
-  const std::string config =
-    tgt->Target->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;
+  this->insert(targets.begin(), targets.end());
 }

+ 49 - 50
Source/cmGlobalGhsMultiGenerator.h

@@ -13,7 +13,7 @@ class cmGeneratedFileStream;
 class cmGlobalGhsMultiGenerator : public cmGlobalGenerator
 {
 public:
-  /// The default name of GHS MULTI's build file. Typically: monolith.gpj.
+  // The default filename extension of GHS MULTI's build files.
   static const char* FILE_EXTENSION;
 
   cmGlobalGhsMultiGenerator(cmake* cm);
@@ -63,29 +63,28 @@ public:
    */
   bool FindMakeProgram(cmMakefile* mf) override;
 
-  cmGeneratedFileStream* GetBuildFileStream()
-  {
-    return this->TargetFolderBuildStreams[""];
-  }
+  void ComputeTargetObjectDirectory(cmGeneratorTarget* gt) const override;
 
-  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; }
+  // Write the common disclaimer text at the top of each build file.
+  void WriteFileHeader(std::ostream& fout);
+
+  // Target dependency sorting
+  class TargetSet : public std::set<cmGeneratorTarget const*>
+  {
+  };
+  class TargetCompare
+  {
+    std::string First;
+
+  public:
+    TargetCompare(std::string const& first)
+      : First(first)
+    {
+    }
+    bool operator()(cmGeneratorTarget const* l,
+                    cmGeneratorTarget const* r) const;
+  };
+  class OrderedTargetDependSet;
 
 protected:
   void Generate() override;
@@ -100,35 +99,35 @@ protected:
                               std::vector<std::string>()) override;
 
 private:
-  void GetToolset(cmMakefile* mf, std::string& tsd, std::string& ts);
-  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<std::string>::const_iterator splitPathI,
-    std::vector<std::string>::const_iterator end, GhsMultiGpj::Types projType);
-  static std::string GetFileNameFromPath(std::string const& path);
-  void UpdateBuildFiles(const std::vector<cmGeneratorTarget*>& tgts);
-  bool IsTgtForBuild(const cmGeneratorTarget* tgt);
-
-  std::vector<cmGeneratedFileStream*> TargetSubProjects;
-  std::map<std::string, cmGeneratedFileStream*> TargetFolderBuildStreams;
-
-  std::vector<std::string> LibDirs;
-
-  bool OSDirRelative;
+  void GetToolset(cmMakefile* mf, std::string& tsd, const std::string& ts);
+
+  /* top-level project */
+  void OutputTopLevelProject(cmLocalGenerator* root,
+                             std::vector<cmLocalGenerator*>& generators);
+  void WriteTopLevelProject(std::ostream& fout, cmLocalGenerator* root,
+                            std::vector<cmLocalGenerator*>& generators);
+  void WriteMacros(std::ostream& fout);
+  void WriteHighLevelDirectives(std::ostream& fout);
+  void WriteSubProjects(std::ostream& fout, cmLocalGenerator* root,
+                        std::vector<cmLocalGenerator*>& generators);
+
+  std::string trimQuotes(std::string const& str);
+
   static const char* DEFAULT_BUILD_PROGRAM;
   static const char* DEFAULT_TOOLSET_ROOT;
 };
 
+class cmGlobalGhsMultiGenerator::OrderedTargetDependSet
+  : public std::multiset<cmTargetDepend,
+                         cmGlobalGhsMultiGenerator::TargetCompare>
+{
+  typedef std::multiset<cmTargetDepend,
+                        cmGlobalGhsMultiGenerator::TargetCompare>
+    derived;
+
+public:
+  typedef cmGlobalGenerator::TargetDependSet TargetDependSet;
+  OrderedTargetDependSet(TargetDependSet const&, std::string const& first);
+};
+
 #endif

+ 74 - 7
Source/cmLocalGhsMultiGenerator.cxx

@@ -7,6 +7,7 @@
 #include "cmGhsMultiTargetGenerator.h"
 #include "cmGlobalGhsMultiGenerator.h"
 #include "cmMakefile.h"
+#include "cmSourceFile.h"
 
 cmLocalGhsMultiGenerator::cmLocalGhsMultiGenerator(cmGlobalGenerator* gg,
                                                    cmMakefile* mf)
@@ -18,16 +19,82 @@ cmLocalGhsMultiGenerator::~cmLocalGhsMultiGenerator()
 {
 }
 
+std::string cmLocalGhsMultiGenerator::GetTargetDirectory(
+  cmGeneratorTarget const* target) const
+{
+  std::string dir;
+  dir += target->GetName();
+  dir += ".dir";
+  return dir;
+}
+
+void cmLocalGhsMultiGenerator::GenerateTargetsDepthFirst(
+  cmGeneratorTarget* target, std::vector<cmGeneratorTarget*>& remaining)
+{
+  if (target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+    return;
+  }
+  // Find this target in the list of remaining targets.
+  auto it = std::find(remaining.begin(), remaining.end(), target);
+  if (it == remaining.end()) {
+    // This target was already handled.
+    return;
+  }
+  // Remove this target from the list of remaining targets because
+  // we are handling it now.
+  *it = nullptr;
+
+  cmGhsMultiTargetGenerator tg(target);
+  tg.Generate();
+}
+
 void cmLocalGhsMultiGenerator::Generate()
 {
-  const std::vector<cmGeneratorTarget*>& tgts = this->GetGeneratorTargets();
+  std::vector<cmGeneratorTarget*> remaining = this->GetGeneratorTargets();
+  for (auto& t : remaining) {
+    if (t) {
+      GenerateTargetsDepthFirst(t, remaining);
+    }
+  }
+}
+
+void cmLocalGhsMultiGenerator::ComputeObjectFilenames(
+  std::map<cmSourceFile const*, std::string>& mapping,
+  cmGeneratorTarget const* gt)
+{
+  std::string dir_max;
+  dir_max += this->GetCurrentBinaryDirectory();
+  dir_max += "/";
+  dir_max += this->GetTargetDirectory(gt);
+  dir_max += "/";
+
+  // Count the number of object files with each name.  Note that
+  // filesystem may not be case sensitive.
+  std::map<std::string, int> counts;
+
+  for (auto const& si : mapping) {
+    cmSourceFile const* sf = si.first;
+    std::string objectNameLower = cmSystemTools::LowerCase(
+      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath()));
+    objectNameLower += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
+    counts[objectNameLower] += 1;
+  }
+
+  // For all source files producing duplicate names we need unique
+  // object name computation.
+  for (auto& si : mapping) {
+    cmSourceFile const* sf = si.first;
+    std::string objectName =
+      cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath());
+    objectName += this->GlobalGenerator->GetLanguageOutputExtension(*sf);
 
-  for (std::vector<cmGeneratorTarget*>::const_iterator l = tgts.begin();
-       l != tgts.end(); ++l) {
-    if ((*l)->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
-      continue;
+    if (counts[cmSystemTools::LowerCase(objectName)] > 1) {
+      const_cast<cmGeneratorTarget*>(gt)->AddExplicitObjectName(sf);
+      bool keptSourceExtension;
+      objectName = this->GetObjectFileNameWithoutTarget(*sf, dir_max,
+                                                        &keptSourceExtension);
+      cmsys::SystemTools::ReplaceString(objectName, "/", "_");
     }
-    cmGhsMultiTargetGenerator tg(*l);
-    tg.Generate();
+    si.second = objectName;
   }
 }

+ 11 - 0
Source/cmLocalGhsMultiGenerator.h

@@ -24,6 +24,17 @@ public:
    * Generate the makefile for this directory.
    */
   virtual void Generate();
+
+  std::string GetTargetDirectory(
+    cmGeneratorTarget const* target) const override;
+
+  void ComputeObjectFilenames(
+    std::map<cmSourceFile const*, std::string>& mapping,
+    cmGeneratorTarget const* gt = nullptr) override;
+
+private:
+  void GenerateTargetsDepthFirst(cmGeneratorTarget* target,
+                                 std::vector<cmGeneratorTarget*>& remaining);
 };
 
 #endif

+ 10 - 0
Source/cmState.cxx

@@ -596,6 +596,16 @@ bool cmState::UseWindowsVSIDE() const
   return this->WindowsVSIDE;
 }
 
+void cmState::SetGhsMultiIDE(bool ghsMultiIDE)
+{
+  this->GhsMultiIDE = ghsMultiIDE;
+}
+
+bool cmState::UseGhsMultiIDE() const
+{
+  return this->GhsMultiIDE;
+}
+
 void cmState::SetWatcomWMake(bool watcomWMake)
 {
   this->WatcomWMake = watcomWMake;

+ 3 - 0
Source/cmState.h

@@ -164,6 +164,8 @@ public:
   bool UseWindowsShell() const;
   void SetWindowsVSIDE(bool windowsVSIDE);
   bool UseWindowsVSIDE() const;
+  void SetGhsMultiIDE(bool ghsMultiIDE);
+  bool UseGhsMultiIDE() const;
   void SetWatcomWMake(bool watcomWMake);
   bool UseWatcomWMake() const;
   void SetMinGWMake(bool minGWMake);
@@ -222,6 +224,7 @@ private:
   bool IsGeneratorMultiConfig = false;
   bool WindowsShell = false;
   bool WindowsVSIDE = false;
+  bool GhsMultiIDE = false;
   bool WatcomWMake = false;
   bool MinGWMake = false;
   bool NMake = false;

+ 93 - 21
Tests/CMakeLists.txt

@@ -2260,32 +2260,104 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
   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")
-    add_test(NAME GhsMulti.duplicate_source_filenames
+    macro(add_test_GhsMulti test_name test_dir bin_sub_dir build_opts)
+      separate_arguments(_ghs_build_opts UNIX_COMMAND ${build_opts})
+      separate_arguments(_ghs_toolset_extra UNIX_COMMAND ${ghs_toolset_extra})
+      if(${ARGC} GREATER 4)
+        set(_ghs_test_command --test-command ${ARGN})
+      endif()
+      if(ghs_config_name STREQUAL "__default__")
+        set(_ghs_test_name "${test_name}")
+      else()
+        set(_ghs_test_name "${ghs_config_name}.${test_name}")
+      endif()
+      add_test(NAME GhsMulti.${_ghs_test_name}
         COMMAND ${CMAKE_CTEST_COMMAND}
         --build-and-test
-        "${CMake_SOURCE_DIR}/Tests/GhsMultiDuplicateSourceFilenames"
-        "${CMake_BINARY_DIR}/Tests/GhsMultiDuplicateSourceFilenames"
+        "${CMake_SOURCE_DIR}/Tests/GhsMulti/${test_dir}"
+        "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}/${test_dir}/${bin_sub_dir}"
         --build-generator "Green Hills MULTI"
-        --build-project ReturnNum
+        --build-project test
         --build-config $<CONFIGURATION>
-        --build-options -DGHS_PRIMARY_TARGET=arm_integrity.tgt
-        -DGHS_BSP_NAME="simarm"
+        --build-options ${ghs_target_arch} ${ghs_toolset_name} ${ghs_toolset_root} ${ghs_target_platform}
+          ${ghs_os_root} ${ghs_os_dir} ${ghs_bsp_name} ${_ghs_build_opts} ${_ghs_toolset_extra}
+          ${_ghs_test_command}
         )
-  endif ()
+        unset(_ghs_build_opts)
+        unset(_ghs_toolset_extra)
+        unset(_ghs_test_command)
+        unset(_ghs_test_name)
+    endmacro()
+    macro(add_test_GhsMulti_rename_install test_name)
+      add_test_GhsMulti( ${test_name} GhsMultiRenameInstall ${test_name}
+        "-DCMAKE_INSTALL_PREFIX=. -DRUN_TEST=${test_name}" ${CMAKE_CMAKE_COMMAND} -P ./cmake_install.cmake)
+    endmacro()
+    #unset ghs config variables
+    unset(ghs_config_name)
+    unset(ghs_target_arch)
+    unset(ghs_toolset_root)
+    unset(ghs_toolset_name)
+    unset(ghs_os_root)
+    unset(ghs_os_dir)
+    unset(ghs_target_platform)
+    unset(ghs_bsp_name)
+    unset(ghs_toolset_extra)
+    if(NOT CMake_TEST_GreenHillsMULTI_config)
+      #if list of config settings not defined then just run once as default
+      set(CMake_TEST_GreenHillsMULTI_config "__default__")
+    endif()
+    foreach(ghs_file IN LISTS CMake_TEST_GreenHillsMULTI_config)
+      # source GHS tools config file
+      if(NOT ghs_file STREQUAL "__default__")
+        if(IS_ABSOLUTE ${ghs_file})
+          include(${ghs_file})
+        else()
+          include(${CMAKE_BINARY_DIR}/${ghs_file})
+        endif()
+      endif()
+      if(NOT ghs_config_name)
+        set(ghs_config_name "__default__")
+      endif()
+      # test integrity build
+      if (NOT ghs_skip_integrity AND (NOT ghs_target_platform OR ghs_target_platform MATCHES "integrity"))
+        add_test_GhsMulti(integrityDDInt GhsMultiIntegrity/GhsMultiIntegrityDDInt "" "")
+        add_test_GhsMulti(integrityMonolith GhsMultiIntegrity/GhsMultiIntegrityMonolith "" "")
+        add_test_GhsMulti(integrityDD GhsMultiIntegrity/GhsMultiIntegrityDD "" "")
+      endif()
+      add_test_GhsMulti(duplicate_source_filenames GhsMultiDuplicateSourceFilenames "" "")
+      add_test_GhsMulti_rename_install(SINGLE_EXEC)
+      add_test_GhsMulti_rename_install(SINGLE_EXEC_RENAMED)
+      add_test_GhsMulti_rename_install(EXEC_AND_LIB)
+      add_test_GhsMulti(multiple_source_groups GhsMultiSrcGroups Default "")
+      add_test_GhsMulti(multiple_source_groups_folders GhsMultiSrcGroups PropFolders "-DTEST_PROP=ON")
+      add_test_GhsMulti(multiple_source_groups_all_folders GhsMultiSrcGroups AllFolders "-DGHS_NO_SOURCE_GROUP_FILE=ON")
+      add_test_GhsMulti(unsupported_targets GhsMultiUnsupportedTargets "" "")
+      add_test_GhsMulti(object_library GhsMultiObjectLibrary "" "")
+      add_test_GhsMulti(exclude GhsMultiExclude "" ""
+        ${CMAKE_CMAKE_COMMAND} -P ${CMake_SOURCE_DIR}/Tests/GhsMulti/GhsMultiExclude/verify.cmake)
+      add_test_GhsMulti(interface GhsMultiInterface "" "")
+      add_test_GhsMulti(transitive_link_test GhsMultiLinkTest TransitiveLink "-DRUN_TEST=NO_FLAGS")
+      add_test_GhsMulti(flags_link_test GhsMultiLinkTest FlagsCheck "-DRUN_TEST=CHECK_FLAGS")
+      add_test_GhsMulti(sub_link_test GhsMultiLinkTestSub "" "")
+      add_test_GhsMulti(multiple_projects GhsMultiMultipleProjects "" ""
+        ${CMAKE_CMAKE_COMMAND} -P ${CMake_SOURCE_DIR}/Tests/GhsMulti/GhsMultiMultipleProjects/verify.cmake)
+      add_test_GhsMulti(compiler_options_none GhsMultiCompilerOptions None "-DRUN_TEST=RELEASE_FLAGS -DRUN_TEST_BUILD_TYPE=\"\"")
+      add_test_GhsMulti(compiler_options_kernel GhsMultiCompilerOptions Kernel "-DRUN_TEST=KERNEL_FLAGS -DRUN_TEST_BUILD_TYPE=DEBUG")
+      add_test_GhsMulti(try_compile_copy GhsMultiCopyFile "" "")
+      add_test_GhsMulti(ghs_platform GhsMultiPlatform "" "")
+      list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/GhsMulti/${ghs_config_name}")
+      #unset ghs config variables
+      unset(ghs_config_name)
+      unset(ghs_target_arch)
+      unset(ghs_toolset_root)
+      unset(ghs_toolset_name)
+      unset(ghs_os_root)
+      unset(ghs_os_dir)
+      unset(ghs_target_platform)
+      unset(ghs_bsp_name)
+      unset(ghs_toolset_extra)
+    endforeach()
+  endif()
 
   if(tegra AND NOT "${CMake_SOURCE_DIR};${CMake_BINARY_DIR}" MATCHES " ")
     macro(add_test_VSNsightTegra name generator)

+ 0 - 4
Tests/GhsMulti/CMakeLists.txt

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

+ 92 - 0
Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt

@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+  ${CMAKE_CURRENT_BINARY_DIR}/src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test.c
+  DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/src
+)
+
+message("Building project")
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/build
+  ${CMAKE_CURRENT_BINARY_DIR}/src
+  test
+  CMAKE_FLAGS
+    -DRUN_TEST=${RUN_TEST}
+    -DCMAKE_BUILD_TYPE=${RUN_TEST_BUILD_TYPE}
+  OUTPUT_VARIABLE OUTPUT)
+
+message("Output from build:\n${OUTPUT}")
+if (RUN_TEST STREQUAL "RELEASE_FLAGS")
+  find_file (fileName test_none.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/build
+    ${CMAKE_CURRENT_BINARY_DIR}/build/test_none
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(opt "-unexpected_release_option")
+  string(FIND "${fileText}" "${opt}" opt_found)
+  if ( NOT opt_found EQUAL -1 )
+    message(SEND_ERROR "Release option found: ${opt}")
+  endif()
+else()
+  unset(fileName CACHE)
+  find_file (fileName K1.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/build
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K1
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(opt "-required-debug-option")
+  string(FIND "${fileText}" "${opt}" opt_found)
+  if ( opt_found EQUAL -1 )
+    message(SEND_ERROR "Missing debug option: ${opt}")
+  endif()
+
+  unset(fileName CACHE)
+  find_file (fileName K2.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/build
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K2
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(opt "-required-debug-option")
+  string(FIND "${fileText}" "${opt}" opt_found)
+  if ( opt_found EQUAL -1 )
+    message(SEND_ERROR "Missing debug option: ${opt}")
+  endif()
+
+  unset(fileName CACHE)
+  find_file (fileName K3.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/build
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K3
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(opt "-required-debug-option")
+  string(FIND "${fileText}" "${opt}" opt_found)
+  if ( opt_found EQUAL -1 )
+    message(SEND_ERROR "Missing debug option: ${opt}")
+  endif()
+
+  unset(fileName CACHE)
+  find_file (fileName K4.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/build
+    ${CMAKE_CURRENT_BINARY_DIR}/build/K4
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(opt "-required-debug-option")
+  string(FIND "${fileText}" "${opt}" opt_found)
+  if ( opt_found EQUAL -1 )
+    message(SEND_ERROR "Missing debug option: ${opt}")
+  endif()
+endif()

+ 32 - 0
Tests/GhsMulti/GhsMultiCompilerOptions/CMakeLists.txt.in

@@ -0,0 +1,32 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  add_link_options("-non_shared")
+endif()
+
+if(RUN_TEST STREQUAL "RELEASE_FLAGS")
+  #RELEASE flags used when CMAKE_BUILD_TYPE is undefined
+  string(APPEND CMAKE_C_FLAGS_RELEASE " -unexpected_release_option")
+  add_executable(test_none test.c)
+endif()
+
+if(RUN_TEST STREQUAL "KERNEL_FLAGS")
+  #DEBUG flag missing when -kernel is added as a compile option
+  string(APPEND CMAKE_C_FLAGS_DEBUG " -required-debug-option")
+
+  add_executable(K1 test.c)
+
+  add_executable(K2 test.c)
+  target_compile_options(K2 PRIVATE -kernel)
+
+  add_executable(K3 test.c)
+  target_compile_options(K3 PRIVATE -kernel=fast)
+
+  add_executable(K4 test.c)
+  target_link_options(K4 PRIVATE -kernel)
+endif()

+ 4 - 0
Tests/GhsMulti/GhsMultiCompilerOptions/test.c

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

+ 30 - 0
Tests/GhsMulti/GhsMultiCopyFile/CMakeLists.txt

@@ -0,0 +1,30 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/build
+  ${CMAKE_CURRENT_SOURCE_DIR}/test.c
+  OUTPUT_VARIABLE OUTPUT
+  COPY_FILE "${CMAKE_CURRENT_BINARY_DIR}/test_library"
+)
+
+message(STATUS "Output from build:\n${OUTPUT}")
+
+if(NOT RESULT)
+  message(SEND_ERROR "try_compile() failed")
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/test_library")
+  if (IS_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_library")
+    message(SEND_ERROR "library is folder !")
+  else()
+    message(STATUS "library seems okay")
+  endif()
+else()
+  message(SEND_ERROR "library is not found !")
+endif()

+ 4 - 0
Tests/GhsMulti/GhsMultiCopyFile/test.c

@@ -0,0 +1,4 @@
+int lib(int x)
+{
+  return -x;
+}

+ 5 - 3
Tests/GhsMultiDuplicateSourceFilenames/CMakeLists.txt → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/CMakeLists.txt

@@ -1,15 +1,17 @@
 cmake_minimum_required(VERSION 3.5)
-project(demo C)
+project(test C)
 
 add_library(libdemo
   test.c
+  testCase.c
   subfolder_test.c
   subfolder_test_0.c
   "subfolder/test.c"
+  subfolder/testcase.c
 )
 
 add_executable(demo main.c)
 target_link_libraries(demo libdemo)
-if(GHSMULTI)
-    target_compile_options(demo PUBLIC "-non_shared")
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  target_link_options(demo PRIVATE "-non_shared")
 endif()

+ 4 - 0
Tests/GhsMultiDuplicateSourceFilenames/main.c → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/main.c

@@ -2,6 +2,8 @@ int test_a(void);
 int test_b(void);
 int test_c(void);
 int test_d(void);
+int test_e(void);
+int test_f(void);
 
 int main(int argc, char* argv[])
 {
@@ -9,5 +11,7 @@ int main(int argc, char* argv[])
   test_b();
   test_c();
   test_d();
+  test_e();
+  test_f();
   return 0;
 }

+ 0 - 1
Tests/GhsMultiDuplicateSourceFilenames/subfolder/test.c → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/test.c

@@ -1,4 +1,3 @@
-
 int test_b()
 {
   return 2;

+ 4 - 0
Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder/testcase.c

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

+ 0 - 1
Tests/GhsMultiDuplicateSourceFilenames/subfolder_test.c → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test.c

@@ -1,4 +1,3 @@
-
 int test_c()
 {
   return 1;

+ 0 - 1
Tests/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/subfolder_test_0.c

@@ -1,4 +1,3 @@
-
 int test_d()
 {
   return 1;

+ 0 - 1
Tests/GhsMultiDuplicateSourceFilenames/test.c → Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/test.c

@@ -1,4 +1,3 @@
-
 int test_a()
 {
   return 1;

+ 4 - 0
Tests/GhsMulti/GhsMultiDuplicateSourceFilenames/testCase.c

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

+ 17 - 0
Tests/GhsMulti/GhsMultiExclude/CMakeLists.txt

@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+set_target_properties( lib1 PROPERTIES EXCLUDE_FROM_ALL yes )
+
+add_library(lib2 EXCLUDE_FROM_ALL lib1.c)
+
+add_executable(exe1 exe1.c)

+ 4 - 0
Tests/GhsMulti/GhsMultiExclude/exe1.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiExclude/lib1.c

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

+ 54 - 0
Tests/GhsMulti/GhsMultiExclude/verify.cmake

@@ -0,0 +1,54 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#test project was generated
+unset(fileName CACHE)
+find_file (fileName lib1.gpj
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}/lib1
+  )
+
+if (fileName)
+  message("Found target lib1: ${fileName}")
+else()
+  message(SEND_ERROR "Could not find target lib1: ${fileName}")
+endif()
+
+#test project was built
+unset(fileName CACHE)
+find_file (fileName lib1.a
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}/lib1
+  )
+
+if (fileName)
+  message(SEND_ERROR "Found target lib1: ${fileName}")
+else()
+  message("Could not find target lib1: ${fileName}")
+endif()
+
+#test project was generated
+unset(fileName CACHE)
+find_file (fileName lib2.gpj
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}/lib2
+  )
+
+if (fileName)
+  message("Found target lib2 ${fileName}")
+else()
+  message(SEND_ERROR "Could not find target lib2: ${fileName}")
+endif()
+
+#test project was built
+unset(fileName CACHE)
+find_file (fileName lib2.a
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}/lib2
+  )
+
+if (fileName)
+  message(SEND_ERROR "Found target lib2: ${fileName}")
+else()
+  message("Could not find target lib2: ${fileName}")
+endif()

+ 19 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/CMakeLists.txt

@@ -0,0 +1,19 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_link_options("-non_shared")
+
+# create virtual AS
+add_executable(vas exe.c)
+target_link_libraries(vas lib)
+add_library(lib func.c)
+
+# create dynamic download INTEGRITY application
+add_executable(dynamic)
+set_target_properties(dynamic PROPERTIES ghs_integrity_app ON)
+target_compile_options(dynamic PRIVATE -dynamic)
+add_dependencies(dynamic vas)

+ 5 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/exe.c

@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+  return func();
+}

+ 4 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDD/func.c

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

+ 1 - 1
Tests/GhsMulti/ReturnNum/App/CMakeLists.txt → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/CMakeLists.txt

@@ -1,4 +1,4 @@
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
 add_executable(App Main.c)
+target_include_directories(App PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../Lib)
 target_link_libraries(App Lib)
 target_compile_options(App PUBLIC "-non_shared")

+ 0 - 0
Tests/GhsMulti/ReturnNum/App/Main.c → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/App/Main.c


+ 3 - 0
Tests/GhsMulti/ReturnNum/CMakeLists.txt → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/CMakeLists.txt

@@ -1,3 +1,6 @@
+cmake_minimum_required(VERSION 3.1)
+project(test)
+
 add_subdirectory(App)
 add_subdirectory(Int)
 add_subdirectory(Lib)

+ 1 - 1
Tests/GhsMulti/ReturnNum/Int/AppDD.int → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/AppDD.int

@@ -7,6 +7,6 @@ Kernel
 EndKernel
 
 AddressSpace        App
-  Filename      "App/App.as"
+  Filename          "App/App"
   Language C
 EndAddressSpace

+ 1 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Int/CMakeLists.txt

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

+ 1 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/CMakeLists.txt

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

+ 0 - 0
Tests/GhsMulti/ReturnNum/Lib/HelperFun.c → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.c


+ 0 - 0
Tests/GhsMulti/ReturnNum/Lib/HelperFun.h → Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityDDInt/Lib/HelperFun.h


+ 20 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/CMakeLists.txt

@@ -0,0 +1,20 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+add_link_options("-non_shared")
+
+project(test C)
+
+# create virtual AS
+add_executable(vas exe.c)
+target_link_libraries(vas lib)
+add_library(lib func.c)
+
+# create kernel
+add_executable(kernel kernel.c)
+target_link_options(kernel PRIVATE -kernel)
+
+# create monolith INTEGRITY application
+add_executable(monolith test.int)

+ 5 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/exe.c

@@ -0,0 +1,5 @@
+extern int func(void);
+int main(void)
+{
+  return func();
+}

+ 5 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/func.c

@@ -0,0 +1,5 @@
+
+int func(void)
+{
+  return 2;
+}

+ 15 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/kernel.c

@@ -0,0 +1,15 @@
+#include "INTEGRITY.h"
+#include "boottable.h"
+
+void main()
+{
+  Exit(0);
+}
+
+/* This global table will be filled in during the Integrate phase with */
+/* information about the AddressSpaces, Tasks, and Objects that are to be */
+/* created.  If you do not plan to use Integrate, you may omit this file from
+ */
+/* the kernel, and the boot table code will then not be included. */
+
+GlobalTable TheGlobalTable = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };

+ 8 - 0
Tests/GhsMulti/GhsMultiIntegrity/GhsMultiIntegrityMonolith/test.int

@@ -0,0 +1,8 @@
+Kernel
+  Filename        kernel
+EndKernel
+
+AddressSpace      App
+  Filename        vas
+  Language C
+EndAddressSpace

+ 8 - 0
Tests/GhsMulti/GhsMultiInterface/CMakeLists.txt

@@ -0,0 +1,8 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_library(iface INTERFACE)

+ 92 - 0
Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt

@@ -0,0 +1,92 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+message("Copy project")
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt.in
+  ${CMAKE_CURRENT_BINARY_DIR}/link_src/CMakeLists.txt COPYONLY)
+
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/exe1.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/exe1.h
+  ${CMAKE_CURRENT_SOURCE_DIR}/func2.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/func3.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/func4.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/func5.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/func6.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/func7.c
+  DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/link_src
+)
+
+message("Building project")
+try_compile(RESULT
+  ${CMAKE_CURRENT_BINARY_DIR}/link_build
+  ${CMAKE_CURRENT_BINARY_DIR}/link_src
+  test
+  CMAKE_FLAGS
+    -DRUN_TEST=${RUN_TEST}
+    -DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}
+  OUTPUT_VARIABLE OUTPUT)
+
+message("Output from build:\n${OUTPUT}")
+if (RUN_TEST STREQUAL "NO_FLAGS")
+  if(NOT RESULT)
+    message(SEND_ERROR "Could not build test project (1)!")
+  endif()
+else()
+  unset(fileName CACHE)
+  find_file(fileName exe1.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/exe1
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(expected_flags
+    -add-link-options1 -add-link-options2
+    link_directories_used1 link_directories_used2 "c:/absolute"
+    link_libraries_used1 link_libraries_used2
+    -lcsl1 csl2
+    -clinkexe1 -clinkexe2
+    -special-lib2-public-link)
+  foreach(opt IN LISTS expected_flags)
+    string(FIND "${fileText}" "${opt}" opt_found)
+    if ( opt_found EQUAL -1 )
+      message(SEND_ERROR "Could not find: ${opt}")
+    endif()
+  endforeach()
+
+  unset(fileName CACHE)
+  find_file (fileName lib1.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib1
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(expected_flags
+    -clinkexeA1 -clinkexeA2
+    -static-lib-flags1 -static-lib-flags2)
+  foreach(opt IN LISTS expected_flags)
+    string(FIND "${fileText}" "${opt}" opt_found)
+    if (opt_found EQUAL -1)
+      message(SEND_ERROR "Could not find: ${opt}")
+    endif()
+  endforeach()
+
+  unset(fileName CACHE)
+  find_file (fileName lib2.gpj
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build
+    ${CMAKE_CURRENT_BINARY_DIR}/link_build/lib2
+    )
+  message("Parsing project file: ${fileName}")
+  file(STRINGS ${fileName} fileText)
+  set(expected_flags
+    -clinkexeA1 -clinkexeA2)
+  foreach(opt IN LISTS expected_flags)
+    string(FIND "${fileText}" "${opt}" opt_found)
+    if ( opt_found EQUAL -1 )
+      message(SEND_ERROR "Could not find: ${opt}")
+    endif()
+  endforeach()
+endif()

+ 43 - 0
Tests/GhsMulti/GhsMultiLinkTest/CMakeLists.txt.in

@@ -0,0 +1,43 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  add_link_options("-non_shared")
+endif()
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+  add_link_options(-add-link-options1 -add-link-options2)
+  link_directories(link_directories_used1 link_directories_used2 "c:/absolute")
+  link_libraries(link_libraries_used1 link_libraries_used2 )
+  set( CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lcsl1 csl2" )
+  set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -clinkexe1 -clinkexe2")
+endif()
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+  set_property(TARGET exe1 APPEND_STRING PROPERTY LINK_FLAGS "--link-flag-prop1 --link-flag-prop2")
+  set_property(TARGET exe1 APPEND PROPERTY LINK_OPTIONS --link-opt-prop1 --link-opt-prop2)
+endif()
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+  set(CMAKE_STATIC_LINKER_FLAGS ${CMAKE_STATIC_LINKER_FLAGS} "-clinkexeA1 -clinkexeA2")
+endif()
+
+add_library(lib1 STATIC func2.c func3.c func4.c)
+target_link_libraries(lib1 lib2)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+  set_property(TARGET lib1 APPEND_STRING PROPERTY STATIC_LIBRARY_FLAGS "-static-lib-flags1 -static-lib-flags2")
+endif()
+
+add_library(lib2 STATIC func5.c func6.c func7.c)
+
+if(RUN_TEST STREQUAL "CHECK_FLAGS")
+  target_link_options(lib2 PUBLIC -special-lib2-public-link)
+endif()

+ 6 - 0
Tests/GhsMulti/GhsMultiLinkTest/exe1.c

@@ -0,0 +1,6 @@
+#include "exe1.h"
+
+int main(void)
+{
+  return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}

+ 6 - 0
Tests/GhsMulti/GhsMultiLinkTest/exe1.h

@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func2.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func3.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func4.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func5.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func6.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTest/func7.c

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

+ 9 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/CMakeLists.txt

@@ -0,0 +1,9 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_subdirectory(sub_exe)
+add_subdirectory(sub_lib)

+ 12 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/CMakeLists.txt

@@ -0,0 +1,12 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  target_link_options(exe1 PRIVATE "-non_shared")
+endif()

+ 6 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.c

@@ -0,0 +1,6 @@
+#include "exe1.h"
+
+int main(void)
+{
+  return func2a() + func3a() + func4a() + func5a() + func6a() + func7a();
+}

+ 6 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_exe/exe1.h

@@ -0,0 +1,6 @@
+extern int func2a(void);
+extern int func3a(void);
+extern int func4a(void);
+extern int func5a(void);
+extern int func6a(void);
+extern int func7a(void);

+ 7 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/CMakeLists.txt

@@ -0,0 +1,7 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+add_library(lib1 STATIC func2.c func3.c func4.c)
+target_link_libraries(lib1 lib2)
+
+add_library(lib2 STATIC func5.c func6.c func7.c)

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func2.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func3.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func4.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func5.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func6.c

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

+ 4 - 0
Tests/GhsMulti/GhsMultiLinkTestSub/sub_lib/func7.c

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

+ 17 - 0
Tests/GhsMulti/GhsMultiMultipleProjects/CMakeLists.txt

@@ -0,0 +1,17 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(test C)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GHS")
+  add_link_options("-non_shared")
+endif()
+
+add_library(lib1 lib1.c)
+add_executable(exe1 exe1.c)
+target_link_libraries(exe1 lib1)
+
+add_subdirectory(sub)
+add_subdirectory(sub2 examples EXCLUDE_FROM_ALL)

+ 5 - 0
Tests/GhsMulti/GhsMultiMultipleProjects/exe1.c

@@ -0,0 +1,5 @@
+extern int lib1_func(void);
+int main(void)
+{
+  return lib1_func();
+}

+ 4 - 0
Tests/GhsMulti/GhsMultiMultipleProjects/lib1.c

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

Some files were not shown because too many files changed in this diff