cros_setup_toolchains: handle duplicate source libs better

If our ELF parsing logic tries to copy different libs to the same
path under lib/, we'll get random misbehavior.  Detect & show an
error when this happens so we know what's going on.

To mitigate the major existing issue, we ignore libopcodes for
copying in files.  This should be safe as the only libs it needs
(libc & libbfd) are pulled in by other ELFs already.

We can't make this logic fatal just yet as there's another error
with libc++ and the x86_64-cros-linux-gnu toolchain.  Fortunately
that's not as big of an issue because the ABIs are compatible.
We still want to fix it, but it's not a P0 issue.

BUG=chromium:917193
TEST=`cros_setup_toolchains --create-packages` doesn't hit libbfd collisions anymore

Change-Id: I7f6382598524e67a5e77aeaeb32fb94fc41643af
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1965955
Reviewed-by: Luis Lozano <llozano@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
diff --git a/scripts/cros_setup_toolchains.py b/scripts/cros_setup_toolchains.py
index 0a295b4..fe0c280 100644
--- a/scripts/cros_setup_toolchains.py
+++ b/scripts/cros_setup_toolchains.py
@@ -1023,6 +1023,7 @@
   libdir = os.path.join(output_dir, 'lib')
   osutils.SafeMakedirs(libdir)
   donelibs = set()
+  basenamelibs = set()
   glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
   for elf in elfs:
     e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
@@ -1041,15 +1042,31 @@
         link = sym_paths[elf]
         GeneratePathWrapper(output_dir, link, elf)
 
-    for lib, lib_data in e['libs'].items():
-      if lib in donelibs:
-        continue
+    # TODO(crbug.com/917193): Drop this hack once libopcodes linkage is fixed.
+    if os.path.basename(elf).startswith('libopcodes-'):
+      continue
 
+    for lib, lib_data in e['libs'].items():
       src = path = lib_data['path']
       if path is None:
         logging.warning('%s: could not locate %s', elf, lib)
         continue
-      donelibs.add(lib)
+
+      # No need to try and copy the same source lib multiple times.
+      if path in donelibs:
+        continue
+      donelibs.add(path)
+
+      # Die if we try to normalize different source libs with the same basename.
+      if lib in basenamelibs:
+        logging.error('Multiple sources detected for %s:\n  new: %s\n  old: %s',
+                      os.path.join('/lib', lib), path,
+                      ' '.join(x for x in donelibs
+                               if x != path and os.path.basename(x) == lib))
+        # TODO(crbug.com/917193): Make this fatal.
+        # cros_build_lib.Die('Unable to resolve lib conflicts')
+        continue
+      basenamelibs.add(lib)
 
       # Needed libs are the SONAME, but that is usually a symlink, not a
       # real file.  So link in the target rather than the symlink itself.