On 03/29/2011 11:36 PM, Rolf Eike Beer wrote:
> Am Dienstag, 29. März 2011, 09:41:36 schrieb Brad King:
>> On 03/29/2011 05:19 AM, Rolf Eike Beer wrote:
>>> The basic idea is: any symbols from those private libraries are, well,
>>> private. The user only ever sees the symbols from the public library. In
>>> fact he _can't_ even link to the private libraries on Windows as we
>>> never
>>> install the .lib files. And that's no problem at all as we already link
>>> to everything we need. I'm using --as-needed and --no-undefined on Un*x
>>> and see no problem there either.
>>>
>>> So the point is I want CMake to stop telling the user that he needs to
>>> those private libraries as that's simply not true.
>>
>> As Michael pointed out it is needed to set this property:
>>
>>  
>> http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:IMPORTED_LINK_
>> DEPENDENT_LIBRARIES
>>
>> CMake running in an outside application needs to know these private runtime
>> dependencies.  It needs them ensure that the application link line is
>> generated such that the linker can find the transitive dependencies (e.g.
>> -rpath-link) of the public library.
> 
> No, why should it? Take the attached example. Build it. Do ldd on testthing.  
> It links against Qt. Run testthing. It prints your path. Delete libqthing. 
> Move libcthing to libqtthing. Run testthing. It prints your path just like 
> before. ldd testthing. It still links against Qt.

Besides, ldd is not appropriate to check against which shared libraries
a binary is linked because it gathers all shared libraries recursively.
As a proof, set the LINK_INTERFACE_LIBRARIES property on qthing to the
empty string and rebuild; "ldd testthing" still shows the Qt libraries,
indirectly pulled in by qthing. Instead, one should apply "readelf -d"
and look for the NEEDED fields to see which shared libraries a binary
actually depends on explicitly, at least on an ELF platform.

> Now when I set LINK_INTERFACE_LIBRARIES on qthing to empty it will prevent 
> testthing to be linked against Qt itself so after replacing libqthing with 
> libcthing everything works fine but without the (now useless) dependency on 
> Qt. 
> So why would I import that dependency to an outside project then?
> 
> I think this transitive linking for _shared_ libraries should actually be 
> considered harmful. We provide an API and that's all a user should care 
> about. 
> We may change our internal libraries in any release at will and the user 
> should care. In fact we have done this more than one and the binaries linked 
> against older runtime versions just happily work with newer releases. If that 
> transitive stuff would have been used none of them would work anymore because 
> we have moved, renamed, deleted, replaced and done other things to our 
> internal libraries.
> 
> I guess you had a reason for this transitive stuff, but I don't understand 
> it. 
> To prevent the silly user from accidentially underlinking his executables and 
> libs? I know where this is needed for in static libs, but for shared ones?
> 
> Eike

Everything you're saying above is correct, and perhaps one can argue
about such a kind of transitive linking, but you can avoid it easily
with the LINK_INTERFACE_LIBRARIES properties which are also honored by
INSTALL(EXPORT), i.e. with imported targets. Take the exemplary project
"LIL" from my previous post, build/install it and look at the following:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(LILUSR C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
INCLUDE(lil)
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
ADD_EXECUTABLE(main1 main.c)
TARGET_LINK_LIBRARIES(main1 f1)
ADD_EXECUTABLE(main2 main.c)
TARGET_LINK_LIBRARIES(main2 f2)

Configure with CMAKE_MODULE_PATH set to the directory containing the
lil.cmake file from the LIL project and look for the linker commands;
you'll see that main1 gets linked against libf1.so and libf0.so while
main2 gets linked against libf2.so only - no f0 in sight. Hence, the
f2 target's IMPORTED_LINK_DEPENDENT_LIBRARIES property actually does
what's expected: It prevents libf0.so from appearing in the linker's
command line, so there is no direct dependency of main2 on libf0.so.

However, I still don't understand the relation of that transitive
linking and its avoidance, respectively, to your initial complaint
about CMake's error message due to the missing library in another
library's export set. Unless I'm mistaken, you've a shared library
target "publiclib" which is linked explicitly against another target
"privatelib" via TARGET_LINK_LIBRARIES(). This means you can't place
publiclib in an export set without privatelib since the former could
not be set up properly w.r.t. its diverse IMPORTED properties if the
latter is not installed, too, i.e. INSTALL(EXPORT) could not generate
a valid export file.

If you want to remove the error message, just include privatelib in
publiclibs's export set; here, both targets may perfectly reside in
different directories with different CMakeLists.txt files, but they
must be members of the same export set. Or don't you want to install
privatelib but use it only to resolve publiclib's symbols during the
build process? If so, you might include privatelib additionally in
your project as an imported target and take this to link publiclib
against; an imported target does not need to be in the export set
of a, say, regular target. Look at the following CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(PRIVATE C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
FILE(WRITE ${CMAKE_BINARY_DIR}/f.c "void f(void){}\n")
ADD_LIBRARY(f SHARED f.c)
EXPORT(TARGETS f NAMESPACE "private_" FILE ${CMAKE_BINARY_DIR}/f.cmake)
INCLUDE(${CMAKE_BINARY_DIR}/f.cmake)
FILE(WRITE ${CMAKE_BINARY_DIR}/g.c "void g(void){f();}\n")
ADD_LIBRARY(g SHARED g.c)
ADD_DEPENDENCIES(g f)
TARGET_LINK_LIBRARIES(g private_f)
INSTALL(TARGETS g EXPORT public LIBRARY DESTINATION lib)
INSTALL(EXPORT public DESTINATION share)

When building, libg.so gets linked against libf.so, but g can be
installed in an export set without f. Note that you need to use an
additional ADD_DEPENDENCIES() to ensure f is built before g because
TARGET_LINK_LIBRARIES() doesn't establish such a dependency anymore.

Of course, feel invited to post again if I still miss your point.

Regards,

Michael
_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Follow this link to subscribe/unsubscribe:
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to