2014-10-02 2 views
0

Я компиляции простую тестовую программу, которая делает использование lapack, однако у меня есть 3 версии LaPack библиотеки, установленной (один из Apple, в /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 версий, но не от Apple версия, которая, кажется, та, с которой она связана. Если я вручную добавлю -L/usr/local/lib в файл сгенерированный CMake CMakeFiles/delme.dir/link.txt, тогда он компилируется отлично.

Мой вопрос: как я могу указать cmake включить -L/usr/local/lib в его ссылку (или другую альтернативу), чтобы она использовала версию в /usr/local/lib?

+0

Из трех путей библиотеки, любые из них в переменной окружения PATH? И в каком порядке они? – jmstoker

+0

Нет, ни один из путей библиотеки не находится в переменной среды $ PATH. –

ответ

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' для каждой библиотеки? –

+1

Вы должны передать соответствующие флаги ('-L') в' target_link_libraries' самостоятельно. Также см. Http://stackoverflow.com/questions/6984479/cmake-how-to-link-a-library-without-automatic-search-function-find-package. – sakra

+0

Итак, вместо использования 'find_library', я могу просто использовать' set (libraries -L/usr/local/lib -llapack -latlas -lcblas) 'и' target_link_libraries (delme $ {libraries}) '. Это также компилируется и кажется намного проще. :-) –

1

Возможно, что один из других путей библиотеки находится в кэшированной переменной cmake. Сначала CMake находит эту версию библиотеки. После того, как библиотека будет найдена, find_library не будет запрашивать снова для той же библиотеки, если только кеш не будет очищен.

Как указано в documentation, команда find_library использует следующий порядок при поиске библиотеки:

  1. поиска пути, указанном в переменном кэше CMake-специфичен.
  2. Пути поиска, указанные в переменных среды, специфичных для cmake.
  3. Поиск путей, указанных опцией HINTS.
  4. Поиск стандартных переменных среды системы.
  5. Поиск переменных cmake, определенных в файлах платформы для текущей системы.
  6. Поиск путей, указанных в параметре PATHS или в короткой версии команды.

Основы из этих шагов, CMake находит другую версию библиотеки на шаге 1 или 2. параметров существуют, чтобы пропустить некоторые или все из этих шагов.

  1. Пропущенные с NO_DEFAULT_PATH или NO_CMAKE_PATH.
  2. Пропущено с NO_DEFAULT_PATH или NO_CMAKE_ENVIRONMENT_PATH.
  3. Пропущено с NO_DEFAULT_PATH.
  4. Пропущено с NO_DEFAULT_PATH или NO_SYSTEM_ENVIRONMENT_PATH.
  5. Пропущено с NO_DEFAULT_PATH или NO_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

ОК, я пробовал изменить команду find_library в моем CMakeLists.txt, как вам было предложено, но я все равно получаю такое же поведение (после удаления всех файлов, созданных cmake), то есть без '-L/usr/local/lib' в 'CMakeFiles/delme.dir/link.txt' и undefined символы при попытке ссылки. Спасибо за отзыв о создании в папке 'build', это было следующим, что я собирался изучить. Я довольно новичок в cmake, но имею большой опыт работы со сложными make-файлами. –

Смежные вопросы