From 1703a6d2c46cc7981dd80bd18d7c2e82ec5d9f82 Mon Sep 17 00:00:00 2001
From: Geoff Viola <geoffrey.viola@asirobots.com>
Date: Sun, 24 Apr 2016 13:47:48 -0600
Subject: GHS: Fix handling of duplicate source filenames (#16046)

Green Hills MULTI project files must specify explicitly distinct object
file names for source files with the same name.
---
 Source/cmGhsMultiTargetGenerator.cxx               | 42 ++++++++++++++++++++++
 Source/cmGhsMultiTargetGenerator.h                 |  2 ++
 Tests/CMakeLists.txt                               | 11 ++++++
 .../CMakeLists.txt                                 | 10 ++++++
 Tests/GhsMultiDuplicateSourceFilenames/main.c      |  9 +++++
 .../subfolder/test.c                               |  5 +++
 Tests/GhsMultiDuplicateSourceFilenames/test.c      |  5 +++
 7 files changed, 84 insertions(+)
 create mode 100644 Tests/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
 create mode 100644 Tests/GhsMultiDuplicateSourceFilenames/main.c
 create mode 100644 Tests/GhsMultiDuplicateSourceFilenames/subfolder/test.c
 create mode 100644 Tests/GhsMultiDuplicateSourceFilenames/test.c

diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index 1f17f8f..12e2eee 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -481,9 +481,46 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper(
     }
 }
 
+std::map<const cmSourceFile *, std::string>
+cmGhsMultiTargetGenerator::GetObjectNames(
+    const std::vector<cmSourceFile *> &objectSources)
+{
+  bool found_duplicate = false;
+  std::set<std::string> filenames;
+  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);
+    if (filenames.end() != filenames.find(lower_filename))
+      {
+      found_duplicate = true;
+      }
+    filenames.insert(lower_filename);
+    }
+
+  std::map<const cmSourceFile *, std::string> objectNames;
+  if (found_duplicate)
+    {
+    for(std::vector<cmSourceFile *>::const_iterator
+        sf = objectSources.begin(); sf != objectSources.end(); ++sf)
+      {
+      std::string full_filename = (*sf)->GetFullPath();
+      cmsys::SystemTools::ReplaceString(full_filename, ":/", "_");
+      cmsys::SystemTools::ReplaceString(full_filename, "/", "_");
+      objectNames[*sf] = full_filename;
+      }
+    }
+
+  return objectNames;
+}
+
 void cmGhsMultiTargetGenerator::WriteSources(
   std::vector<cmSourceFile *> const &objectSources)
 {
+  std::map<const cmSourceFile *, std::string> objectNames =
+    cmGhsMultiTargetGenerator::GetObjectNames(objectSources);
   for (std::vector<cmSourceFile *>::const_iterator si = objectSources.begin();
        si != objectSources.end(); ++si)
     {
@@ -515,6 +552,11 @@ void cmGhsMultiTargetGenerator::WriteSources(
         "bsp" != (*si)->GetExtension())
       {
       this->WriteObjectLangOverride(this->FolderBuildStreams[sgPath], (*si));
+      if (objectNames.end() != objectNames.find(*si))
+        {
+        *this->FolderBuildStreams[sgPath] << "    -o \"" <<
+          objectNames.find(*si)->second << ".o\"" << std::endl;
+        }
 
       this->WriteObjectDir(this->FolderBuildStreams[sgPath],
                            this->AbsBuildFilePath + sgPath);
diff --git a/Source/cmGhsMultiTargetGenerator.h b/Source/cmGhsMultiTargetGenerator.h
index e85e412..3a13600 100644
--- a/Source/cmGhsMultiTargetGenerator.h
+++ b/Source/cmGhsMultiTargetGenerator.h
@@ -88,6 +88,8 @@ private:
   WriteCustomCommandsHelper(std::vector<cmCustomCommand> const &commandsSet,
                             cmTarget::CustomCommandType commandType);
   void WriteSources(std::vector<cmSourceFile *> const &objectSources);
+  static std::map<const cmSourceFile *, std::string>
+  GetObjectNames(const std::vector<cmSourceFile *> &objectSources);
   static void WriteObjectLangOverride(cmGeneratedFileStream *fileStream,
                                       cmSourceFile *sourceFile);
   static void WriteObjectDir(cmGeneratedFileStream *fileStream,
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index 8a256bf..2db5ded 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2103,6 +2103,17 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     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
+        COMMAND ${CMAKE_CTEST_COMMAND}
+        --build-and-test
+        "${CMake_SOURCE_DIR}/Tests/GhsMultiDuplicateSourceFilenames"
+        "${CMake_BINARY_DIR}/Tests/GhsMultiDuplicateSourceFilenames"
+        --build-generator "Green Hills MULTI"
+        --build-project ReturnNum
+        --build-config $<CONFIGURATION>
+        --build-options -DGHS_PRIMARY_TARGET="arm_integrity.tgt"
+        -DGHS_BSP_NAME="simarm"
+        )
   endif ()
 
   if(tegra AND NOT "${CMake_SOURCE_DIR};${CMake_BINARY_DIR}" MATCHES " ")
diff --git a/Tests/GhsMultiDuplicateSourceFilenames/CMakeLists.txt b/Tests/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
new file mode 100644
index 0000000..ffdb582
--- /dev/null
+++ b/Tests/GhsMultiDuplicateSourceFilenames/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.5)
+project(demo C)
+
+add_library(libdemo test.c subfolder/test.c)
+
+add_executable(demo main.c)
+target_link_libraries(demo libdemo)
+if(GHSMULTI)
+    target_compile_options(demo PUBLIC "-non_shared")
+endif()
diff --git a/Tests/GhsMultiDuplicateSourceFilenames/main.c b/Tests/GhsMultiDuplicateSourceFilenames/main.c
new file mode 100644
index 0000000..2779d68
--- /dev/null
+++ b/Tests/GhsMultiDuplicateSourceFilenames/main.c
@@ -0,0 +1,9 @@
+int test_a(void);
+int test_b(void);
+
+int main(int argc, char *argv[])
+{
+    test_a();
+    test_b();
+    return 0;
+}
diff --git a/Tests/GhsMultiDuplicateSourceFilenames/subfolder/test.c b/Tests/GhsMultiDuplicateSourceFilenames/subfolder/test.c
new file mode 100644
index 0000000..e1372b9
--- /dev/null
+++ b/Tests/GhsMultiDuplicateSourceFilenames/subfolder/test.c
@@ -0,0 +1,5 @@
+
+int test_b()
+{
+    return 2;
+}
diff --git a/Tests/GhsMultiDuplicateSourceFilenames/test.c b/Tests/GhsMultiDuplicateSourceFilenames/test.c
new file mode 100644
index 0000000..60286dd
--- /dev/null
+++ b/Tests/GhsMultiDuplicateSourceFilenames/test.c
@@ -0,0 +1,5 @@
+
+int test_a()
+{
+    return 1;
+}
-- 
cgit v0.12