[CMake] not found library with package configuration files and changed CMAKE_INSTALL_PREFIX

Michael Hertling mhertling at online.de
Tue Sep 20 10:38:06 EDT 2011


On 09/20/2011 11:26 AM, Alexander Dahl wrote:
> Hello there, 
> 
> after using FindFOO.cmake scripts for our own projects for a long time
> I'm trying to migrate this to the "real" CMake approach of package
> configuration files. Therefor I read chapter 5.7 of the book »Mastering
> CMake« and two HowTos [1] [2] on the web merging all of these in some
> files. I have own shared C library "foo" and one C command line tool
> "bar" and try to build this on Ubuntu Lucid 10.04 with a self compiled
> cmake 2.8.4.
> 
> This works fine as long as I don't change CMAKE_INSTALL_PREFIX (with
> `make edit_cache` or earlier when calling `cmake
> -DCMAKE_INSTALL_PREFIX=/some/path /path/to/src`) and it is /usr/local –
> however when changing this to /home/adahl/usr (or any other non standard
> path) linking the library fails although the include files are still
> found (FOO_DIR is correctly set to /home/adahl/usr/lib/cmake/foo).
> 
> I'll show my CMakeList.txt files and the package configuration stuff,
> maybe someone could have a look and point me to my errors.
> 
> In project "foo" which builds a shared C library:
> 
> CMakeLists.txt:
> 
>   4 project(foo)
>   5
>   6 cmake_minimum_required(VERSION 2.8)
>   7
>   8 set(PACKAGE_MAJOR_VERSION "0")
>   9 set(PACKAGE_MINOR_VERSION "1")
>  10 set(PACKAGE_BUILD_VERSION "0")
>  11 set(PACKAGE_VERSION
> "${PACKAGE_MAJOR_VERSION}.${PACKAGE_MINOR_VERSION}.${PACKAGE_BUILD_VERSION}"
>    )
>  12
>  13 add_subdirectory("inc")
>  14 add_subdirectory("src")
>  15
>  16 configure_file(
>  17     ${CMAKE_CURRENT_SOURCE_DIR}/foo-config.cmake.in
>  18     ${CMAKE_CURRENT_BINARY_DIR}/foo-config.cmake @ONLY
>  19 )
>  20 configure_file(
>  21     ${CMAKE_CURRENT_SOURCE_DIR}/foo-config-version.cmake.in
>  22     ${CMAKE_CURRENT_BINARY_DIR}/foo-config-version.cmake @ONLY
>  23 )
>  24 install(FILES
>  25     ${CMAKE_CURRENT_BINARY_DIR}/foo-config.cmake
>  26     ${CMAKE_CURRENT_BINARY_DIR}/foo-config-version.cmake
>  27     DESTINATION "lib/cmake/${PROJECT_NAME}"
>  28 )
> 
> foo-config.cmake.in:
> 
>   4 get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
>   5 get_filename_component(_prefix "${_dir}/../../.." ABSOLUTE)
>   6 include("${_dir}/@PROJECT_NAME at -targets.cmake")
>   7 set(FOO_INCLUDE_DIRS "${_prefix}/include/@PROJECT_NAME@")
> 
> foo-config-version.cmake.in:
> 
>   4 set(PACKAGE_VERSION "@PACKAGE_VERSION@")
>   5
>   6 if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
>   7     set(PACKAGE_VERSION_COMPATIBLE FALSE)
>   8 else()
>   9     set(PACKAGE_VERSION_COMPATIBLE TRUE)
>  10     if ("${PACKAGE_VERSION}" VERSION_EQUAL
> "${PACKAGE_FIND_VERSION}")
>  11         set(PACKAGE_VERSION_EXACT TRUE)
>  12     endif()
>  13 endif()
> 
> inc/CMakeLists.txt:
> 
>   4 install(FILES
>   5     foo.h
>   6     DESTINATION "include/${PROJECT_NAME}"
>   7 )
> 
> src/CMakeLists.txt:
> 
>   4 set(FOO_SRC
>   5     foo.c
>   6 )
>   7
>   8 include_directories(
>   9     "${PROJECT_SOURCE_DIR}/inc"
>  10 )
>  11
>  12 add_library(${PROJECT_NAME}-shared SHARED ${FOO_SRC})
>  13 set_target_properties(${PROJECT_NAME}-shared PROPERTIES
>  14     OUTPUT_NAME ${PROJECT_NAME}
>  15     SOVERSION   ${PACKAGE_MAJOR_VERSION}
>  16     VERSION     ${PACKAGE_VERSION}
>  17 )

This leaves the target named "foo-shared", not "foo"; the latter is
just the base name of the target's disk file, i.e. libfoo.so.0.1.0.

>  18 install(TARGETS ${PROJECT_NAME}-shared DESTINATION "lib" EXPORT
> ${PROJECT_NAME}-targets)
>  19 install(EXPORT ${PROJECT_NAME}-targets DESTINATION
> "lib/cmake/${PROJECT_NAME}")

The foo-targets.cmake file contains "foo-shared" as imported target,
and it is this name that must be supplied to TARGET_LINK_LIBRARIES().
Besides, the DESTINATION clause of INSTALL() should be qualified with
ARCHIVE/LIBRARY/RUNTIME/..., and EXPORT must precede DESTINATION then.

> This allows successful build of the library with all files installed
> where they should be, at least binaries and header files. The package
> configuration files are installed like this:
> 
> % ls -l /home/adahl/usr/lib/cmake/foo
> insgesamt 16
> -rw-r--r-- 1 adahl adahl  248 2011-09-20 11:09 foo-config.cmake
> -rw-r--r-- 1 adahl adahl  334 2011-09-20 11:09 foo-config-version.cmake
> -rw-r--r-- 1 adahl adahl  924 2011-09-20 11:09 foo-targets.cmake
> -rw-r--r-- 1 adahl adahl 1041 2011-09-20 11:09
> foo-targets-noconfig.cmake
> 
> Now first I build this library like this:
> 
> ~/Work/build/libfoo % cmake -DCMAKE_INSTALL_PREFIX=/home/adahl/usr
> ../../src/libfoo
> ~/Work/build/libfoo % make
> ~/Work/build/libfoo % make install
> 
> No problem so far, but when building the cli tool »bar« like this:
> 
> ~/Work/build/bar % cmake -DCMAKE_INSTALL_PREFIX=/home/adahl/usr
> ../../src/bar
> ~/Work/build/bar % make
> 
> This fails like this:
> 
> Linking C executable bar
> /usr/bin/ld: cannot find -lfoo

The "-lfoo" notation instead of a full path is a typical hint that CMake
doesn't recognize "foo" as an [imported] target but as a simple library
passed to TARGET_LINK_LIBRARIES(). However, libraries residing in an
"implicit system location" constitute an exception, refer to [3].

> collect2: ld returned 1 exit status
> 
> (Note: when not changing CMAKE_INSTALL_PATH this works.)
> 
> The cmake files for "bar" look like this:
> 
> CMakeLists.txt:
> 
>   4 project(m16c-progflash)
>   5
>   6 cmake_minimum_required(VERSION 2.8)
>   7
>   8 set(PACKAGE_MAJOR_VERSION "0")
>   9 set(PACKAGE_MINOR_VERSION "1")
>  10 set(PACKAGE_BUILD_VERSION "0")
>  11 set(PACKAGE_VERSION
> "${PACKAGE_MAJOR_VERSION}.${PACKAGE_MINOR_VERSION}.${PACKAGE_BUILD_VERSION}"
>    )
>  12
>  16 find_package(FOO 0.1 REQUIRED)
>  17
>  18 add_subdirectory("src")
> 
> src/CMakeLists.txt:
> 
>  11 set(BAR_SRC
>  12     bar.c
>  13 )
>  14
>  15 include_directories(
>  16     ${CMAKE_CURRENT_BINARY_DIR}
>  17     ${FOO_INCLUDE_DIRS}
>  18 )
>  19 add_executable(${PROJECT_NAME} ${BAR_SRC})
>  20
>  21 target_link_libraries(${PROJECT_NAME} foo)

Try TARGET_LINK_LIBRARIES(${PROJECT_NAME} foo-shared).
                                             ^^^^^^^
>  22
>  23 install(TARGETS ${PROJECT_NAME} DESTINATION bin)
> 
> With the former find scripts I would have had FOO_LIBRARIES and used
> this in target_link_libraries() instead of "foo" but this variable is
> not set anymore. So the includes are found, also in the changed
> CMAKE_INSTALL_PREFIX tree, but linking fails. I guess this is some
> misunderstanding or error in the package files of libfoo, but I can not
> see where.

You should still provide the variable FOO_LIBRARIES which contains
"foo-shared", i.e. the name of the imported target. For the user, it
should not make any difference whether the find module / config file
uses full paths to library targets immediately or via imported targets
and their IMPORTED_LOCATION properties. If you read the tutorial in [1]
carefully, you will see that there's still a FOOBAR_LIBRARIES variable
in the FooBar/FooBarConfig.cmake.in template of the configuration file.

'hope that helps.

Regards,

Michael

[3] http://cmake.org/Wiki/CMake_2.6_Notes#Linking_to_System_Libraries

> Any help appreciated. O:-)
> Greets
> Alex
> 
> [1]
> http://cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file
> [2] http://www.vtk.org/Wiki/CMake/Tutorials/Packaging


More information about the CMake mailing list