Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake FIND_PACKAGE succeeds but returns wrong path

Tags:

c++

boost

cmake

I'm trying to have CMake 2.8.6 link to boost::program_options using the following code in my CMakeLists.txt

FIND_PACKAGE(Boost COMPONENTS program_options REQUIRED)
INCLUDE_DIRECTORIES (${Boost_INCLUDE_DIR})

ADD_EXECUTABLE (segment segment.cpp)
TARGET_LINK_LIBRARIES (segment ${Boost_LIBRARIES})

The find command seems to succeed but passes the wrong directory to the linker. The package is actually in:

`/usr/lib64/libboost_program_options-mt.so.5`

but CMakeFiles/segment.dir/link.txt lists the following:

/cm/shared/apps/gcc/4.4.6/bin/c++       CMakeFiles/segment.dir/segment.cpp.o  -o segment -rdynamic /usr/lib64/lib64/libboost_program_options-mt.so.5 -lpthread -lrt -Wl,-rpath,/usr/lib64/lib64

Note the extra lib64 in the path. Also, the -l flag in front of the path seems to be missing.

When running CMake it reports that it correctly finds the package, and the {$Boost_LIBRARIES} variable seems to list the correct libs:

Boost  found.
Found Boost components:
   program_options
${Boost_LIBRARIES} - optimized;boost_program_options-mt-shared;debug;boost_program_options-mt-shared-debug

The generated CMakeCache.txt file starts with:

//The directory containing a CMake configuration file for Boost.
Boost_DIR:PATH=/usr/lib64/boost

//Boost include directory
Boost_INCLUDE_DIR:FILEPATH=/usr/include

Which seems to be correct. But when running make it uses the path in link.txt above and I get the error:

make[2]: *** No rule to make target `/usr/lib64/lib64/libboost_program_options-mt.so.5', needed by `segment'.  Stop.
make[1]: *** [CMakeFiles/segment.dir/all] Error 2
make: *** [all] Error 2

What might cause this extra injection of a subdir into the path? What might cause link.txt to be generated in this way? And how do I fix it (or work around it)?

like image 813
CvW Avatar asked Mar 30 '12 18:03

CvW


People also ask

How does Find_package work in CMake?

CMake searches for a file called Find<package>. cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. It is responsible for finding the package, checking the version, and producing any needed messages.

Where does Find_package search CMake?

Now CMake has a find_package() which opens a Find*. cmake file and searches after the library on the system and defines some variables like SomeLib_FOUND etc. The first command defines where CMake searches after the Find*.

Where is CMake path in Windows?

CMake maintains a list of package information in the Windows registry under HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\ . Packages build from source can register there using the export command. Other projects build later on the same machine will then be able to find that package without additional configuration.

Where are CMake modules stored?

For CMake, these sections are called cmake-modules and can be found in the Modules subdirectory of your installation.


2 Answers

This problem occurs when using some older versions of boost with cmake-2.8.6-rc2 or later, where the boost package finding code was changed.

The problem can be worked around by specifying -DBoost_NO_BOOST_CMAKE=ON on the cmake command line.

The actual commit where this problem is introduced is 7da796d1fdd7cca07df733d010cd343f6f8787a9, and can be viewed here.

like image 67
zultron Avatar answered Sep 29 '22 00:09

zultron


The problem is with the boost-devel distributed file: /usr/lib64/boost/Boost-relwithdebinfo.cmake

The cmake-2.6 package does not use this file at all, because the FindBoost.cmake file returns (correct) full-paths to boost libraries. The cmake28-2.8.8 FindBoost.cmake file returns library strings like "boost_date_time-mt-shared", which are targets defined in /usr/lib64/boost/Boost-relwithdebinfo.cmake.

At the very top of /usr/lib64/boost/Boost-relwithdebinfo.cmake, a variable named _IMPORT_PREFIX is defined from the location of the cmake file itself, and then used like so:

#----------------------------------------------------------------
# Generated CMake target import file for configuration "RelWithDebInfo".
#----------------------------------------------------------------

# Commands may need to know the format version.
SET(CMAKE_IMPORT_FILE_VERSION 1)

# Compute the installation prefix relative to this file.
GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)

# Import target "boost_date_time-static" for configuration "RelWithDebInfo"
SET_PROPERTY(TARGET boost_date_time-static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
SET_TARGET_PROPERTIES(boost_date_time-static PROPERTIES
  IMPORTED_LOCATION_RELWITHDEBINFO "${_IMPORT_PREFIX}/lib64/libboost_date_time.a"
  )

This sets _IMPORT_PREFIX to "/usr/lib64", which is concatenated with another string that has /lib64/ in it as well. I found that if I simply change the file to include a 3rd GET_FILENAME_COMPONENT call, it works fine. Like so:

#----------------------------------------------------------------
# Generated CMake target import file for configuration "RelWithDebInfo".
#----------------------------------------------------------------

# Commands may need to know the format version.
SET(CMAKE_IMPORT_FILE_VERSION 1)

# Compute the installation prefix relative to this file.
GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
GET_FILENAME_COMPONENT(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)

# Import target "boost_date_time-static" for configuration "RelWithDebInfo"
SET_PROPERTY(TARGET boost_date_time-static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO)
SET_TARGET_PROPERTIES(boost_date_time-static PROPERTIES
  IMPORTED_LOCATION_RELWITHDEBINFO "${_IMPORT_PREFIX}/lib64/libboost_date_time.a"
  )
like image 33
Kai Meyer Avatar answered Sep 28 '22 22:09

Kai Meyer