[CMake] transitive linking with separate projects
Michael Hertling
mhertling at online.de
Tue Mar 6 10:46:02 EST 2012
On 03/06/2012 02:47 PM, Alexander Dahl wrote:
> Hei hei,
>
> we faced a build problem with transitive linking of separate projects
> where I can't find the right solution on my own. I hope someone can give
> me a hint. I prepared a test case with two libraries libfoo and libbar
> and an application baz. libfoo is on his own, libbar calls a function
> from libfoo and baz calls the function from libbar calling libfoo. So
> the dependencies are like this:
>
> baz -> libbar -> libfoo
>
> baz doesn't need to know of libfoo because it just calls libbar, so I
> thought.
>
> Now the projects are separated and both libraries come with cmake
> package configuration files. For linking libfoo in libbar I do the
> following:
>
> find_package(FOO)
> target_link_libraries(BAR_SRC foo-shared)
>
> foo-shared is the target libfoo exports via cmake package
> configuration. This works and ldd shows libbar is correctly linked
> against libfoo.
>
> Now when compiling baz I more or less do the same:
>
> find_package(BAR)
> target_link_libraries(BAZ_SRC bar-shared)
>
> However building baz fails with the following error:
>
> % make
> [100%] Building C object src/CMakeFiles/baz.dir/baz.c.o
> Linking C executable baz
> /usr/bin/ld: cannot find -lfoo-shared
> collect2: ld returned 1 exit status
> make[2]: *** [src/baz] Fehler 1
> make[1]: *** [src/CMakeFiles/baz.dir/all] Fehler 2
> make: *** [all] Fehler 2
>
> It seems like cmake tries to link against libfoo here but does not know
> anything about it. If I add find_package(FOO) to baz obviously the
> target is imported from libfoo cmake package files. The question is, if
> I know nothing about the requirements of libbar and want to avoid adding
> find_package statements for those requirements to baz, how would I do
> this?
>
> I put all the code on GitHub, so if someone maybe could have a look?
>
> https://github.com/LeSpocky/libfoo
> https://github.com/LeSpocky/libbar
> https://github.com/LeSpocky/baz
>
> Greets
> Alex
If you run "grep foo -r <libbar-install-dir>/lib/cmake/bar", you will
see only one line which informs the user of bar-config.cmake that the
bar-shared target has a prerequisite name foo-shared, but there is no
more information. For this reason, it's passed as -lfoo-shared to the
linker. You need to include foo-targets.cmake in bar-config.cmake in
order to make the necessary information available, e.g. by
# libbar/bar-config.cmake.in:
INCLUDE(@FOO_CONFIG@)
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE)
include("${_dir}/@PROJECT_NAME at -targets.cmake")
set(BAR_INCLUDE_DIRS "${_prefix}/include/@PROJECT_NAME@")
or possibly better:
# libbar/bar-config.cmake.in:
FIND_PACKAGE(FOO PATHS @FOO_DIR@ NO_DEFAULT_PATH)
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE)
include("${_dir}/@PROJECT_NAME at -targets.cmake")
set(BAR_INCLUDE_DIRS "${_prefix}/include/@PROJECT_NAME@")
This will make the user of bar-config.cmake include the same foo-
config.cmake and, thus, foo-targets.cmake that bar's CMakeLists.txt
has included, too. See also FIND_PACKAGE()'s NAMES / CONFIGS clauses.
BTW, find modules / config files should provide a *_LIBRARIES variable
even if they use imported targets, e.g.: SET(FOO_LIBRARIES foo-shared)
Regards,
Michael
PS: The baz project on GitHub only contains a README.
More information about the CMake
mailing list