CMake Tutorial — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Новая страница: «Туториал по cmake.»)
 
м (rollbackEdits.php mass rollback)
 
(не показано 38 промежуточных версий 14 участников)
Строка 1: Строка 1:
Туториал по cmake.
+
{{В разработке}}
 +
 
 +
= Что это и зачем нужно =
 +
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".
 +
Чтобы где-либо использовать значение этой переменной, нужно написать ${VARIABLE}.
 +
 
 +
Чтобы добавить к переменной некий текст, можно сделать так:
 +
 
 +
set(VARIABLE "${VARIABLE} new text")
 +
 
 +
Как видите, использовать значение можно и внутри кавычек.
 +
Переменные активно используются различными библиотеками - для установки флагов, параметров сборки/линковки и прочих вкусностей, об этом чуть-чуть попозже.
 +
 
 +
Пример коше'гного проекта со списком сорцов в отдельной переменной:
 +
 
 +
cmake_minimum_required(VERSION 2.6)
 +
 +
set(SOURCES test.cpp lib1.cpp lib2.cpp)
 +
 +
add_executable(test ${SOURCES})
 +
 
 +
=== Устанавливаем команды компилятору ===
 +
 
 +
add_definitions(-DSOME_IMPORTANT_DEFINITION)
 +
 
 +
Эта команда используется для установки дефайнов, которыe можно проверить в коде через, например, #ifdef SOME_IMPORTANT_DEFINITION.
 +
 
 +
set(CMAKE_CXX_FLAGS "${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)
 +
 
 +
Первое - мы не хотим, чтобы буст подключался к нам статически (т.е. хотим динамическую линковку). <span style="color:#a0a0a0">Если ты, %username%, не знаешь, что это, пока просто забей и используй этот флаг так, как написано. Но в ближайшее время узнай, о чем речь.</span> 
 +
Второй флаг разрешает бусту внутри своих магических реализаций использовать треды для распараллеливания и прочих радостей.
 +
 
 +
Итак, мы установили флаги. Давайте найдем буст!
 +
 
 +
Допустим, нам нужны компоненты буста под названием chrono (библиотека для работы со временем) и filesystem (библиотека для работы с файловой системой):
 +
 
 +
find_package(Boost COMPONENTS chrono filesystem REQUIRED)
 +
 
 +
Win, будут искаться только нужные библиотеки, и их расположение будет записано в переменную Boost_LIBRARIES.
 +
 
 +
Опция "REQUIRED" говорит о том, что библиотека необходима проекту.
 +
Без нее cmake решит, что отсутствие данной библиотеки - не так уж и страшно, и будет собирать дальше.
 +
 
 +
Добавим директории с хедерами буста для поиска в них хедеров:
 +
 
 +
include_directories(${Boost_INCLUDE_DIRS})
 +
 
 +
Итак, осталось найденные библиотеки подключить к исполняемому файлу.
 +
 
 +
target_link_libraries(test ${Boost_LIBRARIES})
 +
 
 +
В качестве библиотек нужно указать пути к необходимым собранным библиотекам. 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 "$\$${CMAKE_CXX_FLAGS} -std=c++11 -Wall")
 +
 +
set(SRC_LIST lib1/main.cpp lib2/main.cpp main.cpp)
 +
 +
add_executable($\$${PROJECT_NAME} $\$${SRC_LIST})
 +
target_link_libraries($\$${PROJECT_NAME} $\$${Boost_LIBRARIES})
 +
 
 +
Если Вам что-то в нём не понятно - перечитайте соответствующую информацию выше.
 +
 
 +
Создаем директорию "/build" ('''не''' "/sources/build"), переходим в нее, запускаем в ней "cmake ..".
 +
".." - метка родительской директории.
 +
cmake возьмет из нее наш CMakeLists.txt и по нему создаст проект в папке "/build".
 +
Чтобы проект собрать, запускаем "make" в той же папке "/build".
 +
 
 +
Таким образом, в корне у нас есть:
 +
 
 +
* CMakeLists.txt
 +
* директория с исходниками
 +
* каталог сборки
 +
 
 +
Все разделено, автоматизировано и удобно.
 +
 
 +
=== Как создать библиотеку в поддиректории и слинковать ее с основной программой ===
 +
 
 +
Пусть в ./ лежит основной проект, а в ./subdir мы хотим сделать либу, а в ./build построить проект.
 +
 
 +
./subdir/CMakeLists.txt
 +
project(MegaLibrary)
 +
set(SOURCES lib.cpp)
 +
set(HEADERS lib.h)
 +
add_library(lib $\$${SOURCES} $\$${HEADERS})
 +
target_include_directories(lib PUBLIC $\$${CMAKE_CURRENT_SOURCE_DIR})
 +
 
 +
./CMakeLists.txt
 +
project(MainProject)
 +
set(MAIN_PROJECT_SRC_LIST main)
 +
# Other stuff
 +
 
 +
add_executable(main $\$${MAIN_PROJECT_SRC_LIST})
 +
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($\$${PROJECT_NAME} $\$${SRC_LIST})
 +
 
 +
измените на
 +
 
 +
add_executable($\$${PROJECT_NAME} $\$${SRC_LIST} "header.h")

Текущая версия на 19:39, 4 сентября 2022

Эта статья находится в разработке!

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

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". Чтобы где-либо использовать значение этой переменной, нужно написать ${VARIABLE}.

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

set(VARIABLE "${VARIABLE} new text")

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

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

cmake_minimum_required(VERSION 2.6)

set(SOURCES test.cpp lib1.cpp lib2.cpp)

add_executable(test ${SOURCES})

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

add_definitions(-DSOME_IMPORTANT_DEFINITION)

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

set(CMAKE_CXX_FLAGS "${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(${Boost_INCLUDE_DIRS})

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

target_link_libraries(test ${Boost_LIBRARIES})

В качестве библиотек нужно указать пути к необходимым собранным библиотекам. 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 "$\$${CMAKE_CXX_FLAGS} -std=c++11 -Wall")

set(SRC_LIST lib1/main.cpp lib2/main.cpp main.cpp)

add_executable($\$${PROJECT_NAME} $\$${SRC_LIST})
target_link_libraries($\$${PROJECT_NAME} $\$${Boost_LIBRARIES})

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

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

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

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

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

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

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

./subdir/CMakeLists.txt

project(MegaLibrary)
set(SOURCES lib.cpp)
set(HEADERS lib.h)
add_library(lib $\$${SOURCES} $\$${HEADERS})
target_include_directories(lib PUBLIC $\$${CMAKE_CURRENT_SOURCE_DIR})

./CMakeLists.txt

project(MainProject)
set(MAIN_PROJECT_SRC_LIST main)
# Other stuff
add_executable(main $\$${MAIN_PROJECT_SRC_LIST})
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($\$${PROJECT_NAME} $\$${SRC_LIST})

измените на

add_executable($\$${PROJECT_NAME} $\$${SRC_LIST} "header.h")