Перейти к содержимому

Cmake как подключить библиотеку

  • автор:

Cmake: линк библиотеки лежащий в отдельной папке

Здравствуйте! Есть проект, который выглядит примерно вот так:

engine/CMakeLists.txt engine/libs/SOIL/libSOIL.a 

Как можно подключить эту библиотеку (libSOIL.a) к моему проекту CMakeLists.txt?

egordorichev
02.04.15 10:40:02 MSK

1. Написаь свой Find***.cmake.

2. Включить либу в состав проекта.

panter_dsd ★★★★
( 02.04.15 10:42:43 MSK )
Последнее исправление: panter_dsd 02.04.15 10:42:50 MSK (всего исправлений: 1)

ну гугл же первыми ссылками поможет

gavlig ★★★
( 02.04.15 10:43:57 MSK )
Ответ на: комментарий от panter_dsd 02.04.15 10:42:43 MSK

Всмысле, использовать find_package?

egordorichev
( 02.04.15 10:44:08 MSK ) автор топика
Ответ на: комментарий от egordorichev 02.04.15 10:44:08 MSK

panter_dsd ★★★★
( 02.04.15 10:45:04 MSK )
Ответ на: комментарий от panter_dsd 02.04.15 10:45:04 MSK

Ну в том то и дело, что этой либы может не быть в системе, поэтому я ее тащу вместе с проектом

egordorichev
( 02.04.15 10:46:23 MSK ) автор топика
Ответ на: комментарий от egordorichev 02.04.15 10:46:23 MSK

Так засунь ее в проект, чтобы она собиралась вместе с проектом и будешь ее линковать просто по имени.

panter_dsd ★★★★
( 02.04.15 10:52:08 MSK )
Ответ на: комментарий от egordorichev 02.04.15 10:46:23 MSK

Вот поэтому тебе и предлагали написать свой Find. А там уже ищи ее, где хочешь. устанавливай свои макросы, какие хочешь и подключай потом как хочешь. Ну или говори «ошибка, дайте либу».

Что это и зачем нужно

CMake — кроссплатформенная автоматизированная система сборки проектов. Непосредственно сборкой она не занимается, а только генерирует Makefile, который потом будет выполнен утилитой make.

CMake может проверять наличие необходимых библиотек и подключать их, собирать проекты под разными компиляторами и операционными системами. Т.е. у вас есть куча кода и файлик, содержащий информацию для cmake, и чтобы скомпилить это дело где-нибудь еще, вам нужно просто запустить там cmake, который сделает всё сам. Удобно, полезно, просто.

Краткое описание

Если нет желания/времени/сил читать весь туториал и Вы используете какой-нибудь QtCreator (или любая другая IDE, умеющая работать с cmake), то:

  • Создайте в IDE проект под cmake
  • Найдите в папке с проектом CMakeFiles.txt
  • Пробегитесь глазами по туториалу, соотнося его с вашим CMakeFiles.txt

Про подключение библиотек рекомендуется все-таки прочитать целиком.

Старт

Предполагается, что найти и скачать сам cmake ты, %username%, в состоянии. //а если нет?

Предположим, у Вас есть исходничек «test.cpp» (// а если нет?)(А если нет, то CMake тебе трогать рано). Для начала нужно создать файлик для cmake, который обычно называют «CMakeLists.txt», и написать туда вот это:

add_executable(test test.cpp)

Теперь запускаем (из консоли) в этой папке команду «cmake CMakeLists.txt» (аргументом можно передавать не только файл, но и директорию, в которой он лежит, тогда cmake найдет его сам).

cmake будет использовать переданный (или найденный) файл проекта (тот самый CMakeLists.txt), и в текущей директории будет создавать проект. Проект — это много-много файлов и директорий (примечание: поэтому лучше запускать cmake из другой директории, чтобы можно было, например, быстро удалить все бинарники), из которых нас больше всего интересует Makefile.

Makefile — это файл, нужный для утилиты make. Именно она запускает компиляторы, линковщики и прочие радости. Запускаем make в каталоге сборки (т.е. там же, где Вы запускали cmake). В консоли вылезет примерно такой текст:

Scanning dependencies of target test [100%] Building CXX object CMakeFiles/test.dir/test.cpp.o Linking CXX executable test [100%] Built target test

А у Вас в папочке появится исполняемый файл «test». Запустите, убедитесь, что это действительно то, что ожидается от компиляции файла «test.cpp».

Подробное описание

Поразбираемся с различными возможностями cmake.

Указание необходимой версии cmake

cmake_minimum_required(VERSION 2.6)

Указывайте высокую минимальную версию CMake. Если используемая версия cmake меньше 2.6, он не захочет работать. Писать эту команду всегда — хороший стиль (cmake будет пыхтеть и обижаться, если вы не укажете версию, но собирать всё равно всё будет).

Название проекта

project(visualization)

Указывает, что этот cmake-файл является корневым для некоторого проекта. С проектами связаны определенные переменные и поведение cmake (читайте документацию).

Переменные

В cmake можно создавать текстовые переменные. Команда

set(VARIABLE The variable's value)

запишет в переменную «VARIABLE» значение «The variable’s value». Чтобы где-либо использовать значение этой переменной, нужно написать $.

Чтобы добавить к переменной некий текст, можно сделать так:

set(VARIABLE "$ new text")

Как видите, использовать значение можно и внутри кавычек. Переменные активно используются различными библиотеками — для установки флагов, параметров сборки/линковки и прочих вкусностей, об этом чуть-чуть попозже.

Пример коше’гного проекта со списком сорцов в отдельной переменной:

cmake_minimum_required(VERSION 2.6) set(SOURCES test.cpp lib1.cpp lib2.cpp) add_executable(test $)

Устанавливаем команды компилятору

add_definitions(-DSOME_IMPORTANT_DEFINITION)

Эта команда используется для установки дефайнов, которыe можно проверить в коде через, например, #ifdef SOME_IMPORTANT_DEFINITION.

set(CMAKE_CXX_FLAGS "$ -std=c++11 -Wall")

Эта команда добавит к флагам, используемым при сборке c++-кода, флаги -std=c++11 и -Wall.

Кто не знает: «-std=c++11» включает в gcc поддержку стандарта c++11, «-Wall» говорит gcc выводить все предупреждения (очень советую, помогает отловить много глупых багов и писать аккуратный код).

Если ваша версия GCC меньше, чем 4.7.0, вместо -std=c++11 нужно использовать -std=c++0x.

В GCC 4.8.0 появился флаг -std=c++1y, в котором начинают реализовывать фичи следующего стандарта.

Папка с хедерами

Допустим, Вы хотите, чтобы хедеры (файлики, подключаемые через #include) искались еще и в каталогах «headers/» и «more_headers/»:

include_directories("headers/" "more_headers/")

Надеюсь, и это понятно.

Самое важное — подключение библиотек

Научимся искать и подключать библиотеки при помощи cmake на примере Boost. Для начала установим переменные для буста:

set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON)

Первое — мы не хотим, чтобы буст подключался к нам статически (т.е. хотим динамическую линковку). Если ты, %username%, не знаешь, что это, пока просто забей и используй этот флаг так, как написано. Но в ближайшее время узнай, о чем речь. Второй флаг разрешает бусту внутри своих магических реализаций использовать треды для распараллеливания и прочих радостей.

Итак, мы установили флаги. Давайте найдем буст!

Допустим, нам нужны компоненты буста под названием chrono (библиотека для работы со временем) и filesystem (библиотека для работы с файловой системой):

find_package(Boost COMPONENTS chrono filesystem REQUIRED)

Win, будут искаться только нужные библиотеки, и их расположение будет записано в переменную Boost_LIBRARIES.

Опция «REQUIRED» говорит о том, что библиотека необходима проекту. Без нее cmake решит, что отсутствие данной библиотеки — не так уж и страшно, и будет собирать дальше.

Добавим директории с хедерами буста для поиска в них хедеров:

include_directories($)

Итак, осталось найденные библиотеки подключить к исполняемому файлу.

target_link_libraries(test $)

В качестве библиотек нужно указать пути к необходимым собранным библиотекам. cmake нашел указанные нами библиотеки и записал в переменную, чем мы и пользуемся.

Заметим, что эту команду нужно вызывать после того, как создан target сборки (через add_executable).

Пример хорошего CMakeLists.txt и где он будет лежать

Итак, полный пример использования всего этого. У нас есть некая директория (отныне считаем ее «/sources»), и в ней лежат исходники

/sources/lib1/main.cpp /sources/lib2/main.cpp /sources/main.cpp

В корне «/» лежит файл «/CMakeLists.txt»:

cmake_minimum_required(VERSION 2.8) project(cmake-example) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON) find_package(Boost COMPONENTS chrono filesystem REQUIRED) set(CMAKE_CXX_FLAGS "$\$$ -std=c++11 -Wall") set(SRC_LIST lib1/main.cpp lib2/main.cpp main.cpp) add_executable($\$$ $\$$) target_link_libraries($\$$ $\$$)

Если Вам что-то в нём не понятно — перечитайте соответствующую информацию выше.

Создаем директорию «/build» (не «/sources/build»), переходим в нее, запускаем в ней «cmake ..». «..» — метка родительской директории. cmake возьмет из нее наш CMakeLists.txt и по нему создаст проект в папке «/build». Чтобы проект собрать, запускаем «make» в той же папке «/build».

Таким образом, в корне у нас есть:

  • CMakeLists.txt
  • директория с исходниками
  • каталог сборки

Все разделено, автоматизировано и удобно.

Как создать библиотеку в поддиректории и слинковать ее с основной программой

Пусть в ./ лежит основной проект, а в ./subdir мы хотим сделать либу, а в ./build построить проект.

project(MegaLibrary) set(SOURCES lib.cpp) set(HEADERS lib.h) add_library(lib $\$$ $\$$) target_include_directories(lib PUBLIC $\$$)
project(MainProject) set(MAIN_PROJECT_SRC_LIST main) # Other stuff
add_executable(main $\$$) add_subdirectory(subdir) target_link_libraries(main lib)

Теперь можно в файлах основного проекта делать #include «lib.h» (см. документацию по target_include_directories).

В ./build запускаем «cmake .. && make» и получаем собранный проект.

Как использовать CMake в связке с QtCreator

Интеграция с cmake у QtCreator не очень тесная, тем не менее, работать с ним можно.

Создаем новый проект без использования Qt, выбираем «Проект на С++ с использованием CMake». Создастся дефолтный файл сборки, который просто добавляет все исходники в директории проекта и компилирует их в один бинарник.

Как добавить header в проект, чтобы его было видно в списке файлов

Если вы создали файл header.h в директорию проекта, просто строчку

add_executable($\$$ $\$$)
add_executable($\$$ $\$$ "header.h")

CMake. Как подключить библиотеку из файла?

Существуют тысячи статей в интернете по поводу того, как же подключить предсобранную библиотеку к своему проекту, использующему cmake, но ни одна из статей мне не помогла.

У меня есть библиотека для представления приближенных чисел, собираемая в статическую библиотеку.

Конфигурация библиотеки

cmake_minimum_required(VERSION 3.19) project(approx_lib) set(CMAKE_CXX_STANDARD 20) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY $/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY $/bin/examples) add_library(approx_lib STATIC include/approx_number.h src/approx_number.cpp) target_include_directories(approx_lib PUBLIC include/) install(TARGETS approx_lib LIBRARY DESTINATION lib)

Как можно заметить по конфигурации, в ней присутствует класс approx_number, разделенный на заголовочный файл approx_number.h и реализацию approx_number.cpp.
После сборки библиотеки производим установку в по пути /usr/local/lib/libapprox_lib.a

Есть приложение, которое библиотеку использует

Конфигурация приложения

cmake_minimum_required(VERSION 3.19) project(just_calculator VERSION 1.0.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) find_library(APPROX_LIB approx_lib HINTS /usr/local/lib REQUIRED) message(STATUS "Found approx_lib: $") add_executable(just_calculator main.cpp) target_link_libraries(just_calculator LINK_PUBLIC $)

После загрузки конфигурации видим, что библиотека нашлась

-- Found approx_lib: /usr/local/lib/libapprox_lib.a -- Configuring done -- Generating done

Для работы приложения нам нужен класс approx_number, а значить надо подключить заголовочный файл approx_number.h из библиотеки.
Прописываем в main.cpp #include

60baa8c8ea456812711705.png

Но получаем сообщение об ошибке:

Так как же подключить библиотеку?

  • Вопрос задан более двух лет назад
  • 2482 просмотра

Комментировать
Решения вопроса 1

Так у вас либа из двух частей — собственно, архив .a, и хедер (или хедеры).

install(TARGETS approx_lib LIBRARY DESTINATION lib) — ставит только собранный target (т.е. непосредственно файл статик либы), но не хедер!

Если не производить установку — можно либу подключить как add_subdirectory с путём к исходникам. Тогда она будет частью основного проекта, будет собираться вместе с ним и всё нужное найдётся (покуда target_include_directories прописан и знает, где искать).

Если устанавливать — то, очевидно, надо установить и хедеры тоже. И ещё как-то сообщить проекту, где что лежит.

Вот кусочек из нашей кастомной сборки icu (пусть имя пакета будет foo, а не icu. А namespace — baz. Так интереснее!)

add_library(icu . ) target_include_directories(icu PUBLIC $/source/common>$) install ( TARGETS icu EXPORT icuExport RUNTIME DESTINATION lib LIBRARY DESTINATION lib ) install ( DIRECTORY source/common/unicode DESTINATION include/icu FILES_MATCHING PATTERN "*.h") # install exports set ( CMAKE_CMAKE_DIR "lib/cmake/foo" ) install ( EXPORT icuExport FILE foo-targets.cmake DESTINATION "$" NAMESPACE baz:: ) file ( WRITE foo-config.cmake "if(NOT TARGET baz::icu) include(\"\$/foo-targets.cmake\") endif()") install ( FILES foo-config.cmake DESTINATION "$" )

Здесь несколько моментов.
Во-первых, обратите внимание на target_include_directories. Там два пути. Один будет работать при сборке, второй — при инсталляции. Т.е. когда собирается либа, либо подключается через add_subdirectory — найдётся нужное по первому пути. После установки — по второму, и этот второй — относительный.

Во-вторых, при установке задано имя export. Это что-то вроде именованного набора разных свойств, которые cmake накапливает из добавленных с этим именем целей и потом может оформить в файл экспорта. В данном случае туда попадает явно прописанная библиотека, и неявно — include-path от неё, последний потому что он изначально включён как public.

В-третьих, собственно, ставим помимо таргета и сами хедеры!

И в-последних, ставим то, что «накопил» экспорт. Первый файл foo-targets.cmake. Второй — который будет работать при поиске пакета (я его осознанно упростил, на самом деле он длиннее) foo-config.cmake.

Всё это куда-то ставится. Например, в /root/bar (для определённости) — как `cmake —install . —prefix /root/bar`. У вас оно прямо в систему, но тут спецом левый путь, чтобы глазами было видно, как он в конфиге пробрасывается и используется.

Потом в самом проекте — не надо никаких find_library, всё же известно, где!

LIST (APPEND CMAKE_PREFIX_PATH "/root/bar") find_package(foo) add_executable(my_prog main.cpp) target_link_libraries(my_prog PRIVATE baz::icu)

find_package сперва пытается найти модуль FindFoo.cmake. Такого нет. Потом пытается найти конфиг FooConfig.cmake или foo-config.cmake. Он разыскивается по указанному префиксу (там весьма развесистый алгоритм, который умеет заглядывать в разные папки, в доках всё есть) и включается. Он, в свою очередь, включает. foo-targets.cmake, сгенерированный из экспорта. И вот там и находится вся магия.

. # это сгенерированный код! # Create imported target baz::icu add_library(baz::icu STATIC IMPORTED) set_target_properties(baz::icu PROPERTIES INTERFACE_COMPILE_DEFINITIONS "U_STATIC_IMPLEMENTATION;U_CHARSET_IS_UTF8=1;U_NO_DEFAULT_INCLUDE_UTF_HEADERS=1" INTERFACE_INCLUDE_DIRECTORIES "$/include/icu" ) . # Load information for each installed configuration. get_filename_component(_DIR "$" PATH) file(GLOB CONFIG_FILES "$/foo-targets-*.cmake") foreach(f $) include($) endforeach() . . а это файл foo-targets-relwithdebinfo.cmake # Import target "baz::icu" for configuration "RelWithDebInfo" set_property(TARGET baz::icu APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO) set_target_properties(baz::icu PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELWITHDEBINFO "CXX" IMPORTED_LOCATION_RELWITHDEBINFO "$/lib/libicu.a" )

а вообще в доках cmake (не надо никаких левых вики/SO!) этой теме посвящён большой и подробный раздел.

Как подключить библиотеку к Cmake?

Я всегда писал код в visual studio совершенно не парясь ни о чём, но теперь я пытаюсь написать небольшую программку, которая будет работать как на windows, так и на linux. Хорошо, я создал проект Cmake, теперь мне нужно подключить библиотеки (glm, glfw, sockpp) Glm и glfw я подключил, просто скопировав репозиторий из гитхаба и прописав в cmakelists.txt
add_subdirecory([путь до папки])
target_link_libraries(myproject [название библиотеки из её cmakelists]) Но с sockpp возникла проблема, при сборке компилятор пишет Ошибка LNK1104 не удается открыть файл «sockpp.lib»
При этом проект нормально собирается утилитой Cmake gui, но он выплевывает проект visual studio, а мне нужна кроссплатформенность. Правильно ли я подключаю библиотеки к своему проекту? Как их нужно подключать? Если я хочу подключить библиотеку, которая не содержит cmakelists.txt, а только makefile, (например asio) то как быть? Есть ли пути написания кроссплатформенных программ без Cmake?

Отслеживать

задан 19 июн 2021 в 10:38

1 1 1 бронзовый знак

Тут слишком много вопросов в одном вопросе. Cmake для написания кроссплатформенных программ не нужен вообще. Зато нужен тулсет для кросс компиляции или машина нативным тулсетом для целевой платформы. А подключать разные библиотеки на разных платформах в cmake придется очень по-разному.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *