conan icon indicating copy to clipboard operation
conan copied to clipboard

[bug] conan removes duplicated entries from self.cpp_info.components[""].libs

Open ilya-lavrenov opened this issue 2 years ago • 9 comments

Environment details

  • Operating System+version: macOS 13.x
  • Compiler+version: clang (arm64-apple-darwin22.6.0)
  • Conan version: 2.0.9
  • Python version: 3.11

Steps to reproduce

We have a product with plugin architecture where CORE library can load PLUGIN_A, PLUGIN_B in runtime. Our product can also be built for static libraries configuration. In this case, CORE library explicitly have entry points ENTRY_POINT_A, ENTRY_POINT_B which references to symbols in PLUGIN_A, PLUGIN_B respectively.

In this case, when users statically links with CORE, it statically depends on PLUGIN_A and PLUGIN_B and can create their instances via those symbols. Also note, that some common functionality is used by PLUGIN_A and PLUGIN_B from CORE library. So, we have a cyclic dependency here and cmake can perfectly export such targets (install(EXPORT ..)) and they are used by 3rd party projects.

But with Conan I cannot resolve such scheme with cyclic dependencies, because I have to fill self.cpp_info.components["CORE"].libs with ["CORE", "PLUGIN_A", "PLUGIN_B", "CORE"], but last "CORE" is removed by Conan for some reason. Why does Conan do it?

Last "CORE" is required, because "CORE" simply speaking contains of two parts: user API and developer API. First one represent set of symbols used by public users, developer API is for PLUGIN_<x>s. And during static linkage, developer API is removed by linker, because it's not used by final application and we have unresolved symbols in PLUGIN_A and PLUGIN_B. So, last "CORE" is required to resolve those symbols for PLUGINS_<x>s. And cmake generates similar sequence where CORE is faced multiple times in linker command.

Could you please remove filtering out of duplicated libraries, because it's really required for cyclic dependencies?

Logs

N/A

ilya-lavrenov avatar Sep 01 '23 07:09 ilya-lavrenov

Hi @ilya-lavrenov

Thanks for your report.

I am doing a quick test trying to reproduce, so far I got:

def test_components_repeated_libs():
    """
    https://github.com/conan-io/conan/issues/14632
    """
    c = TestClient()
    conanfile = textwrap.dedent("""
        from conan import ConanFile

        class TestcycleConan(ConanFile):
            name = "pkg"
            version = "1.0"

            def package_info(self):
                self.cpp_info.components["mycomp"].libs = ["core", "liba", "libb", "core"]
        """)
    test_conanfile = textwrap.dedent("""
        from conan import ConanFile
        class Test(ConanFile):

            def generate(self):
                comp = self.dependencies["pkg"].cpp_info.components["mycomp"]
                self.output.info(f'LIBS: {comp.libs}')

            def requirements(self):
                self.requires(self.tested_reference_str)

            def test(self):
                pass
            """)
    c.save({"conanfile.py": conanfile,
            "test_package/conanfile.py": test_conanfile})
    c.run("create .")
    print(c.out)
    assert "pkg/1.0 (test package): LIBS: ['core', 'liba', 'libb', 'core']" in c.out

So libs are not being removed.

I suspect this could be something specific to a generator, which generators are you using? Thanks!

memsharded avatar Sep 01 '23 14:09 memsharded

Hi @memsharded Here is my recipe and place where I have to add a WA by adding system_libs instead of libs https://github.com/conan-io/conan-center-index/pull/19164/files#diff-7ca309e1d202ce3bb2475f1e05db803cbfd2838445ed24e3d489de4a795546f2R343-R347

ilya-lavrenov avatar Sep 01 '23 15:09 ilya-lavrenov

Thanks for the feedback! Still, the workaround is not enough to try to understand who is removing the duplicate libs, because Conan core cpp_info is not doing it. This is why I was suspecting that is the consumer side, as the test_package is using CMake, I think it is indicating the CMakeDeps could be the one doing the actual removal of duplicates, I'll check that.

memsharded avatar Sep 01 '23 15:09 memsharded

Uhmm, I have extended the test to use CMakeDeps and I see that the components libraries are assert "set(pkg_pkg_mycomp_LIBS_RELEASE core liba libb core)" in cmake_data, so up to this point, the libraries duplicates are not removed. It is true that the global package variable removes it, but if you are consuming the component, the duplicated entries should be there (unless CMake itself is removing it?). If you could elaborate a bit more about the usage of the component, that might help.

memsharded avatar Sep 01 '23 16:09 memsharded

Hi @memsharded Here is a small diff in the code which reproduces the issue https://github.com/conan-io/conan-center-index/pull/20161 Can you reproduce it locally by disabling all frontend and plugins except PyTorch one (to build minimal amount of code).

ilya-lavrenov avatar Sep 29 '23 09:09 ilya-lavrenov

Hi @memsharded Have you been able to reproduce the issue?

ilya-lavrenov avatar Oct 07 '23 11:10 ilya-lavrenov

I encountered the issue myself, but that's because I had duplicates in system_libs. Strangely enough this only showed up when the package was in editable mode. Looking into it I managed to figure out that the merge_list() implementation in conans.model.build_info._Component.merge() was the culprit. Assuming that the behavior of removing duplicates is desired I can't think of a better solution than adding an exception for _libs and _system_libs so that merge_list() doesn't run for those and instead just goes through a regular extend()

ohunter avatar May 14 '24 13:05 ohunter

I opened a related issue in CCI: https://github.com/conan-io/conan-center-index/issues/24795

Using system_libs is fragile too, as libraries and headers should be part of the package only.

Currently, we need to provide a custom component, only with openvino as library. However, it's a bad pattern, as that component will be exposed too.

uilianries avatar Aug 06 '24 11:08 uilianries

I created a repository including another minimal scenario to reproduce the case: https://github.com/uilianries/conan-cmake-deps-cyclic-bug

Running build.sh, it will build the project and use test package with both CMakeDeps and PkgConfigDeps (separated builds).

The CMakeDeps does not conserve repeated libraries, and pass absolute pass for static libraries:

[2/2] : && /usr/bin/c++ -m64 -O3 -DNDEBUG -m64 CMakeFiles/example.dir/src/example.cpp.o -o example -L/home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib -Wl,-rpath,/home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib  /home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib/libfoo.a  /home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib/libcore.a  /home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib/libbaz.a && :

At same time, when using PkgConfigDeps with CMake, the same repeats libraries listed in cpp_info.libs:

[2/2] : && /usr/bin/c++ -m64 -O3 -DNDEBUG -m64 CMakeFiles/example.dir/src/example.cpp.o -o example -L/home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib -Wl,-rpath,/home/uilian/.conan2/p/b/foo7229e6f52d733/p/lib  -lfoo  -lcore  -lbaz  -lfoo  -lcore  -lbaz && :

The full build log can be obtained in the same repository: https://github.com/uilianries/conan-cmake-deps-cyclic-bug/blob/master/build.log

uilianries avatar Aug 06 '24 13:08 uilianries