conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.14k stars 970 forks source link

private linking of transitive dependencies #13302

Open memsharded opened 1 year ago

memsharded commented 1 year ago

I've setup a small example. If this is not related to the topic of the discussion above, we can also move this into a new issue.

The relationship is as follows ("->" == "depends on"): app -> libB libB -> libA libA -> libX & libY

Build via:

cd libX
conan create . -pr:h default -pr:b default -s build_type=Release

cd libY
conan create . -pr:h default -pr:b default -s build_type=Release

cd libA
conan create . -pr:h default -pr:b default -s build_type=Release

cd app
conan create . -pr:h default -pr:b default -s build_type=Release

This is failing with:

Scanning dependencies of target app
[ 80%] Building CXX object src/app/CMakeFiles/app.dir/app.cpp.o
[ 80%] Building CXX object src/app/CMakeFiles/app.dir/main.cpp.o
[100%] Linking CXX executable app
/usr/bin/ld: warning: liblibX.so, needed by /home/user/.conan/data/libA/1.0.0/_/_/package/b2bcf496ea6094c509a11d681ff126c83f01fc2f/lib/liblibA.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: liblibY.so, needed by /home/user/.conan/data/libA/1.0.0/_/_/package/b2bcf496ea6094c509a11d681ff126c83f01fc2f/lib/liblibA.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: /home/user/.conan/data/libA/1.0.0/_/_/package/b2bcf496ea6094c509a11d681ff126c83f01fc2f/lib/liblibA.so: undefined reference to `libY()'
/usr/bin/ld: /home/user/.conan/data/libA/1.0.0/_/_/package/b2bcf496ea6094c509a11d681ff126c83f01fc2f/lib/liblibA.so: undefined reference to `libX()'
collect2: error: ld returned 1 exit status
make[2]: *** [src/app/CMakeFiles/app.dir/build.make:100: src/app/app] Error 1
make[1]: *** [CMakeFiles/Makefile2:160: src/app/CMakeFiles/app.dir/all] Error 2
make: *** [Makefile:130: all] Error 2

The error is gone once you link libB PUBLIC against libA. target_link_libraries(libB PUBLIC libA::libA)

I was wondering whether this is related to this issue, but I might be wrong.

$ conan --version
Conan version 1.53.0

Originally posted by @tbsuht in https://github.com/conan-io/conan/issues/7192#issuecomment-1451741971

memsharded commented 1 year ago

quick hint @tbsuht: do not use package names in uppercase, as that will be incompatible with 2.0. please start using packages lowercase

I am having a quick check in Windows first, and it builds in Windows correctly (except it fails in the final app package(), but the app.exe is built correctly. So this seems exclusively a failure in Linux. Lets move to Linux to check

memsharded commented 1 year ago

I have been able to dig deep into this.

The issue is originated because the liba::liba Conan generated target is an interface target, that depends on the real CONAN_LIB::liba target that is unknown imported (because Conan doesn't have enough information on that). It seems that CMake is unable to propagate correctly the linkage requirements in this case.

So you are correct, the workaround would be to define PUBLIC dependency on it. We will be improving CMakeDeps generator to better handle these cases, but this is complicated, so it might take a bit of time. Assigning this for the 2.X roadmap.

tbsuht commented 1 year ago

@memsharded thanks for the fast response!

So this seems exclusively a failure in Linux. Lets move to Linux to check

Do you know why this is not a problem on Windows if that is related to the generated CMake files?

because Conan doesn't have enough information on that

I can fix the linking manually by providing the lib paths via "-rpath-link". But those path infos are not available as it's an imported target?

We will be improving CMakeDeps generator to better handle these cases. Assigning this for the 2.X roadmap.

Will this also be available in Conan 1.X?


I was wondering a little bit: is this an uncommon use case? For us this is used regularly. Whenever there is an executable & library inside a conan package where the executable is also using the library and the lib has some dependencies managed by conan.

tbsuht commented 1 year ago

Another workaround instead of using PUBLIC for linking:

In the conanfile of app:

    def imports(self):
        self.copy("*.so*", "lib", "lib")

and its CMakeLists.txt

target_link_libraries(app PRIVATE libB "-Wl,-rpath-link ${CMAKE_BINARY_DIR}/lib")

what do you think makes more sense to use?

PengZheng commented 1 year ago
target_link_libraries(app PRIVATE libB "-Wl,-rpath-link ${CMAKE_BINARY_DIR}/lib")

I'd rather fix it at the conan level:

https://github.com/apache/celix/pull/569/commits/40df914a5a4e00697a8ef9d0d0dbb014f43ec883

Anyway, thanks for a workaround much better than previous ones.

memsharded commented 1 year ago

Hi @PengZheng, @tbsuht

It is better not to use the imports() anymore, it has been deprecated and removed in Conan 2.0. So to be ready, the best is to use generate() method and do a explicit copy() there (not a self.copy(), note the free copy() is imported from conan.tools.files import copy, the self.copy() has also been removed in Conan 2.0)

tbsuht commented 1 year ago

To be considered in https://github.com/conan-io/conan/issues/13018.