Discussion:
[CMake] Dynamic libraries and library dependencies
Stefan Buschmann
2007-01-31 19:25:24 UTC
Permalink
Hi all

I'm trying to build a project that consists of several shared libraries
and some applications using those libraries.
The directory layout is as follows (simplified):

Project
Project/CMakeLists.txt
Project/SharedLib
Project/SharedLib/CMakeLists.txt
Project/SharedLib/include
Project/SharedLib/src
Project/SharedLib/external
Project/SharedLib/external/include
Project/SharedLib/external/lib
Project/SharedLib/external/lib/libFoo.a
Project/SampleApp
Project/SampleApp/CMakeLists.txt
Project/SampleApp/src

Project/CMakeLists.txt:
ADD_SUBDIRECTORY(SharedLib)
ADD_SUBDIRECTORY(SampleApp)

Project/SharedLib/CMakeLists.txt:
INCLUDE_DIRECTORIES(external/include)
LINK_DIRECTORIES(external/lib)
SET(PROJECT_LIBS Foo)
...
ADD_LIBRARY(${PROJECT_TARGET} SHARED ${PROJECT_SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_TARGET} ${PROJECT_LIBS})

Project/SampleApp/CMakeLists.txt:
INCLUDE_DIRECTORIES(../SharedLib/include)
SET(PROJECT_LIBS SharedLib)
...
ADD_EXECUTABLE(${PROJECT_TARGET} ${PROJECT_SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_TARGET} ${PROJECT_LIBS})

Now, when building the project, cmake tries to link libFoo to the sample
application instead of linking it to the dynamic library (which is
explained in the cmake faq). So it adds -lFoo to the command line, but
that library can't be found because the path to the library is unknown
(Project/SharedLib/external/lib) as this is only defined in the
SharedLib/CMakeLists.txt, but not inside SampleApp/CMakeLists.txt.
So, is there a way to solve this without having to add the library path
to every dependent project (which would in fact make the library
abstraction useless)?

Thanks

Stefan
Alan W. Irwin
2007-01-31 21:15:06 UTC
Permalink
So, is there a way to solve this without having to add the library path to
every dependent project (which would in fact make the library abstraction
useless)?
Let me try to give you a general answer that I think should apply to your
specific case. If any library or application that you build with CMake has
symbols in it that are resolved by an external library, then your best
approach is to use the find_library command (in your top-level
CMakeLists.txt file or a module included from that file) to find the
complete path to that external library. Then specify that complete path to
TARGET_LINK_LIBRARIES only for those targets where it is required (i.e.,
only for targets which specifically have symbols that need to be resolved by
an external library), and CMake will do the rest for you following the
linking rules for your platform of choice.

For example, PLplot has a core library which in turn depends on external
libraries. Those external libraries only have to be mentioned for the core
library, and not for all our other applications/libraries which depend on
our core library. For such hierarchical linking, cmake figures everything
out for you, if you follow the rule I have specified (i.e., mention the
external library only for those targets which have specific symbols that
need to be resolved by that external library).

BTW, to test that the resulting CMake linking is correct for all targets in
the build tree or install tree, I find the ldd command (especially with the
-r option) and nm commands are extremely useful for the Linux case.

Alan
__________________________
Alan W. Irwin

Astronomical research affiliation with Department of Physics and Astronomy,
University of Victoria (astrowww.phys.uvic.ca).

Programming affiliations with the FreeEOS equation-of-state implementation
for stellar interiors (freeeos.sf.net); PLplot scientific plotting software
package (plplot.org); the Yorick front-end to PLplot (yplot.sf.net); the
Loads of Linux Links project (loll.sf.net); and the Linux Brochure Project
(lbproject.sf.net).
__________________________

Linux-powered Science
__________________________
Bill Hoffman
2007-01-31 21:55:16 UTC
Permalink
Post by Stefan Buschmann
Hi all
I'm trying to build a project that consists of several shared
libraries and some applications using those libraries.
Project
Project/CMakeLists.txt
Project/SharedLib
Project/SharedLib/CMakeLists.txt
Project/SharedLib/include
Project/SharedLib/src
Project/SharedLib/external
Project/SharedLib/external/include
Project/SharedLib/external/lib
Project/SharedLib/external/lib/libFoo.a
Project/SampleApp
Project/SampleApp/CMakeLists.txt
Project/SampleApp/src
ADD_SUBDIRECTORY(SharedLib)
ADD_SUBDIRECTORY(SampleApp)
INCLUDE_DIRECTORIES(external/include)
LINK_DIRECTORIES(external/lib)
SET(PROJECT_LIBS Foo)
...
ADD_LIBRARY(${PROJECT_TARGET} SHARED ${PROJECT_SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_TARGET} ${PROJECT_LIBS})
INCLUDE_DIRECTORIES(../SharedLib/include)
SET(PROJECT_LIBS SharedLib)
...
ADD_EXECUTABLE(${PROJECT_TARGET} ${PROJECT_SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_TARGET} ${PROJECT_LIBS})
Now, when building the project, cmake tries to link libFoo to the
sample application instead of linking it to the dynamic library (which
is explained in the cmake faq). So it adds -lFoo to the command line,
but that library can't be found because the path to the library is
unknown (Project/SharedLib/external/lib) as this is only defined in
the SharedLib/CMakeLists.txt, but not inside SampleApp/CMakeLists.txt.
So, is there a way to solve this without having to add the library
path to every dependent project (which would in fact make the library
abstraction useless)?
Try putting the full path to Foo. SET(PROJECT_LIBS
${Project_SOURCE_DIR}/external/lib/libFoo.a)

-Bill
Stefan Buschmann
2007-02-01 21:50:56 UTC
Permalink
Post by Bill Hoffman
Post by Stefan Buschmann
Now, when building the project, cmake tries to link libFoo to the
sample application instead of linking it to the dynamic library
(which is explained in the cmake faq). So it adds -lFoo to the
command line, but that library can't be found because the path to the
library is unknown (Project/SharedLib/external/lib) as this is only
defined in the SharedLib/CMakeLists.txt, but not inside
SampleApp/CMakeLists.txt.
So, is there a way to solve this without having to add the library
path to every dependent project (which would in fact make the library
abstraction useless)?
Try putting the full path to Foo. SET(PROJECT_LIBS
${Project_SOURCE_DIR}/external/lib/libFoo.a)
-Bill
Worked perfectly :-) Thanks.

Stefan

Loading...