Repository: conan-io/conan

Issue:
[bug] 1.8.0 introduces a misleading warning in tools.collect_libs()
After updating to 1.8.0 today (thank you for such frequent releases 👍 ), I noticed several warnings when `conan install`ing recipes that depends on our custom boost recipe.

```
boost/1.67@com/stable: WARN: Library 'boost_atomic' already found in a previous 'conanfile.cpp_info.libdirs' folder
boost/1.67@com/stable: WARN: Library 'boost_chrono' already found in a previous 'conanfile.cpp_info.libdirs' folder
...
```

Which corresponds to the following addition to the source:
https://github.com/conan-io/conan/blob/a20c0f5ca432192596af6b34eccf56c1f5e20904/conans/client/tools/files.py#L308-L310

We see the intention here, but in our situation this message is misleading: it would imply there are several `conanfile.cpp_info.libdirs`, although there is actually only one element in this collection.

The message is in fact triggered because in this single `conanfile.cpp_info.libdirs` directory, each library is present with two different extensions (static and dynamic libraries).


Discussion:
If I understood it correctly, the warning is correct, as a warning, but the message is misleading. It seems that you have a **.a** and **.so** in the same "lib" folder, which is problematic for linking via the collected ``tool.collect_libs()`` because it is not deterministic which one will be used.

What do you think the warning message should be? Something like "I have found both .a and .so libraries"?
Hi @memsharded, thank you for taking a look at this!

For the message, it depends what you want to do? If you distinguish between the two situations (the same file in different folders, and the same basename in several files of the same folder), an explicit message like you propose could work well!

If you don't want to add logic to make this distinction, something generic like 

> 'boost_atomic' was either found in a previous 'conanfile.cpp_info.libdirs' folder, or appears several times with different file extensions

could also work, what do you think?
Yes, that is reasonable, lets do it for the next minor 1.8.2. Thanks for the feeback!

Resolving patch:
diff --git a/conans/client/tools/files.py b/conans/client/tools/files.py
--- a/conans/client/tools/files.py
+++ b/conans/client/tools/files.py
@@ -306,8 +306,9 @@ def collect_libs(conanfile, folder=None):
                 if ext != ".lib" and name.startswith("lib"):
                     name = name[3:]
                 if name in result:
-                    conanfile.output.warn("Library '%s' already found in a previous "
-                                          "'conanfile.cpp_info.libdirs' folder" % name)
+                    conanfile.output.warn("Library '%s' was either already found in a previous "
+                                          "'conanfile.cpp_info.libdirs' folder or appears several "
+                                          "times with a different file extension" % name)
                 else:
                     result.append(name)
     return result
diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -180,9 +180,9 @@ def user(self):
                                      "but self.user is used in conanfile")
         return self._conan_user
 
-    def collect_libs(self, folder="lib"):
-        self.output.warn("Use 'self.collect_libs' is deprecated, "
-                         "use tools.collect_libs(self) instead")
+    def collect_libs(self, folder=None):
+        self.output.warn("'self.collect_libs' is deprecated, "
+                         "use 'tools.collect_libs(self)' instead")
         return tools.collect_libs(self, folder=folder)
 
     @property


Test patch:
diff --git a/conans/test/util/tools_test.py b/conans/test/util/tools_test.py
--- a/conans/test/util/tools_test.py
+++ b/conans/test/util/tools_test.py
@@ -1863,6 +1863,7 @@ def test_clone_subfolder(self):
 
 
 class CollectLibTestCase(unittest.TestCase):
+
     def collect_libs_test(self):
         conanfile = ConanFileMock()
         # Without package_folder
@@ -1910,8 +1911,9 @@ def collect_libs_test(self):
         conanfile.cpp_info.libdirs = ["lib", "custom_folder"]
         result = tools.collect_libs(conanfile)
         self.assertEqual(["mylib"], result)
-        self.assertIn("Library 'mylib' already found in a previous 'conanfile.cpp_info.libdirs' "
-                      "folder", conanfile.output)
+        self.assertIn("Library 'mylib' was either already found in a previous "
+                      "'conanfile.cpp_info.libdirs' folder or appears several times with a "
+                      "different file extension", conanfile.output)
 
         # Warn lib folder does not exist with correct result
         conanfile = ConanFileMock()
@@ -1926,3 +1928,68 @@ def collect_libs_test(self):
         self.assertIn("WARN: Lib folder doesn't exist, can't collect libraries: %s"
                       % no_folder_path, conanfile.output)
 
+    def self_collect_libs_test(self):
+        conanfile = ConanFileMock()
+        # Without package_folder
+        conanfile.package_folder = None
+        result = conanfile.collect_libs()
+        self.assertEqual([], result)
+        self.assertIn("'self.collect_libs' is deprecated, use 'tools.collect_libs(self)' instead",
+                      conanfile.output)
+
+        # Default behavior
+        conanfile.package_folder = temp_folder()
+        mylib_path = os.path.join(conanfile.package_folder, "lib", "mylib.lib")
+        save(mylib_path, "")
+        conanfile.cpp_info = CppInfo("")
+        result = conanfile.collect_libs()
+        self.assertEqual(["mylib"], result)
+
+        # Custom folder
+        customlib_path = os.path.join(conanfile.package_folder, "custom_folder", "customlib.lib")
+        save(customlib_path, "")
+        result = conanfile.collect_libs(folder="custom_folder")
+        self.assertEqual(["customlib"], result)
+
+        # Custom folder doesn't exist
+        result = conanfile.collect_libs(folder="fake_folder")
+        self.assertEqual([], result)
+        self.assertIn("Lib folder doesn't exist, can't collect libraries:", conanfile.output)
+
+        # Use cpp_info.libdirs
+        conanfile.cpp_info.libdirs = ["lib", "custom_folder"]
+        result = conanfile.collect_libs()
+        self.assertEqual(["mylib", "customlib"], result)
+
+        # Custom folder with multiple libdirs should only collect from custom folder
+        self.assertEqual(["lib", "custom_folder"], conanfile.cpp_info.libdirs)
+        result = conanfile.collect_libs(folder="custom_folder")
+        self.assertEqual(["customlib"], result)
+
+        # Warn same lib different folders
+        conanfile = ConanFileMock()
+        conanfile.package_folder = temp_folder()
+        conanfile.cpp_info = CppInfo("")
+        custom_mylib_path = os.path.join(conanfile.package_folder, "custom_folder", "mylib.lib")
+        lib_mylib_path = os.path.join(conanfile.package_folder, "lib", "mylib.lib")
+        save(custom_mylib_path, "")
+        save(lib_mylib_path, "")
+        conanfile.cpp_info.libdirs = ["lib", "custom_folder"]
+        result = conanfile.collect_libs()
+        self.assertEqual(["mylib"], result)
+        self.assertIn("Library 'mylib' was either already found in a previous "
+                      "'conanfile.cpp_info.libdirs' folder or appears several times with a "
+                      "different file extension", conanfile.output)
+
+        # Warn lib folder does not exist with correct result
+        conanfile = ConanFileMock()
+        conanfile.package_folder = temp_folder()
+        conanfile.cpp_info = CppInfo("")
+        lib_mylib_path = os.path.join(conanfile.package_folder, "lib", "mylib.lib")
+        save(lib_mylib_path, "")
+        no_folder_path = os.path.join(conanfile.package_folder, "no_folder")
+        conanfile.cpp_info.libdirs = ["no_folder", "lib"]  # 'no_folder' does NOT exist
+        result = conanfile.collect_libs()
+        self.assertEqual(["mylib"], result)
+        self.assertIn("WARN: Lib folder doesn't exist, can't collect libraries: %s"
+                      % no_folder_path, conanfile.output)