链接到特定库

时间:2014-10-02 13:29:12

标签: linker cmake lapack

我正在编译一个使用lapack的简单测试程序,但我安装了3个版本的lapack库(一个来自Apple /usr/lib,一个来自/opt/local/lib中的macports我在/usr/local/lib)安装了一个。

我有以下CMakeLists.txt文件:

cmake_minimum_required(VERSION 3.0)

project(delme)

include_directories(../../include /usr/local/include/boost-numeric-bindings)

find_library(lapack_LIBRARY NAMES lapack liblapack HINTS /usr/local/lib )
find_library(atlas_LIBRARY NAMES atlas libatlas HINTS /usr/local/lib )
find_library(cblas_LIBRARY NAMES cblas libcblas HINTS /usr/local/lib )

add_executable(delme test.cpp main.cpp)

target_link_libraries(delme lapack atlas cblas)

install(TARGETS delme RUNTIME DESTINATION bin)

调用cmake . && make VERBOSE=1后,输出结束于:

Linking CXX executable delme
/opt/local/bin/cmake -E cmake_link_script CMakeFiles/delme.dir/link.txt --verbose=1
/usr/bin/c++    -Wl,-search_paths_first -Wl,-headerpad_max_install_names   CMakeFiles/delme.dir/test.cpp.o CMakeFiles/delme.dir/main.cpp.o  -o delme  -llapack -latlas -lcblas
Undefined symbols for architecture x86_64:
  "_clapack_dgetrf", referenced from:
      boost::numeric::bindings::atlas::detail::getrf(CBLAS_ORDER, int, int, double*, int, int*) in main.cpp.o
  "_clapack_dgetri", referenced from:
      boost::numeric::bindings::atlas::detail::getri(CBLAS_ORDER, int, double*, int, int const*) in main.cpp.o
  "_clapack_dpotrf", referenced from:
      boost::numeric::bindings::atlas::detail::potrf(CBLAS_ORDER, CBLAS_UPLO, int, double*, int) in main.cpp.o
ld: symbol(s) not found for architecture x86_64

这些符号位于/usr/local/lib和macports版本中,但不是Apple的版本,它似乎是它所链接的版本。 如果我手动将-L/usr/local/lib添加到CMake生成的文件CMakeFiles/delme.dir/link.txt,那么它编译得很好。

我的问题是,如何指示cmake在其链接命令(或其他替代方案)中包含-L/usr/local/lib,以便它使用/usr/local/lib中的版本?

2 个答案:

答案 0 :(得分:3)

您的target_link_libraries电话中看起来好像正在使用错误的库。正确的电话是:

target_link_libraries(delme ${lapack_LIBRARY} ${atlas_LIBRARY} ${cblas_LIBRARY})

这将使链接命令使用find_library调用找到的库而不是默认库。

答案 1 :(得分:1)

其他库路径之一可能位于cmake缓存变量中。 CMake首先发现了库版本。找到库后,除非清除缓存,否则find_library不会再次查询同一个库。

documentation中所述,命令find_library在搜索库时使用以下顺序:

  1. 搜索特定于cmake的缓存变量中指定的路径。
  2. 搜索特定于cmake的环境变量中指定的路径。
  3. 搜索HINTS选项指定的路径
  4. 搜索标准系统环境变量。
  5. 搜索当前系统的平台文件中定义的cmake变量。
  6. 搜索PATHS选项或命令的简写版本指定的路径。
  7. 基于这些步骤,CMake在步骤1或2中找到了不同版本的库。 存在允许跳过部分或全部步骤的参数。

    1. 使用NO_DEFAULT_PATHNO_CMAKE_PATH
    2. 跳过
    3. 使用NO_DEFAULT_PATHNO_CMAKE_ENVIRONMENT_PATH
    4. 跳过
    5. 跳过NO_DEFAULT_PATH
    6. 使用NO_DEFAULT_PATHNO_SYSTEM_ENVIRONMENT_PATH
    7. 跳过
    8. 使用NO_DEFAULT_PATHNO_CMAKE_SYSTEM_PATH
    9. 跳过
    10. 跳过NO_DEFAULT_PATH
    11. 首先看起来你会跳过第1步和第2步,但根据Kitware,你不应该在HINTS下放置绝对路径。关于提示,CMake documentation

        

      这些应该是系统内省计算的路径,例如由已找到的另一个项目的位置提供的提示。应使用PATHS选项指定硬编码猜测。

      当然,今天可能会使用HINTS,但如果您希望将来证明您的CMake文件,我建议您遵循他们的建议。因此,您的命令看起来与此类似,以防止CMake执行步骤1,2,3和4:

      find_library(lapack_LIBRARY 
          NAMES lapack liblapack 
          PATHS /usr/local/lib 
          NO_CMAKE_PATH
          NO_CMAKE_ENVIRONMENT_PATH
          NO_SYSTEM_ENVIRONMENT_PATH
          NO_CMAKE_SYSTEM_PATH
      )
      

      另一个选择是设置在步骤1或2中搜索到的变量之一,但这样做更难以正确,并且容易被未来的变化破坏。

      另外作为旁注,请避免使用cmake .来创建源内构建。创建另一个文件夹,如build,然后从那里运行cmake命令。这样可以更轻松地删除cmake生成的文件并重新开始。它也不会使源树混乱。