dsp-site/wiki/Prog/Development/CMake управление проектом.adoc

959 lines
35 KiB
Plaintext
Raw Normal View History

2019-06-01 21:08:41 +00:00
= CMake: управление проектом
2019-06-02 16:31:29 +00:00
:title-separator: {sp}|
2019-06-01 21:08:41 +00:00
:category: Программирование
:tags: программирование, cmake,
:toc:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
== Полезные ссылки
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
* https://github.com/onqtam/awesome-cmake[Каталог ссылок]
2020-04-09 16:23:16 +00:00
* https://cgold.readthedocs.io/en/latest/index.html[CGold: The Hitchhikers Guide to the CMake]
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
== Структура каталогов проекта
2019-04-20 08:38:43 +00:00
Файлы проекта и результаты компиляции размещаются в каталогах:
2019-06-01 21:08:41 +00:00
....
2020-04-09 16:23:16 +00:00
└── project
2019-04-20 08:38:43 +00:00
├── _build
2020-04-06 05:49:00 +00:00
│ ├── debug
│ │ ├── bin
│ │ ├── etc
│ │ ├── files
│ │ │ ├── data
│ │ │ ├── lib
│ │ │ └── log
│ │ ├── include
│ │ └── lib
│ └── release
2019-04-20 08:38:43 +00:00
├── .git
2020-04-06 05:49:00 +00:00
├── .gitlab-ci
2019-04-20 08:38:43 +00:00
├── cmake
│ ├── cmlib
2020-04-06 05:49:00 +00:00
│ ├── doc
2019-04-20 08:38:43 +00:00
│ ├── etc
2020-04-06 05:49:00 +00:00
│ │ └── uncrustify
2019-04-20 08:38:43 +00:00
│ ├── find
│ └── generators
├── doc
├── files
2020-04-06 05:49:00 +00:00
│ ├── data
2019-04-20 08:38:43 +00:00
│ ├── etc
2020-04-06 05:49:00 +00:00
│ ├── lib
│ └── log
2019-04-20 08:38:43 +00:00
├── l10n
├── src
│ ├── app
│ └── lib
├── thirdparty
└── tools
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
Назначение каталогов приведено в таблице.
2020-04-08 17:09:58 +00:00
[cols="2,4",options="header",]
2019-06-01 21:08:41 +00:00
|===
2020-04-09 16:23:16 +00:00
|Каталог | Назначение
|`_build` | Результаты компиляции
|`_build/debug` | Результаты компиляции в режиме отладки
|`_build/debug/bin` | Исполняемые файлы
|`_build/debug/etc` | Символическая ссылка на каталог `cmex/files/etc`
|`_build/debug/files/data` | Символическая ссылка на каталог `cmex/files/data`
|`_build/debug/files/lib` | Символическая ссылка на каталог `cmex/files/lib`
|`_build/debug/files/log` | Символическая ссылка на каталог `cmex/files/log`
|`_build/debug/include` | Заголовочные файлы копируемые и генерируемые во время сборки
|`_build/debug/lib` | Статические и динамические библиотеки
|`_build/release` | Результаты компиляции в режиме выпуска (иерархия аналогична `debug`)
|`.git` | Системные файлы репозитория git
|`.gitlab.ci` | Шаблон правил для автоматической сборки на сервере Gitlab
|`cmake` | Файлы с дополнительными функциями для CMake
|`cmake/cmlib` | Библиотека функций для CMake
|`cmake/doc` | Правила для автоматической генерации документации
|`cmake/etc` | Файлы настроек, используемые в CMake
|`cmake/etc/uncrustify` | Файл настройки для программы автоматического форматирования исходных текстов
|`cmake/find` | Модули CMake для поиска внешних программ и библиотек
|`cmake/generators` | Генераторы проектов
|`doc` | Документация для проекта
|`files` | Каталог для дополнительных файлов
|`files/etc` | Каталог для файлов настроек проекта
|`files/data` | Каталог для неизменяемых файлов
|`files/lib` | Каталог для изменяемых файлов
|`files/log` | Каталог для журналов
|`l10n` | Файлы переводов
|`src` | Исходные тексты
|`src/app` | Исходные тексты программы
|`src/lib` | Исходные тексты библиотеки
|`thirdparty` | Исходные тексты дополнительных и сторонних проектов
|`tools` | Дополнительные утилиты
2019-06-01 21:08:41 +00:00
|===
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
Каталог `_build` создаётся, чтобы избежать попадания создаваемых во время
2019-06-01 21:08:41 +00:00
сборки файлов в иерархию основного проекта. Запись результатов сборки
проекта внутрь иерархии каталогов с исходными текстами приводит к
засорению формируемыми на этапе сборки файлами, которые затрудняют
разработку, поиск в оригинальных файлах и мешают ориентироваться в
проекте. При работе с несколькими типами сборки, например, отладка и
выпуск, появляется необходимость корректного полного удаления
результатов предыдущего тип сборки.
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
[[base-project]]
== Базовый проект
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
Проект, в котором выполнены приведённые в данном разделе действия,
можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-base[здесь]
или сделать его копию командой:
2019-06-03 07:03:24 +00:00
[source,sh]
----
2020-04-09 16:23:16 +00:00
git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-base
2019-06-03 07:03:24 +00:00
----
2020-04-09 16:23:16 +00:00
=== Инициализация подмодулей
Для начала нужно создать каталог для проекта, перейти в него и
инициализировать репозиторий git:
[source,sh]
----
mkdir cmlib-example-base
cd cmlib-example-base
git init
----
Для подключения основных подмодулей, содержащих дополнительные функции
для работы с проектом, и фиксации произведённого изменения нужно выполнить:
[source,sh]
----
2020-04-10 15:10:40 +00:00
git submodule add https://git.246060.ru/f1x1t/cmlib.git cmake/cmlib
git submodule add https://git.246060.ru/f1x1t/cmake-find.git cmake/find
git submodule add https://git.246060.ru/f1x1t/cmake-generators.git cmake/generators
git submodule add https://git.246060.ru/f1x1t/cmake-doc.git cmake/doc
git submodule add https://git.246060.ru/f1x1t/uncrustify-config.git cmake/etc/uncrustify
2020-04-09 16:23:16 +00:00
git commit -a -m "Начало проекта"
----
2020-04-09 17:10:52 +00:00
Отправить изменения в проекте на сервер и сделать ветку `master` основной
(можно пропустить):
2020-04-09 16:23:16 +00:00
[source,sh]
----
git remote add origin АДРЕС_РЕПОЗИТОРИЯ_НА_СЕРВЕРЕ
git push -u origin master
----
Загрузить шаблоны для автоматической сборки проекта в разных вариантах
программных окружений и зафиксировать изменения:
[source,sh]
----
mkdir .gitlab-ci
wget -O .gitlab-ci/scheduled.yml https://git.246060.ru/f1x1t/gitlab-ci/raw/branch/master/.gitlab-ci/scheduled.yml
wget -O .gitlab-ci.yml https://git.246060.ru/f1x1t/gitlab-ci/raw/branch/master/.gitlab-ci.yml
git add .gitlab-ci.yml .gitlab-ci/scheduled.yml
git commit -m "Настройка автосборки"
----
Загрузить файл настройки для анализатора Clang-Tidy:
[source,sh]
----
wget https://git.246060.ru/f1x1t/clang-tidy-config/raw/branch/master/.clang-tidy
git add .clang-tidy
git commit -m "Настройка Clang-Tidy"
----
Создать стандартные файлы и каталоги:
[source,sh]
----
mkdir -p doc/breathe
touch doc/breathe/index.md.in
mkdir -p files/etc
touch files/etc/.keep-directory
mkdir -p files/data
touch files/data/.keep-directory
mkdir -p files/lib
touch files/lib/.keep-directory
mkdir -p files/log
touch files/log/.keep-directory
git add doc files
git commit -m "Стандартные файлы и каталоги"
----
Создать файл `.gitignore` для исключения каталогов и файлов из-под контроля git:
[source,sh]
----
wget https://git.246060.ru/f1x1t/cmlib-gitignore/raw/branch/master/.gitignore
git add .gitignore
git commit -m "Шаблон для игнорирования каталогов и файлов"
----
=== Базовые инструкции в CMake
В корневом каталоге проекта нужно создать файл `CMakeLists.txt`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2020-04-09 16:23:16 +00:00
# Минимальная версия CMake
2019-04-20 08:38:43 +00:00
cmake_minimum_required(VERSION 3.3)
2020-04-09 16:23:16 +00:00
# Предпочтительно следовать стандартам принятым в указанном диапазоне версий
2019-04-20 08:38:43 +00:00
cmake_policy(VERSION 3.0.2..3.7)
# Название и версия проекта и используемые языки программирования
2020-04-09 16:23:16 +00:00
project(cmlib-example-base VERSION 0.2.0 LANGUAGES C CXX)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
Значение версии следует формировать согласно правилам
2019-06-01 21:08:41 +00:00
https://semver.org/lang/ru/[семантического версионирования].
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
Для подключения функций для CMake из библиотеки CMLib, нужно добавить
в файл `CMakeLists.txt` строки:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# В каталоге cmake/cmlib находятся файлы с библиотечными функциями
if(IS_DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/cmlib)
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/cmlib)
else()
message(FATAL_ERROR "CMake library directory does not exist")
endif()
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/find)
include(CMLibCommon)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-09 17:43:02 +00:00
[[variables-cmake]]
2020-04-09 16:23:16 +00:00
В каталоге `cmake/etc` требуется создать файл `Variables.cmake`,
2020-04-09 17:41:13 +00:00
в котором должны быть определены переменные, используемые
библиотекой CMLib для архивирования исходных текстов, автоматического
создания пакетов, генерации документации:
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
[source,cmake]
----
set(ORGANIZATION_NAME "org")
set(AUTHOR_NAME "John Doe")
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
set(DOXYGEN_PROJECT_TITLE "Пример проекта (начало)")
set(DOXYGEN_GENERATE_LATEX YES)
set(DOXYGEN_GENERATE_HTML YES)
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
set(CPACK_GENERATOR "TXZ;DEB")
set(CPACK_PACKAGE_CONTACT "John Doe <box@mail.domain>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CMake project example")
set(CPACK_DEBIAN_PACKAGE_SECTION "misc")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_SOURCE_IGNORE_FILES
2020-04-11 11:57:13 +00:00
"${CMAKE_BINARY_DIR}"
"/\\\\.git/"
"/\\\\.gitlab-ci/"
"^${CMAKE_SOURCE_DIR}/.?build.?/"
"^${CMAKE_SOURCE_DIR}/.?output.?/"
"^${CMAKE_SOURCE_DIR}/files/lib"
"^${CMAKE_SOURCE_DIR}/files/log"
"\\\\.clang-tidy$"
"\\\\.cmake-format$"
"\\\\.gitignore$"
"\\\\.gitattributes$"
"\\\\.gitmodules$"
"\\\\.gitlab-ci.yml"
"CMakeLists.txt.user.*"
"~$"
"\\\\.swp$")
2020-04-09 16:23:16 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
Произведённые изменения можно зафиксировать:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,sh]
----
2020-04-09 16:23:16 +00:00
git add cmake/etc/Variables.cmake CMakeLists.txt
git commit -m "Подключение библиотеки CMLib"
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-09 16:23:16 +00:00
Чтобы проверить корректность подключения CMLib, можно выполнить команду:
[source,sh]
----
(mkdir -p _build && cd _build && cmake .. && make && echo OK)
----
Если последней строкой вывода будет `OK`, то настройка завершена верно.
2019-06-01 21:08:41 +00:00
== Поиск системных библиотек
2019-04-20 08:38:43 +00:00
2020-04-09 17:10:52 +00:00
Поиск программ, библиотек и заголовочных файлов, установленных в системе, можно
выполнять с помощью программы https://en.wikipedia.org/wiki/Pkg-config[`pkg-config`]
или функции CMake `find_package`. В любом случае для указания того,
что наличие искомого объекта обязательно для сборки, используется
параметр `REQUIRED`.
=== Поиск с помощью программы `pkg-config`
Программа `pkg-config` хранит базу данных параметров (обычно в каталогах
`/usr/share/pkgconfig`, `/usr/lib/pkgconfig` и `/usr/lib/x86_64-linux-gnu/pkgconfig`),
содержащую флаги компиляции для поиска заголовочных файлов и компоновки
библиотек, установленных в систему. Для использования в CMake сначала
необходимо выполнить проверку наличия программы `pkg-config` в системе
и подключить определённую в модуле `PkgConfig` функцию `pkg_check_modules`.
Например, для поиска библиотек `gsl`, `fftw3` и `udev` можно написать
в файле `CMakeLists.txt`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Поиск библиотек с помощью pkgconfig
2020-04-09 17:10:52 +00:00
find_package(PkgConfig REQUIRED)
2019-04-20 08:38:43 +00:00
pkg_check_modules(GSL REQUIRED gsl)
pkg_check_modules(FFTW3 REQUIRED fftw3)
pkg_check_modules(UDEV udev)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-09 17:10:52 +00:00
=== Поиск с помощью функции `find_package`
Если системная библиотека поставляется без файла описания для `pkg-config`
или необходимо произвести более сложный поиск, например, включающий поиск
исполняемого файла, то может быть написан специальный модуль для `CMake`,
который вызывается функцией `find_package`. Примеры вызова функции:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Поиск с помощью функции find_package
find_package(LibXml2)
2020-04-09 17:10:52 +00:00
find_package(CURL REQUIRED)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
== Автоматически генерируемый заголовочный файл
2019-04-20 08:38:43 +00:00
2020-04-09 17:10:52 +00:00
На этапе конфигурирования проекта можно сгенерировать файл, в который
будут записаны собранные значения параметров. В библиотеке CMLib
2019-04-20 08:38:43 +00:00
присутствует функция `cmlib_config_hpp_generate()`, создающая файл
2020-04-09 17:10:52 +00:00
`${CMAKE_BINARY_DIR}/include/cmlib_private_config.hpp`, в который
записывается информация о имени и версии проекта, дате и типе сборки.
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Автоматически генерируемый заголовочный файл
cmlib_config_hpp_generate()
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-09 17:10:52 +00:00
2020-04-09 17:35:09 +00:00
== Удаление установленных файлов
В библиотеку CMLib добавлена цель `uninstall`, позволяющая удалить файлы,
которые могут быть установлены в результате выполнения цели `install`:
[source,sh]
----
cd _build/debug
make install
make uninstall
----
2020-04-11 11:57:13 +00:00
== Архивирование проекта и создание пакетов
2020-04-09 17:35:09 +00:00
Стандартный модуль `CPack` предназначен для архивирования исходных
текстов проекта и создания пакетов для установки в целевую систему.
Необходимые переменные устанавливаются в файле `cmake/etc/Variables.cmake`
2020-04-09 17:43:02 +00:00
<<variables-cmake,см. выше>>.
2020-04-09 17:35:09 +00:00
2020-04-11 11:57:13 +00:00
Устанавливаемые файлы делятся на две группы `MAIN` и `DEV` с помощью
параметра `COMPONENT` функции `install`. В группу `MAIN` необходимо
помещать файлы для установки на целевую систему (исполняемые файлы,
файлы настроек, файлы данных, разделяемые библиотеки), а в группу `DEV` ---
для установки на систему для разработки (заголовочные файлы, статические
библиотеки).
2020-04-09 17:35:09 +00:00
2020-04-11 11:57:13 +00:00
По умолчанию цель для упаковки исходных текстов называется `package_source`.
Бинарные пакеты создаются программой `cpack`. Пример:
2020-04-09 17:35:09 +00:00
[source,sh]
----
cd _build/debug
2020-04-11 11:57:13 +00:00
make
make package_source
2020-04-09 17:35:09 +00:00
cpack
----
== Примеры библиотек и приложений
2020-04-10 15:10:40 +00:00
=== Базовая библиотека
2020-04-09 17:10:52 +00:00
2020-04-10 15:10:40 +00:00
Проект с базовой библиотекой реализован на основе <<base-project,базового проекта>>.
Исходные тексты содержат комментарии, объясняющие назначение используемых функций.
Проект можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-library[здесь]
или сделать его копию командой:
2020-04-09 17:10:52 +00:00
2020-04-10 15:10:40 +00:00
[source,sh]
----
git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-library
----
2020-04-09 17:10:52 +00:00
2020-04-10 15:10:40 +00:00
В файл `CMakeLists.txt`, находящийся в корневом каталоге проекта, нужно добавить:
2020-04-09 17:39:10 +00:00
2020-04-10 15:10:40 +00:00
[source,cmake]
----
# Поиск библиотеки Boost
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED OFF)
set(Boost_USE_STATIC_RUNTIME ON)
find_package(Boost 1.55.0 REQUIRED COMPONENTS headers)
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
# Автоматически генерируемый заголовочный файл
cmlib_config_hpp_generate()
# Каталог с исходными текстами библиотеки
add_subdirectory(src/cmlib-example)
# Документация
add_subdirectory(cmake/doc)
# Создание вспомогательных символических ссылок
add_dependencies(cmlib-example create_auxilary_symlinks)
----
В подкаталоге `src/cmlib-example` нужно создать файл `CMakeLists.txt`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2020-04-10 15:10:40 +00:00
# Название основной цели и имя библиотеки в текущем каталоге
set(TRGT cmlib-example)
# Список файлов исходных текстов
2020-04-11 11:57:13 +00:00
set(TRGT_sources ${CMAKE_CURRENT_SOURCE_DIR}/init.cpp)
2020-04-10 15:10:40 +00:00
# Список заголовочных файлов (используется для установки)
2020-04-11 11:57:13 +00:00
set(TRGT_headers ${CMAKE_CURRENT_SOURCE_DIR}/init.hpp)
2020-04-10 15:10:40 +00:00
# Функция для создания цели, результатом которой будет сборка библиотеки
add_common_library(TARGET ${TRGT} SOURCES ${TRGT_sources})
common_target_properties(${TRGT})
# Добавление к пути поиска заголовочных файлов
target_include_directories(${TRGT} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
# Цель, используемая только для установки
# заголовочных файлов без компиляции проекта
2020-04-11 11:57:13 +00:00
add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=DEV -P
"${CMAKE_BINARY_DIR}/cmake_install.cmake")
2020-04-10 15:10:40 +00:00
# Установка статической библиотеки
2020-04-11 11:57:13 +00:00
install(TARGETS ${TRGT}_static COMPONENT DEV ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
2020-04-10 15:10:40 +00:00
# Установка динамической библиотеки
if(BUILD_SHARED_LIBS)
2020-04-11 11:57:13 +00:00
install(TARGETS ${TRGT}_shared COMPONENT DEV LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
2020-04-10 15:10:40 +00:00
endif()
# Установка заголовочных файлов
2020-04-11 11:57:13 +00:00
install(FILES ${TRGT_headers} COMPONENT DEV DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${TRGT})
2020-04-10 15:10:40 +00:00
# Установка файла для pkg-config
2020-04-11 11:57:13 +00:00
install(FILES ${CMAKE_BINARY_DIR}/${TRGT}.pc COMPONENT DEV DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
файл `init.hpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2020-04-10 15:10:40 +00:00
#ifndef CMLIB_EXAMPLE_HPP_
#define CMLIB_EXAMPLE_HPP_
2019-04-20 08:38:43 +00:00
#include <stdint.h>
2020-04-10 15:10:40 +00:00
int32_t cmlib_example_init(int32_t i);
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
#endif // CMLIB_EXAMPLE_HPP_
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
и файл `init.cpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2020-04-10 15:10:40 +00:00
#include "init.hpp"
#include <boost/range/counting_range.hpp>
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
int32_t cmlib_example_init(int32_t i = 0)
{
int32_t s = 0;
for ( auto r : boost::counting_range( 1, i ) )
{
s += r;
}
return s;
2019-04-20 08:38:43 +00:00
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
=== Базовое приложение
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
Проект с базовым приложением реализован на основе <<base-project,базового проекта>>.
Исходные тексты содержат комментарии, объясняющие назначение используемых функций.
2020-04-11 11:57:13 +00:00
Проект можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-app[здесь]
2020-04-10 15:10:40 +00:00
или сделать его копию командой:
[source,sh]
----
2020-04-11 11:57:13 +00:00
git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-app
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
В файл `CMakeLists.txt`, находящийся в корневом каталоге проекта, нужно добавить:
2020-04-11 11:57:13 +00:00
[source,cmake]
----
# Boost
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED OFF)
set(Boost_USE_STATIC_RUNTIME ON)
find_package(Boost 1.55.0 REQUIRED COMPONENTS headers)
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Автоматически генерируемый заголовочный файл
cmlib_config_hpp_generate()
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Приложение
add_subdirectory(src/cmlib-example)
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Документация
add_subdirectory(cmake/doc)
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Создание вспомогательных символических ссылок
add_dependencies(cmlib-example create_auxilary_symlinks)
----
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
В подкаталоге `src/cmlib-example` нужно создать файл `CMakeLists.txt`:
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
[source,cmake]
----
# Название основной цели и имя библиотеки в текущем каталоге
set(TRGT cmlib-example)
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Список файлов исходных текстов
set(TRGT_sources ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Функция для создания цели, результатом которой будет сборка приложения
add_executable(${TRGT} ${TRGT_sources})
common_target_properties(${TRGT})
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Добавление к пути поиска заголовочных файлов
target_include_directories(${TRGT} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
# Имя целевого каталога и выходного файла для цели
set_target_properties(${TRGT}
PROPERTIES
OUTPUT_NAME ${TRGT}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}
)
2019-04-20 08:38:43 +00:00
2020-04-11 11:57:13 +00:00
# Правила для установки
install(TARGETS ${TRGT} COMPONENT MAIN RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-11 11:57:13 +00:00
и файл `main.cpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "compiler_features.hpp"
2020-04-11 11:57:13 +00:00
#include "cmlib_private_config.hpp"
2019-04-20 08:38:43 +00:00
#include <iostream>
2020-04-11 11:57:13 +00:00
#include <boost/range/counting_range.hpp>
2019-04-20 08:38:43 +00:00
2020-04-11 11:57:13 +00:00
int32_t nsum(int32_t i = 0)
{
int32_t s = 0;
for ( auto r : boost::counting_range( 1, i ) )
{
s += r;
}
return s;
2019-04-20 08:38:43 +00:00
}
2020-04-11 11:57:13 +00:00
int main(int argc, char* argv[])
{
// Значение из compiler_features.hpp
std::cout << CMLIB_EXAMPLE_APP_COMPILER_VERSION_MAJOR << std::endl;
// Значение из cmlib_private_config.hpp
std::cout << CMLIB_BUILD_TYPE << std::endl;
// Значение из cmlib_private_config.hpp
std::cout << CMLIB_BUILD_DATE << std::endl;
2019-04-20 08:38:43 +00:00
2020-04-11 11:57:13 +00:00
auto s = nsum( argc );
std::cout << s << std::endl;
2019-04-20 08:38:43 +00:00
2020-04-11 11:57:13 +00:00
return ( s );
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2020-04-10 15:10:40 +00:00
2020-04-11 11:57:13 +00:00
ПИШУ ЗДЕСЬ!!!
2020-04-10 15:10:40 +00:00
2019-06-01 21:08:41 +00:00
== Подключение внешнего проекта
2019-04-20 08:38:43 +00:00
В каталоге `cmex/thirdparty` нужно создать каталог `cmext` с проектом,
2019-08-29 14:34:57 +00:00
состоящим из файла `cmext.hpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,c]
----
2019-04-20 08:38:43 +00:00
#ifndef CMEXT_CMEXT_HPP_
#define CMEXT_CMEXT_HPP_
#include <stdint.h>
int32_t cmext_init(int32_t i);
#endif
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-08-29 14:34:57 +00:00
файла `cmext.cpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,c]
----
2019-04-20 08:38:43 +00:00
#include "cmext.hpp"
int32_t cmext_init(int32_t i = 0) {
2019-06-01 21:08:41 +00:00
return i;
2019-04-20 08:38:43 +00:00
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-08-29 14:34:57 +00:00
и файла `CMakeLists.txt`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
cmake_minimum_required(VERSION 3.3)
project(cmext)
include(GNUInstallDirs)
add_library(cmext cmext.cpp)
install(TARGETS cmext ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES cmext.hpp COMPONENT headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${CMAKE_PROJECT_NAME})
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
В файле `cmex/CMakeLists.txt` нужно подключить стандартный модуль
`ExternalProject` и описать правила для его загрузки, настройки,
компиляции и установки для сопряжения с текущим проектом:
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Подключение внешних проектов
include(ExternalProject)
ExternalProject_Add(cmext
EXCLUDE_FROM_ALL TRUE
2019-06-02 16:31:29 +00:00
SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/cmext
2019-04-20 08:38:43 +00:00
INSTALL_DIR ${CMAKE_BINARY_DIR}
DOWNLOAD_COMMAND ""
BUILD_BYPRODUCTS <INSTALL_DIR>/lib/libcmext.a
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -DCMAKE_BUILD_TYPE=Release
)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-03 07:03:24 +00:00
Вызовы этих функций нужно сделать до функций `add_subdirectories`, чтобы
в подключенных подкаталогах можно было использовать цель `cmext` для
определения зависимостей.
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
В файле `cmex/src/cmex/CMakeLists.txt` нужно подключить внешний проект
`cmext`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Зависимость от библиотеки из внешнего проекта проекта
add_dependencies(${current_target} cmext)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Добавление каталога, в который устанавливаются заголовочные файлы от внешнего
# проекта cmext, к списку путей для поиска заголовочных файлов
target_include_directories(${current_target} PUBLIC
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include/cmext>)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Библиотека из внешнего проекта cmext
target_link_libraries(${current_target} ${CMAKE_BINARY_DIR}/lib/libcmext.a)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
Для проверки работоспособности в файле `cmex/src/cmex/main.cpp` нужно
вызвать функцию `cmext_init` из библиотеки, предоставляемой внешним
2020-04-04 08:51:36 +00:00
проектом. Например, можно заменить его содержимое на:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "compiler_features.hpp"
2019-08-29 14:34:57 +00:00
#include "cmlib_config.hpp"
2019-04-20 08:38:43 +00:00
#include <iostream>
#include <cmext/cmext.hpp>
#include "cmex.hpp"
2019-04-20 12:01:11 +00:00
QTextStream& qStdOut()
{
static QTextStream ts(stdout);
return ts;
}
2019-04-20 08:38:43 +00:00
int main(int argc, char **argv) {
2019-04-20 12:01:11 +00:00
// Значение из compiler_features.hpp
qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Build type: ") << BUILD_TYPE << endl;
// Функция из внутренней библиотеки
qStdOut() << QObject::tr("libcmex function call: ") << cmex_init(4) << endl;
// Функция из внешней библиотеки
qStdOut() << QObject::tr("libcmext function call: ") << cmext_init(9) << endl;
2019-06-01 21:08:41 +00:00
return 0;
2019-04-20 08:38:43 +00:00
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
== Qt5
2019-04-20 08:38:43 +00:00
2019-08-29 14:34:57 +00:00
Для поиска необходимых компонентов Qt5 нужно в файл `cmex/CMakeLists.txt`
перед вызовом функции `cmlib_config_hpp_generate()` нужно добавить строку:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
find_package(Qt5 COMPONENTS Core Network Gui Widgets DBus Concurrent Sql REQUIRED)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
Библиотека CMLib автоматически подключает вызов препроцессора `moc` и
компилятора ресурсов `rcc`, если цель использует модуль `Core`, и
2019-04-20 08:38:43 +00:00
вызывает компилятор файлов описания интерфейса, если цель использует
модуль `Widgets`.
2019-06-01 21:08:41 +00:00
== Консольное приложение
2019-04-20 08:38:43 +00:00
В файл `cmex/src/cmex/CMakeLists.txt` добавить строки:
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Qt5
qt_translation(TARGET ${current_target} TS_DIR ${CMAKE_SOURCE_DIR}/l10n LANGUAGES ru_RU)
target_include_directories(${current_target} SYSTEM PUBLIC ${Qt5Core_INCLUDE_DIRS})
target_compile_options(${current_target} PUBLIC "${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
target_link_libraries(${current_target} Qt5::Core)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
Для проверки работоспособности подключения Qt5 файл
`cmex/src/cmex/main.cpp` нужно заменить на:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "compiler_features.hpp"
2019-08-29 14:34:57 +00:00
#include "cmlib_config.hpp"
2019-04-20 08:38:43 +00:00
#include <QtCore>
#include <iostream>
#include <cmext/cmext.hpp>
#include "cmex.hpp"
2019-04-20 12:01:11 +00:00
QTextStream& qStdOut()
{
static QTextStream ts(stdout);
return ts;
}
2019-04-20 08:38:43 +00:00
int main(int argc, char **argv) {
2019-06-01 21:08:41 +00:00
QCoreApplication app(argc, argv);
QTranslator translator;
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
{
app.installTranslator(&translator);
}
2019-04-20 12:01:11 +00:00
// Значение из compiler_features.hpp
qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Build type: ") << BUILD_TYPE << endl;
// Функция из внутренней библиотеки
qStdOut() << QObject::tr("libcmex function call: ") << cmex_init(4) << endl;
// Функция из внешней библиотеки
qStdOut() << QObject::tr("libcmext function call: ") << cmext_init(9) << endl;
2019-06-01 21:08:41 +00:00
return 0;
2019-04-20 08:38:43 +00:00
}
2019-06-01 21:08:41 +00:00
----
После сборки проекта в каталоге `cmex/l10n` появится файл
`cmex_app_ru_RU.ts`, в котором нужно отредактировать переводы с помощью
программы `linguist`. После сохранения переводов проект нужно
2019-06-02 16:31:29 +00:00
пересобрать, файл переводов в скомпилированном виде будет встроен в
2019-06-01 21:08:41 +00:00
исполняемый файл `cmex`, а доступ к нему будет осуществляться с помощью
кода:
[source,cpp]
----
if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
{
app.installTranslator(&translator);
}
----
== Графическое приложение
Для создания минимального графического приложения нужно создать файл
описания интерфейса `cmex/src/cmex/my_main_window.ui`:
[source,xml]
----
2019-04-20 08:38:43 +00:00
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MyMainWindow</class>
<widget class="QMainWindow" name="MyMainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>678</width>
<height>415</height>
</rect>
</property>
<property name="windowTitle">
<string>Main Window</string>
</property>
<widget class="QWidget" name="centralwidget"/>
</widget>
<resources/>
<connections/>
</ui>
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
заголовочный файл `cmex/src/cmex/my_main_window.hpp`:
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#ifndef CMEX_MY_MAIN_WINDOW_HPP_
#define CMEX_MY_MAIN_WINDOW_HPP_
#include <QWidget>
#include "ui_my_main_window.h"
class MyMainWindow : public QWidget, private Ui::MyMainWindow {
2019-06-01 21:08:41 +00:00
Q_OBJECT
public:
MyMainWindow(QWidget* parent = 0);
virtual ~MyMainWindow();
2019-04-20 08:38:43 +00:00
};
#endif /* CMEX_MY_MAIN_WINDOW_HPP_ */
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
и файл с реализацией конструктора и деструктора
`cmex/src/cmex/my_main_window.cpp`:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "my_main_window.hpp"
MyMainWindow::MyMainWindow(QWidget* parent) {
}
MyMainWindow::~MyMainWindow() {
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
Для отображения графического окна нужно заменить файл
`cmex/src/cmex/main.cpp` на:
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "compiler_features.hpp"
2019-08-29 14:34:57 +00:00
#include "cmlib_config.hpp"
2019-04-20 08:38:43 +00:00
#include <QtCore>
#include <QtWidgets>
#include <iostream>
#include <cmext/cmext.hpp>
#include "cmex.hpp"
#include "my_main_window.hpp"
2019-04-20 12:01:11 +00:00
QTextStream& qStdOut()
{
static QTextStream ts(stdout);
return ts;
}
2019-04-20 08:38:43 +00:00
int main(int argc, char **argv) {
2019-06-01 21:08:41 +00:00
QApplication app(argc, argv);
QTranslator translator;
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
{
app.installTranslator(&translator);
}
2019-04-20 12:01:11 +00:00
// Значение из compiler_features.hpp
qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
2019-08-29 14:34:57 +00:00
// Значение из cmlib_config.hpp
2019-04-20 12:01:11 +00:00
qStdOut() << QObject::tr("Build type: ") << BUILD_TYPE << endl;
// Функция из внутренней библиотеки
qStdOut() << QObject::tr("libcmex function call: ") << cmex_init(4) << endl;
// Функция из внешней библиотеки
qStdOut() << QObject::tr("libcmext function call: ") << cmext_init(9) << endl;
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
MyMainWindow* mmw = new MyMainWindow();
mmw->show();
return app.exec();
2019-04-20 08:38:43 +00:00
}
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
В файле `cmex/src/cmex/CMakeLists.txt` добавить новые файлы к списку
файлов, используемых для компиляции:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
set(current_target_sources
2020-04-04 08:51:36 +00:00
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/my_main_window.cpp
2019-04-20 08:38:43 +00:00
)
set(current_target_uis
2020-04-04 08:51:36 +00:00
${CMAKE_CURRENT_SOURCE_DIR}/my_main_window.ui
2019-04-20 08:38:43 +00:00
)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Цель для создания исполняемого файла
add_executable(${current_target} ${current_target_sources} ${current_target_uis})
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
и добавить строки для подключения графических библиотек Qt5 и
соответствующих им заголовочных файлов:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
target_include_directories(${current_target} SYSTEM PUBLIC ${Qt5Gui_INCLUDE_DIRS})
target_include_directories(${current_target} SYSTEM PUBLIC ${Qt5Widgets_INCLUDE_DIRS})
target_link_libraries(${current_target} Qt5::Gui)
target_link_libraries(${current_target} Qt5::Widgets)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
Во время сборки проекта в файл переводов `cmex/l10n/cmex_app_ru_RU.ts`
2019-06-02 23:26:28 +00:00
будут добавлены новые строки, их нужно перевести с помощью `linguist` и
2019-06-01 21:08:41 +00:00
снова скомпилировать проект.
2019-04-20 08:38:43 +00:00