[CMake] what is best for library dependencies?

Michael Hertling mhertling at online.de
Tue Oct 4 22:40:13 EDT 2011


On 10/04/2011 04:39 PM, Cristobal Navarro wrote:
> great explanation,
> i did:
> readelf -d /usr/local/lib/mylib.so
> 
> Dynamic section at offset 0x7ad28 contains 27 entries:
>   Tag        Type                         Name/Value
>  0x0000000000000001 (NEEDED)             Shared library: [libcudart.so.4]
>  0x0000000000000001 (NEEDED)             Shared library: [libcuda.so.1]
>  0x0000000000000001 (NEEDED)             Shared library: [libGLEW.so.1.5]
>  0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
>  0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
>  0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
>  0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

This means that mylib.so has been linked against libGLEW.so.1.5 - or
more probably against libGLEW.so that has an SONAME libGLEW.so.1.5 -
which is perfect if mylib.so uses symbols from GLEW immediately.

To pull in GLEW when an executable is linked against mylib, one usually
specifies both in the linker command, preferably with their full paths
and in the correct order, i.e. from most dependent to least dependent.
This ensures that the linker will find each library, all symbols could
be resolved, and it works also for static libraries which cannot refer
to other libraries as Eike has already mentioned. BTW, if one follows
the advice with TARGET_LINK_LIBRARIES(mylib <path/to>/libGLEW.so), an
executable "main" linked with TARGET_LINK_LIBRARIES(main mylib) will
be linked explicitly with both libraries in the linker command line,
too, regardless whether it refers to libGLEW.so immediately or not:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(LINK C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
FILE(WRITE ${CMAKE_BINARY_DIR}/glew.c "void glew(void){}\n")
EXECUTE_PROCESS(COMMAND gcc -shared -o libGLEW.so glew.c)
FILE(WRITE ${CMAKE_BINARY_DIR}/mylib.c "void mylib(void){}\n")
ADD_LIBRARY(mylib SHARED mylib.c)
TARGET_LINK_LIBRARIES(mylib ${CMAKE_BINARY_DIR}/libGLEW.so)
SET_TARGET_PROPERTIES(mylib PROPERTIES PREFIX "")
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
ADD_EXECUTABLE(main main.c)
TARGET_LINK_LIBRARIES(main mylib)

That's because TARGET_LINK_LIBRARIES() also tracks mediate dependencies.

You might drop GLEW - or generally, each prerequisite library - on the
linker command line, i.e. specify the immediate dependencies only, and
trust in the linker to find the prerequisites by itself, e.g. via the
DT_RPATH tags of shared libraries. However, this might not work in all
situations, see the INSUFFICIENT example, and especially not with less
sophisticated linkers than GNU ld or less sophisticated binary formats
than ELF, and with static libraries, it won't work at all. Thus, IMO,
it's best to specify the prerequisite libraries on the linker command
line explicitly. To achieve this for mylib, follow Eike's advice, i.e.

- provide a configuration file if mylib is built with CMake, see [1],
- provide a find module if mylib is not built with CMake, see [2],
- provide an export file if your setup is quite simple, see [3].

The same holds for GLEW, or try FIND_LIBRARY(GLEW_LIBRARY GLEW ...)
in the mylib-related files if GLEW isn't worth the effort. Finally,
if mylib and/or GLEW are just used in their CMake-generated build
trees, i.e. not installed, take a look at the EXPORT() command.

> is there a difference between DT_NEEDED and NEEDED?

No, readelf is just a bit scrimpy w.r.t. its output. ;-)

Regards,

Michael

[1]
http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file
[2]
http://www.cmake.org/gitweb?p=cmake.git;a=blob;f=Modules/readme.txt;hb=master
[3] http://www.mail-archive.com/cmake@cmake.org/msg38180.html

> On Tue, Oct 4, 2011 at 4:37 AM, Michael Hertling <mhertling at online.de>wrote:
> 
>> On 10/03/2011 11:32 AM, Rolf Eike Beer wrote:
>>> Am Sonntag, 2. Oktober 2011, 12:21:01 schrieb Cristobal Navarro:
>>>> hello,
>>>>
>>>> as many of us, i am making a library and this is my first time. I have
>> some
>>>> concept questions.
>>>>
>>>> for example, my library depends on "GLEW" library. Therefore
>> applications
>>>> that use my library must compile with  "-lmylib"  and  "-lGLEW"
>>>
>>> Nope. Your library has to link against those libraries. The applications
>> only
>>> have to if they use this interface directly.
>>
>> This might be insufficient; look at the following counterexample:
>>
>> CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
>> PROJECT(INSUFFICIENT C)
>> SET(CMAKE_VERBOSE_MAKEFILE ON)
>> SET(CMAKE_SKIP_BUILD_RPATH TRUE)
>> FILE(WRITE ${CMAKE_BINARY_DIR}/f.c "void f(void){}\n")
>> ADD_LIBRARY(f SHARED f.c)
>> FILE(WRITE ${CMAKE_BINARY_DIR}/g.c "void g(void){f();}\n")
>> ADD_LIBRARY(g SHARED g.c)
>> TARGET_LINK_LIBRARIES(g f)
>> GET_TARGET_PROPERTY(G_LIBRARY g LOCATION)
>> FILE(WRITE ${CMAKE_BINARY_DIR}/main.c
>> "int main(void){g(); return 0;}\n")
>> ADD_EXECUTABLE(main main.c)
>> TARGET_LINK_LIBRARIES(main ${G_LIBRARY})
>>
>> This exemplary project has two shared library targets f and g and an
>> executable target main; g uses and is linked against f, and main uses
>> and is linked against g. The latter is done with g's full path so that
>> TARGET_LINK_LIBRARIES() doesn't track the transient dependencies main-
>> on-g-on-f. That's the situation you aim at, if I understand correctly.
>> A "readelf -d libg.so" reveals that libg.so actually has a DT_NEEDED
>> tag of "libf.so", and main's link command line essentially reads
>>
>> gcc .../main.c.o -o main ... -L${CMAKE_BINARY_DIR} -lg
>>
>> i.e. main is about to be linked against libg.so only. Nevertheless, the
>> linking operation fails since libf.so is not found although it resides
>> next to libg.so in the build directory. The reason is that ld in fact
>> uses libg.so's DT_NEEDED tags to learn about the prerequisite libf.so,
>> but has no hint where to find it; see ld's manpage - particularly the
>> -rpath-link section with its 8-item list - for more information. The
>> reason why it usually works even without TARGET_LINK_LIBRARIES()'s
>> ado is item 6 in connection with CMake's elaborate RPATH handling.
>> In short: DT_NEEDED tells which library, but not where it is.
>>
>> Furthermore, it's not necessary that g is linked against f as long as
>> both are mentioned on the linker command line in the correct order or
>> recognized by other means. It's also not necessary for executables to
>> be linked against libraries they're immediately referring to; e.g. if
>> main calls f() and libg.so has a hint to libf.so, it's sufficient for
>> main to link against libg.so, provided that libf.so can be found. The
>> essence is that for an executable's creation, all symbols need to be
>> resolved, i.e. each necessary library must be found - may it via an
>> explicit specification on the command line, may it by following DT
>> _NEEDED via DT_RPATH or whichever methods the linker offers to
>> locate libraries. However, if "mylib" depends on "GLEW", it's
>> usually perfect to link the former against the latter.
>>
>> Regards,
>>
>> Michael
>>
>>>> is it possible, to make the "-lGLEW" implicit inside my library?? or
>> making
>>>> the user put it manually is the way to go?
>>>
>>> You do TARGET_LINK_LIBRARIES(mylib /path/to/glew/libglew.so). That's all.
>> To
>>> get the path to GLEW in a system independent way please have a look on
>>> FIND_LIBRARY.
>>>
>>> The only exception is if your library is a static one and the target
>>> application is not built with CMake. The problem is that you can't put
>> this
>>> information in static libraries. Writing a pkgconfig or CMake export file
>> is the
>>> way to go then.
>>>
>>> Eike


More information about the CMake mailing list