2014-10-02 104 views
0

我编写一个简单的测试程序,它利用了lapack,但是我有3个版本安装LAPACK库(一个来自苹果/usr/lib,一个从MacPorts的在/opt/local/lib和一个我在/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的版本,但不是苹果的版本,这似乎是它连接的一个版本。 如果我手动将-L/usr/local/lib添加到CMake生成的文件CMakeFiles/delme.dir/link.txt,那么它编译得很好。

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

+0

在三个库路径中,它们中的任何一个是否在PATH环境变量中?他们的顺序是什么? – jmstoker 2014-10-02 20:30:44

+0

不,没有任何库路径在我的$ PATH环境变量中。 – 2014-10-03 07:17:43

回答

3

它看起来像你在你的target_link_libraries调用中使用错误的库。正确的调用是:

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

这将使链接命令使用已发现的find_library调用,而不是默认的库。

+0

谢谢。现在编译。我从调用'make VERBOSE = 1'看到cmake指示链接器直接链接到这些库(即'/ usr/bin/C++ -std = C++ 11 -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/delme .dir/test.cpp.o CMakeFiles/delme.dir/main.cpp.o -o delme /usr/local/lib/liblapack.a /usr/local/lib/libatlas.a/usr/local/lib/libcblas .a'),这对于一些库很不错,但我更喜欢使用'-L'链接器标志的解决方案。有没有办法告诉cmake先查看'/ usr/local/lib',这样我就不需要为每个库使用'find_library'了? – 2014-10-03 09:17:03

+1

您必须自己将相关标志('-L')传递给'target_link_libraries'。另请参阅http://stackoverflow.com/questions/6984479/cmake-how-to-link-a-library-without-automatic-search-function-find-package。 – sakra 2014-10-03 10:08:49

+0

好吧,所以我可以使用'set(库-L/usr/local/lib -llapack -latlas -lcblas)'和'target_link_libraries(delme $ {libraries})'而不是'find_library'。这也编译,似乎更容易。 :-) – 2014-10-03 11:37:17

1

其他库路径中的一个可能位于cmake缓存变量中。 CMake首先找到该库的版本。在找到一个库之后,find_library将不会再次查询同一个库,除非缓存被清除。在一个特定的cmake缓存变量指定

  1. 搜索路径:

    documentation所述,命令find_library搜索库时使用下面的顺序。

  2. 在特定于cmake的环境变量中指定的搜索路径。
  3. 搜索由HINTS选项指定的路径。
  4. 搜索标准系统环境变量。
  5. 搜索当前系统平台文件中定义的cmake变量。
  6. 搜索由PATHS选项指定的路径或命令的简短版本。

基于关的这些步骤,CMake的是找到一个不同版本的库的步骤1或2 参数存在,以允许跳越某些或所有这些步骤。

  1. 跳过与NO_DEFAULT_PATHNO_CMAKE_PATH
  2. 跳过NO_DEFAULT_PATHNO_CMAKE_ENVIRONMENT_PATH
  3. 跳过NO_DEFAULT_PATH
  4. 跳过NO_DEFAULT_PATHNO_SYSTEM_ENVIRONMENT_PATH
  5. 跳过NO_DEFAULT_PATHNO_CMAKE_SYSTEM_PATH
  6. 跳过与NO_DEFAULT_PATH

所以刚开始那样子你会跳过步骤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生成的文件并重新开始。它也不会混乱你的源代码树。

+0

好吧,我已经尝试修改我的CMakeLists.txt中的find_library命令,正如你所建议的那样,但我仍然得到相同的行为(在删除所有cmake生成的文件后),即没有'-L/usr/local/lib'尝试链接时遇到'CMakeFiles/delme.dir/link.txt'和未定义的符号。 感谢关于构建'build'文件夹的提示,这是我将要研究的下一个内容。我对cmake相当陌生,但对复杂的makefile有相当丰富的经验。 – 2014-10-03 07:24:18