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

725 lines
24 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[Каталог ссылок]
* 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
....
2019-04-20 08:38:43 +00:00
└── cmex
├── _build
│ ├── Debug
│ └── Release
├── .git
├── cmake
│ ├── cmlib
│ ├── etc
│ ├── find
│ └── generators
├── doc
├── files
│ ├── etc
│ ├── share
│ └── var
├── l10n
├── src
│ ├── app
│ └── lib
├── thirdparty
└── tools
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
Назначение каталогов приведено в таблице.
2019-06-02 16:31:29 +00:00
[cols="1,3",options="header",]
2019-06-01 21:08:41 +00:00
|===
|Каталог |Назначение
|`cmex/_build` |Результаты компиляции
|`cmex/_build/Debug` |Результаты компиляции в режиме отладки
|`cmex/_build/Release` |Результаты компиляции в режиме выпуска
|`cmex/.git` |Репозиторий git
|`cmex/cmake` |Файлы с дополнительными функциями для CMake
|`cmex/cmake/cmlib` |Библиотека функций для CMake
|`cmex/cmake/find` |Модули CMake для поиска внешних программ и библиотек
|`cmex/cmake/etc` |Файлы настроек, используемые в CMake
|`cmex/cmake/generators` |Генераторы проектов
|`cmex/doc` |Документация для проекта
|`cmake/files` |Каталог для дополнительных файлов
|`cmake/files/etc` |Каталог для файлов настроек проекта
|`cmake/files/share` |Каталог для неизменяемых файлов
|`cmake/files/var` |Каталог для изменяемых файлов
|`cmex/l10n` |Файлы переводов
|`cmex/src` |Исходные тексты
|`cmex/src/app` |Исходные тексты программ
|`cmex/src/lib` |Исходные тексты библиотек
|`cmex/thirdparty` |Исходные тексты сторонних проектов
|`cmex/tools` |Дополнительные утилиты
|===
2019-04-20 08:38:43 +00:00
Каталог `_build` создаётся, чтобы избежать попадания получаемых во время
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
В каталоге `cmex` нужно создать файл `CMakeLists.txt`:
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Минимальная версия Cmake
cmake_minimum_required(VERSION 3.3)
cmake_policy(VERSION 3.0.2..3.7)
# Название и версия проекта и используемые языки программирования
project(cmex 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
2019-06-02 23:26:28 +00:00
В каталог `cmake/cmlib` установить подмодуль CMLib, содержащий функции
2019-06-01 21:08:41 +00:00
для 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
git submodule add ssh://git@gitlab-server/root/cmlib cmake/cmlib
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
и подключить в файле `CMakeLists.txt`:
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
2019-06-01 21:08:41 +00:00
В файле `cmake/etc/organization.txt` записать название организации,
которой принадлежит проект:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
ORG, Inc.
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
В файле `cmake/etc/cpack_ignore.txt` перечислить шаблоны для исключения
из архива, создаваемого целью `dist`. Например:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
cmake/lib/.git$
.git$
files/var
CMakeLists.txt.user
~$
\\\\..*\\\\.bak$
\\\\..*\\\\.tmp$
\\\\..*\\\\.swp$
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
Чтобы проверить корректность файла `CMakeLists.txt`, нужно создать
каталог `_build` в каталоге `cmex`, перейти в него и выполнить команды:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
[source,sh]
----
2019-04-20 08:38:43 +00:00
cmake ..
make
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
Системные библиотеки можно искать с помощью программы `pkgconfig`,
которая хранит базу данных параметров, включающую пути к заголовочным
2019-06-01 21:08:41 +00:00
файлами и перечни библиотек, необходимых для компоновки. Сначала
производится наличие модуля `PkgConfig`, в котором определена функция
`pkg_check_modules`, которая и осуществляет поиск. Например, для поиска
библиотек `gsl`, `fftw3` и `udev` можно написать:
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
find_package(PkgConfig)
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
2019-06-01 21:08:41 +00:00
Если системная библиотека поставляется без файла описания для
`pkgconfig`, то для её поиска может быть написан специальный модуль для
`CMake`, который вызывается функцией `find_package`. Кроме того функция
`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)
find_package(CURL)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
Если для библиотеки нет модуля, выполняющего её поиск, то можно
произвести поиск с помощью функции `find_library`. Например,
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Поиск библиотеки с помощью функции find_library
find_library(MATHGL mgl PATHS /usr/lib /usr/lib/x86_64-linux-gnu)
find_library(MATHGLQT5 mgl-qt5 PATHS /usr/lib /usr/lib/x86_64-linux-gnu)
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
На этапе конфигурирования проекта можно создать файл, в который будут
записаны параметры, полученные на данной стадии. В библиотеке CMLib
присутствует функция `cmlib_config_hpp_generate()`, создающая файл
`${CMAKE_BUILD_DIR}/include/config.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
[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
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/CMakeLists.txt` должна быть строка, включающая поиск файла
`CMakeLists.txt` в подкаталоге `src/lib`:
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_subdirectory(src/libcmex)
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
В каталоге `cmex/src/libcmex` нужно создать файл `cmex.hpp`:
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#ifndef LIBCMEX_CMEX_HPP_
#define LIBCMEX_CMEX_HPP_
#include <stdint.h>
int32_t cmex_init(int32_t i);
#endif // LIBCMEX_CMEX_HPP_
2019-06-01 21:08:41 +00:00
----
2019-04-20 08:38:43 +00:00
файл `cmex.cpp`:
2019-06-01 21:08:41 +00:00
[source,cpp]
----
2019-04-20 08:38:43 +00:00
#include "cmex.hpp"
int32_t cmex_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
и файл `CMakeLists.txt`:
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Название основной цели и имя библиотеки в текущем каталоге
set(current_target cmex)
# Список файлов исходных текстов
set(current_target_sources
cmex.cpp
)
# Список заголовочных файлов (используется для установки)
set(current_target_headers
cmex.hpp
)
add_common_library(TARGET ${current_target} SOURCES ${current_target_sources})
common_target_properties(${current_target})
# Цель, используемая только для установки заголовочных файлов, без компиляции проекта
add_custom_target(${current_target}-install-headers
COMMAND "${CMAKE_COMMAND}"
-DCMAKE_INSTALL_COMPONENT=headers -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
)
# Правила для установки
install(TARGETS ${current_target}_static ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
if(BUILD_SHARED_LIBS)
install(TARGETS ${current_target}_shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
install(FILES ${CMAKE_BINARY_DIR}/include/config.hpp ${current_target_headers}
COMPONENT headers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${current_target})
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
2019-06-01 21:08:41 +00:00
В файле `cmex/CMakeLists.txt` должна быть строка, включающая поиск файла
`CMakeLists.txt` в подкаталоге `src/cmex`:
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_subdirectory(src/cmex)
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"
#include "config.hpp"
#include <iostream>
#include "cmex.hpp"
int main(int argc, char **argv) {
2019-06-01 21:08:41 +00:00
std::cout << CMEX_COMPILER_VERSION_MAJOR << std::endl; // Значение из compiler_features.hpp
std::cout << BUILD_TYPE << std::endl; // Значение из config.hpp
std::cout << CMEX_VERSION_STR << std::endl; // Значение из config.hpp
std::cout << cmex_init(4) << std::endl; // Функция из внутренней библиотеки
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
и файл `CMakeLists.txt`:
2019-06-01 21:08:41 +00:00
[source,cmake]
----
2019-04-20 08:38:43 +00:00
# Название основной цели в текущем каталоге
set(current_target cmex_app)
# Список файлов исходных текстов
set(current_target_sources
main.cpp
)
# Цель для создания исполняемого файла
add_executable(${current_target} ${current_target_sources})
common_target_properties(${current_target})
# Зависимость от библиотеки из текущего проекта
add_dependencies(${current_target} cmex)
# Добавление внутреннего каталога src/libcmex к списку путей для поиска заголовочных файлов
target_include_directories(${current_target} PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/libcmex>)
# Имя выходного файла для цели (параметр OUTPUT_NAME)
set_target_properties(${current_target}
PROPERTIES
OUTPUT_NAME cmex
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}
)
# Путь поиска библиотек внутри проекта
link_directories(${CMAKE_INSTALL_LIBDIR})
# Сначала внутренние статические библиотеки
target_link_libraries(${current_target} cmex_static)
# Правила для установки
install(TARGETS ${current_target} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
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
В каталоге `cmex/thirdparty` нужно создать каталог `cmext` с проектом,
состоящим из файлов `cmext.hpp`:
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
`cmext.cpp`:
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
и `CMakeLists.txt`:
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-02 16:31:29 +00:00
Вызовы этих функций нужно сделать до функций `add_subdirectories`,
2019-06-02 23:26:28 +00:00
чтобы в подключённых подкаталогах можно было использовать цель `cmext`
2019-06-02 16:31:29 +00:00
для определения зависимостей.
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` из библиотеки, предоставляемой внешним
проектом. Например:
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"
#include "config.hpp"
#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;
// Значение из config.hpp
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
// Значение из config.hpp
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-06-01 21:08:41 +00:00
Для поиска необходимых компонентов Qt5 нужно в файл
`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
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"
#include "config.hpp"
#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;
// Значение из config.hpp
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
// Значение из config.hpp
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"
#include "config.hpp"
#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;
// Значение из config.hpp
qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl;
// Значение из config.hpp
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
main.cpp
my_main_window.cpp
)
set(current_target_uis
my_main_window.ui
)
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
2019-06-01 21:08:41 +00:00
== Удаление установленных файлов
2019-04-20 08:38:43 +00:00
В библиотеку CMLib добавлена цель `uninstall`, позволяющая удалить
файлы, перечисленные в файле `${CMAKE_BUILD_DIR}/install_manifest.txt`.
2019-06-01 21:08:41 +00:00
== Архивирование проекта
2019-04-20 08:38:43 +00:00
2019-06-02 23:26:28 +00:00
Стандартный модуль `CPack` осуществляет архивирование проекта. В файле
2019-06-01 21:08:41 +00:00
`cproj/cmake/etc/cpack_ignore.txt` определён список типовых масок файлов
для исключения из архива:
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
....
2019-04-20 08:38:43 +00:00
.git$
files/var
CMakeLists.txt.user
~$
\\\\..*\\\\.tmp$
2019-06-01 21:08:41 +00:00
\\\\..*\\\\.bak$
2019-04-20 08:38:43 +00:00
\\\\..*\\\\.swp$
2019-06-01 21:08:41 +00:00
\\\\..*\\\\.o$
....
2019-04-20 08:38:43 +00:00
2019-06-01 21:08:41 +00:00
По умолчанию цель для упаковки проекта называется `package_source`. В
библиотеке CMLib определены значения основных параметров, а также
2019-04-20 08:38:43 +00:00
дополнительная цель `dist`.