diff --git a/conan/tools/files/files.py b/conan/tools/files/files.py index 7eca6af893f..9aebe7970dd 100644 --- a/conan/tools/files/files.py +++ b/conan/tools/files/files.py @@ -494,24 +494,29 @@ def collect_libs(conanfile, folder=None): else: lib_folders = [os.path.join(conanfile.package_folder, folder) for folder in conanfile.cpp_info.libdirs] - result = [] + + ref_libs = {} for lib_folder in lib_folders: if not os.path.exists(lib_folder): conanfile.output.warn("Lib folder doesn't exist, can't collect libraries: " "{0}".format(lib_folder)) continue + # In case of symlinks, only keep shortest file name in the same "group" files = os.listdir(lib_folder) for f in files: name, ext = os.path.splitext(f) if ext in (".so", ".lib", ".a", ".dylib", ".bc"): - if ext != ".lib" and name.startswith("lib"): - name = name[3:] - if name in result: - 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) + real_lib = os.path.basename(os.path.realpath(os.path.join(lib_folder, f))) + if real_lib not in ref_libs or len(f) < len(ref_libs[real_lib]): + ref_libs[real_lib] = f + + result = [] + for f in ref_libs.values(): + name, ext = os.path.splitext(f) + if ext != ".lib" and name.startswith("lib"): + name = name[3:] + if name not in result: + result.append(name) result.sort() return result diff --git a/conans/client/tools/files.py b/conans/client/tools/files.py index 199581c0ee6..a8444b23c07 100644 --- a/conans/client/tools/files.py +++ b/conans/client/tools/files.py @@ -351,24 +351,29 @@ def collect_libs(conanfile, folder=None): else: lib_folders = [os.path.join(conanfile.package_folder, folder) for folder in conanfile.cpp_info.libdirs] - result = [] + + ref_libs = {} for lib_folder in lib_folders: if not os.path.exists(lib_folder): conanfile.output.warn("Lib folder doesn't exist, can't collect libraries: " "{0}".format(lib_folder)) continue + # In case of symlinks, only keep shortest file name in the same "group" files = os.listdir(lib_folder) for f in files: name, ext = os.path.splitext(f) if ext in VALID_LIB_EXTENSIONS: - if ext != ".lib" and name.startswith("lib"): - name = name[3:] - if name in result: - 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) + real_lib = os.path.basename(os.path.realpath(os.path.join(lib_folder, f))) + if real_lib not in ref_libs or len(f) < len(ref_libs[real_lib]): + ref_libs[real_lib] = f + + result = [] + for f in ref_libs.values(): + name, ext = os.path.splitext(f) + if ext != ".lib" and name.startswith("lib"): + name = name[3:] + if name not in result: + result.append(name) result.sort() return result diff --git a/conans/test/unittests/tools/files/collect_lib_test.py b/conans/test/unittests/tools/files/collect_lib_test.py index e862ce75ba0..854ea374769 100644 --- a/conans/test/unittests/tools/files/collect_lib_test.py +++ b/conans/test/unittests/tools/files/collect_lib_test.py @@ -1,4 +1,7 @@ import os +import platform + +import pytest from conan.tools.files import check_md5, check_sha1, check_sha256, collect_libs from conans.model.build_info import CppInfo @@ -43,7 +46,7 @@ def test_collect_libs(): result = collect_libs(conanfile, folder="custom_folder") assert ["customlib"] == result - # Warn same lib different folders + # Unicity of lib names conanfile = ConanFileMock() conanfile.folders.set_base_package(temp_folder()) conanfile.cpp_info = CppInfo(conanfile.name, "") @@ -54,9 +57,6 @@ def test_collect_libs(): conanfile.cpp_info.libdirs = ["lib", "custom_folder"] result = collect_libs(conanfile) assert ["mylib"] == result - assert "Library 'mylib' was either already found in a previous "\ - "'conanfile.cpp_info.libdirs' folder or appears several times with a "\ - "different file extension" in conanfile.output # Warn lib folder does not exist with correct result conanfile = ConanFileMock() @@ -70,3 +70,23 @@ def test_collect_libs(): assert ["mylib"] == result assert "WARN: Lib folder doesn't exist, can't collect libraries: %s" % no_folder_path \ in conanfile.output + +@pytest.mark.skipif(platform.system() == "Windows", reason="Needs symlinks support") +def test_collect_libs_symlinks(): + # Keep only the shortest lib name per group of symlinks + conanfile = ConanFileMock() + conanfile.folders.set_base_package(temp_folder()) + conanfile.cpp_info = CppInfo(conanfile.name, "") + version_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.0.0.dylib") + soversion_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.dylib") + lib_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.dylib") + lib_mylib2_path = os.path.join(conanfile.package_folder, "lib", "libmylib.2.dylib") + lib_mylib3_path = os.path.join(conanfile.package_folder, "custom_folder", "libmylib.3.dylib") + save(version_mylib_path, "") + os.symlink(version_mylib_path, soversion_mylib_path) + os.symlink(soversion_mylib_path, lib_mylib_path) + save(lib_mylib2_path, "") + save(lib_mylib3_path, "") + conanfile.cpp_info.libdirs = ["lib", "custom_folder"] + result = collect_libs(conanfile) + assert ["mylib", "mylib.2", "mylib.3"] == result diff --git a/conans/test/unittests/util/tools_test.py b/conans/test/unittests/util/tools_test.py index 2be7e00e8e2..cc4c9bcd0c3 100644 --- a/conans/test/unittests/util/tools_test.py +++ b/conans/test/unittests/util/tools_test.py @@ -817,7 +817,7 @@ def test_collect_libs(self): result = tools.collect_libs(conanfile, folder="custom_folder") self.assertEqual(["customlib"], result) - # Warn same lib different folders + # Unicity of lib names conanfile = ConanFileMock() conanfile.folders.set_base_package(temp_folder()) conanfile.cpp_info = CppInfo(conanfile.name, "") @@ -828,9 +828,6 @@ def test_collect_libs(self): conanfile.cpp_info.libdirs = ["lib", "custom_folder"] result = tools.collect_libs(conanfile) 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() @@ -845,6 +842,26 @@ def test_collect_libs(self): self.assertIn("WARN: Lib folder doesn't exist, can't collect libraries: %s" % no_folder_path, conanfile.output) + @pytest.mark.skipif(platform.system() == "Windows", reason="Needs symlinks support") + def test_collect_libs_symlinks(self): + # Keep only the shortest lib name per group of symlinks + conanfile = ConanFileMock() + conanfile.folders.set_base_package(temp_folder()) + conanfile.cpp_info = CppInfo(conanfile.name, "") + version_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.0.0.dylib") + soversion_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.dylib") + lib_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.dylib") + lib_mylib2_path = os.path.join(conanfile.package_folder, "lib", "libmylib.2.dylib") + lib_mylib3_path = os.path.join(conanfile.package_folder, "custom_folder", "libmylib.3.dylib") + save(version_mylib_path, "") + os.symlink(version_mylib_path, soversion_mylib_path) + os.symlink(soversion_mylib_path, lib_mylib_path) + save(lib_mylib2_path, "") + save(lib_mylib3_path, "") + conanfile.cpp_info.libdirs = ["lib", "custom_folder"] + result = tools.collect_libs(conanfile) + self.assertEqual(["mylib", "mylib.2", "mylib.3"], result) + def test_self_collect_libs(self): conanfile = ConanFileMock() # Without package_folder @@ -880,7 +897,7 @@ def test_self_collect_libs(self): result = conanfile.collect_libs(folder="custom_folder") self.assertEqual(["customlib"], result) - # Warn same lib different folders + # Unicity of lib names conanfile = ConanFileMock() conanfile.folders.set_base_package(temp_folder()) conanfile.cpp_info = CppInfo("", "") @@ -891,9 +908,6 @@ def test_self_collect_libs(self): 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() @@ -907,3 +921,23 @@ def test_self_collect_libs(self): self.assertEqual(["mylib"], result) self.assertIn("WARN: Lib folder doesn't exist, can't collect libraries: %s" % no_folder_path, conanfile.output) + + @pytest.mark.skipif(platform.system() == "Windows", reason="Needs symlinks support") + def test_self_collect_libs_symlinks(self): + # Keep only the shortest lib name per group of symlinks + conanfile = ConanFileMock() + conanfile.folders.set_base_package(temp_folder()) + conanfile.cpp_info = CppInfo("", "") + version_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.0.0.dylib") + soversion_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.1.dylib") + lib_mylib_path = os.path.join(conanfile.package_folder, "lib", "libmylib.dylib") + lib_mylib2_path = os.path.join(conanfile.package_folder, "lib", "libmylib.2.dylib") + lib_mylib3_path = os.path.join(conanfile.package_folder, "custom_folder", "libmylib.3.dylib") + save(version_mylib_path, "") + os.symlink(version_mylib_path, soversion_mylib_path) + os.symlink(soversion_mylib_path, lib_mylib_path) + save(lib_mylib2_path, "") + save(lib_mylib3_path, "") + conanfile.cpp_info.libdirs = ["lib", "custom_folder"] + result = conanfile.collect_libs() + self.assertEqual(["mylib", "mylib.2", "mylib.3"], result)