Pārlūkot izejas kodu

CUDA: Properly de-duplicate libs when doing device linking

The nvcc device linker is designed so that each static library
with device symbols only needs to be listed once as it doesn't
care about link order. If you provide the same static library
multiple times it will error out. To make sure this occurs
we find the unique set of link items.
Robert Maynard 7 gadi atpakaļ
vecāks
revīzija
fd0523a215

+ 17 - 5
Source/cmLinkLineDeviceComputer.cxx

@@ -3,7 +3,9 @@
 
 
 #include "cmLinkLineDeviceComputer.h"
 #include "cmLinkLineDeviceComputer.h"
 
 
+#include <set>
 #include <sstream>
 #include <sstream>
+#include <utility>
 
 
 #include "cmAlgorithms.h"
 #include "cmAlgorithms.h"
 #include "cmComputeLinkInformation.h"
 #include "cmComputeLinkInformation.h"
@@ -28,6 +30,12 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
 {
 {
   // Write the library flags to the build rule.
   // Write the library flags to the build rule.
   std::ostringstream fout;
   std::ostringstream fout;
+
+  // Generate the unique set of link items when device linking.
+  // The nvcc device linker is designed so that each static library
+  // with device symbols only needs to be listed once as it doesn't
+  // care about link order.
+  std::set<std::string> emitted;
   typedef cmComputeLinkInformation::ItemVector ItemVector;
   typedef cmComputeLinkInformation::ItemVector ItemVector;
   ItemVector const& items = cli.GetItems();
   ItemVector const& items = cli.GetItems();
   std::string config = cli.GetConfig();
   std::string config = cli.GetConfig();
@@ -50,20 +58,24 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
       }
       }
     }
     }
 
 
+    std::string out;
     if (item.IsPath) {
     if (item.IsPath) {
       // nvcc understands absolute paths to libraries ending in '.a' should
       // nvcc understands absolute paths to libraries ending in '.a' should
       // be passed to nvlink.  Other extensions like '.so' or '.dylib' are
       // be passed to nvlink.  Other extensions like '.so' or '.dylib' are
       // rejected by the nvcc front-end even though nvlink knows to ignore
       // rejected by the nvcc front-end even though nvlink knows to ignore
       // them.  Bypass the front-end via '-Xnvlink'.
       // them.  Bypass the front-end via '-Xnvlink'.
       if (!cmHasLiteralSuffix(item.Value, ".a")) {
       if (!cmHasLiteralSuffix(item.Value, ".a")) {
-        fout << "-Xnvlink ";
+        out += "-Xnvlink ";
       }
       }
-      fout << this->ConvertToOutputFormat(
-        this->ConvertToLinkReference(item.Value));
+      out +=
+        this->ConvertToOutputFormat(this->ConvertToLinkReference(item.Value));
     } else {
     } else {
-      fout << item.Value;
+      out += item.Value;
+    }
+
+    if (emitted.insert(out).second) {
+      fout << out << " ";
     }
     }
-    fout << " ";
   }
   }
 
 
   if (!stdLibString.empty()) {
   if (!stdLibString.empty()) {

+ 1 - 2
Tests/CudaOnly/CircularLinkLine/CMakeLists.txt

@@ -16,8 +16,7 @@ add_executable(CudaOnlyCircularLinkLine main.cu)
 
 
 target_link_libraries(CUDACircularDeviceLinking1 PUBLIC CUDACircularDeviceLinking2)
 target_link_libraries(CUDACircularDeviceLinking1 PUBLIC CUDACircularDeviceLinking2)
 target_link_libraries(CUDACircularDeviceLinking2 PUBLIC CUDACircularDeviceLinking3)
 target_link_libraries(CUDACircularDeviceLinking2 PUBLIC CUDACircularDeviceLinking3)
-#FIXME: complete the loop once supported
-#target_link_libraries(CUDACircularDeviceLinking3 PUBLIC CUDACircularDeviceLinking1)
+target_link_libraries(CUDACircularDeviceLinking3 PUBLIC CUDACircularDeviceLinking1)
 
 
 target_link_libraries(CudaOnlyCircularLinkLine PRIVATE CUDACircularDeviceLinking3)
 target_link_libraries(CudaOnlyCircularLinkLine PRIVATE CUDACircularDeviceLinking3)