[cmake-developers] Setting the link interface and dependencies in one command

Clinton Stimpson clinton at elemtech.com
Sun Oct 2 01:34:35 EDT 2011


On Oct 1, 2011, at 10:51 PM, Clinton Stimpson wrote:

> 
> On Oct 1, 2011, at 4:48 PM, Rolf Eike Beer wrote:
> 
>> On Sa.,   1. Okt. 2011 18:40:09 CEST, Alexander Neundorf <neundorf at kde.org> wrote:
>> 
>>> If library bar internally uses symbols from foo,
>>> it needs to link against foo.
>> 
>> Correct.
>> 
>>> But if bar doesn't expose symbols from foo in its
>>> interface, and my executable   hello links against bar, it doesn't also
>>> have to be linked against foo. This saves startup time and other things.
>>> Packagers also like that.
>> 
>> No, you got something wrong here. Packagers hate that. That's exactly the reason why e.g. Fedora and others introduced -Wl,no-unneeded (or how that's called) in their default linker flags.
>> 
>> If your hello needs foo and bar, and is only linked to bar because that one is already linked against foo, that your package will not work any longer if you replace foo 1.0 with foo 1.1 which is totally binary compatible but doesn't need foo internally any longer because your hello then misses symbols on startup. This is called unterlinking of hello and should be avoided whereever possible.
>> 
>> The opposite is overlinking and that was what I tried to avoid: my hello did not need any symbols from foo itself, so I wanted to get rid of them (which worked by forcing the implicit dependencies to empty). But CMake still did not want to allow me to export the bar target without also exporting foo even if the linkage to foo was only an internal detail and the user was not even allowed to use foo directly.
> 
> 
> Can you consider this example as a demonstration for why cmake wants information about foo in the exports file even though its an internal detail?
> 
> project(test)
> set(CMAKE_SKIP_RPATH 1)
> 
> add_library(foo SHARED test.cpp)
> set_target_properties(foo PROPERTIES LIBRARY_OUTPUT_DIRECTORY "foo")
> 
> add_library(bar SHARED test.cpp)
> target_link_libraries(bar foo)
> set_target_properties(bar PROPERTIES LIBRARY_OUTPUT_DIRECTORY "bar" LINK_INTERFACE_LIBRARIES "")
> 
> add_executable(baz test.cpp)
> # 1) link giving target name
> #target_link_libraries(baz bar)
> # 2) link giving the path to the library
> target_link_libraries(baz "${CMAKE_CURRENT_BINARY_DIR}/bar/libbar.so")
> 
> If I do #2, I get a link warning 
> /usr/bin/ld: warning: libfoo.so, needed by bar/libbar.so, not found (try using -rpath or -rpath-link)
> 
> If I do #1, then I don't get that warning and if I turn on verbose output, I see that cmake wasn't linking foo into baz anyway.  Apparently the linker wants to have a look at dependent shared libraries, and cmake is using the -rpath-link flag for that.
> This information is passed into the exports file, and cmake needs the dependent shared libraries for that.


If I actually change the code being compiled so baz calls a function in bar and bar calls a function in foo, then #2 now gives a linker error.
Linking C executable baz
/usr/bin/ld: warning: libfoo.so, needed by bar/libbar.so, not found (try using -rpath or -rpath-link)
bar/libbar.so: undefined reference to `foo'
collect2: ld returned 1 exit status
make[2]: *** [baz] Error 1
make[1]: *** [CMakeFiles/baz.dir/all] Error 2

I don't get that with #1.  So the linker isn't checking that bar's symbols have been satisfied until it is linked into an executable.

To make sure that doesn't happen, dependent shared libraries go in the export file even if they are internal libraries, but it appears that isn't necessary if the dependent libraries are in the same directory.

Also, instead of putting the libs in different directories, one can also link with -Wl,--enable-new-dtags to reproduce the same problem (which newer distros are starting to use).  This example gives a link error:

project(test)
set(CMAKE_SKIP_RPATH 1)
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-new-dtags")

add_library(foo SHARED foo.c)

add_library(bar SHARED bar.c)
target_link_libraries(bar foo)
set_target_properties(bar PROPERTIES LINK_INTERFACE_LIBRARIES "")

add_executable(baz test.c)
#target_link_libraries(baz bar)
target_link_libraries(baz "${CMAKE_CURRENT_BINARY_DIR}/bar/libbar.so")

So when linking baz with bar, the linker still needs to know about foo, so it needs to go in the exports file.

Clint




More information about the cmake-developers mailing list