CMake Tutorial — различия между версиями
Bobrov (обсуждение | вклад) |
м (rollbackEdits.php mass rollback) |
||
(не показано 37 промежуточных версий 14 участников) | |||
Строка 1: | Строка 1: | ||
{{В разработке}} | {{В разработке}} | ||
− | // | + | = Что это и зачем нужно = |
+ | 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
Содержание
- 1 Что это и зачем нужно
- 2 Старт
- 3 Подробное описание
- 3.1 Указание необходимой версии cmake
- 3.2 Название проекта
- 3.3 Переменные
- 3.4 Устанавливаем команды компилятору
- 3.5 Папка с хедерами
- 3.6 Самое важное - подключение библиотек
- 3.7 Пример хорошего CMakeLists.txt и где он будет лежать
- 3.8 Как создать библиотеку в поддиректории и слинковать ее с основной программой
- 4 Как использовать CMake в связке с QtCreator
Что это и зачем нужно
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")