2014-10-02 101 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