diff --git a/plugins/thirdparty/asciidoctor b/plugins/thirdparty/asciidoctor index b271b3e..288c5ae 160000 --- a/plugins/thirdparty/asciidoctor +++ b/plugins/thirdparty/asciidoctor @@ -1 +1 @@ -Subproject commit b271b3ed553a3e00f9fa079384e94a27c68ff550 +Subproject commit 288c5aeba001bc605d20c573c37d1fb9384262e8 diff --git a/themes/bootstrap4 b/themes/bootstrap4 index c651ba0..ce6b186 160000 --- a/themes/bootstrap4 +++ b/themes/bootstrap4 @@ -1 +1 @@ -Subproject commit c651ba0ef064734b6457684c780f8c863f0956bf +Subproject commit ce6b18660a933855dbe996fc5b5d3d0ac1c25223 diff --git a/wiki/Prog/Development/CMake управление проектом.adoc b/wiki/Prog/Development/CMake управление проектом.adoc new file mode 100644 index 0000000..4bc4152 --- /dev/null +++ b/wiki/Prog/Development/CMake управление проектом.adoc @@ -0,0 +1,958 @@ += CMake: управление проектом +:title-separator: {sp}| +:category: Программирование +:tags: программирование, cmake, +:toc: + +== Полезные ссылки + +* https://github.com/onqtam/awesome-cmake[Каталог ссылок] +* https://cgold.readthedocs.io/en/latest/index.html[CGold: The Hitchhiker’s Guide to the CMake] + +== Структура каталогов проекта + +Файлы проекта и результаты компиляции размещаются в каталогах: + +.... +└── project + ├── _build + │ ├── debug + │ │ ├── bin + │ │ ├── etc + │ │ ├── files + │ │ │ ├── data + │ │ │ ├── lib + │ │ │ └── log + │ │ ├── include + │ │ └── lib + │ └── release + ├── .git + ├── .gitlab-ci + ├── cmake + │ ├── cmlib + │ ├── doc + │ ├── etc + │ │ └── uncrustify + │ ├── find + │ └── generators + ├── doc + ├── files + │ ├── data + │ ├── etc + │ ├── lib + │ └── log + ├── l10n + ├── src + │ ├── app + │ └── lib + ├── thirdparty + └── tools +.... + +Назначение каталогов приведено в таблице. + +[cols="2,4",options="header",] +|=== +|Каталог | Назначение +|`_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` | Дополнительные утилиты +|=== + +Каталог `_build` создаётся, чтобы избежать попадания создаваемых во время +сборки файлов в иерархию основного проекта. Запись результатов сборки +проекта внутрь иерархии каталогов с исходными текстами приводит к +засорению формируемыми на этапе сборки файлами, которые затрудняют +разработку, поиск в оригинальных файлах и мешают ориентироваться в +проекте. При работе с несколькими типами сборки, например, отладка и +выпуск, появляется необходимость корректного полного удаления +результатов предыдущего тип сборки. + + +[[base-project]] +== Базовый проект + +Проект, в котором выполнены приведённые в данном разделе действия, +можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-base[здесь] +или сделать его копию командой: + +[source,sh] +---- +git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-base +---- + +=== Инициализация подмодулей + +Для начала нужно создать каталог для проекта, перейти в него и +инициализировать репозиторий git: + +[source,sh] +---- +mkdir cmlib-example-base +cd cmlib-example-base +git init +---- + +Для подключения основных подмодулей, содержащих дополнительные функции +для работы с проектом, и фиксации произведённого изменения нужно выполнить: + +[source,sh] +---- +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 +git commit -a -m "Начало проекта" +---- + +Отправить изменения в проекте на сервер и сделать ветку `master` основной +(можно пропустить): + +[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`: + +[source,cmake] +---- +# Минимальная версия CMake +cmake_minimum_required(VERSION 3.3) + +# Предпочтительно следовать стандартам принятым в указанном диапазоне версий +cmake_policy(VERSION 3.0.2..3.7) + +# Название и версия проекта и используемые языки программирования +project(cmlib-example-base VERSION 0.2.0 LANGUAGES C CXX) +---- + +Значение версии следует формировать согласно правилам +https://semver.org/lang/ru/[семантического версионирования]. + +Для подключения функций для CMake из библиотеки CMLib, нужно добавить +в файл `CMakeLists.txt` строки: + +[source,cmake] +---- +# В каталоге 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) +---- + +[[variables-cmake]] +В каталоге `cmake/etc` требуется создать файл `Variables.cmake`, +в котором должны быть определены переменные, используемые +библиотекой CMLib для архивирования исходных текстов, автоматического +создания пакетов, генерации документации: + +[source,cmake] +---- +set(ORGANIZATION_NAME "org") +set(AUTHOR_NAME "John Doe") + +set(DOXYGEN_PROJECT_TITLE "Пример проекта (начало)") +set(DOXYGEN_GENERATE_LATEX YES) +set(DOXYGEN_GENERATE_HTML YES) + +set(CPACK_GENERATOR "TXZ;DEB") +set(CPACK_PACKAGE_CONTACT "John Doe ") +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 + "${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$") +---- + +Произведённые изменения можно зафиксировать: + +[source,sh] +---- +git add cmake/etc/Variables.cmake CMakeLists.txt +git commit -m "Подключение библиотеки CMLib" +---- + +Чтобы проверить корректность подключения CMLib, можно выполнить команду: + +[source,sh] +---- +(mkdir -p _build && cd _build && cmake .. && make && echo OK) +---- + +Если последней строкой вывода будет `OK`, то настройка завершена верно. + + +== Поиск системных библиотек + +Поиск программ, библиотек и заголовочных файлов, установленных в системе, можно +выполнять с помощью программы 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`: + +[source,cmake] +---- +# Поиск библиотек с помощью pkgconfig +find_package(PkgConfig REQUIRED) +pkg_check_modules(GSL REQUIRED gsl) +pkg_check_modules(FFTW3 REQUIRED fftw3) +pkg_check_modules(UDEV udev) +---- + +=== Поиск с помощью функции `find_package` + +Если системная библиотека поставляется без файла описания для `pkg-config` +или необходимо произвести более сложный поиск, например, включающий поиск +исполняемого файла, то может быть написан специальный модуль для `CMake`, +который вызывается функцией `find_package`. Примеры вызова функции: + +[source,cmake] +---- +# Поиск с помощью функции find_package +find_package(LibXml2) +find_package(CURL REQUIRED) +---- + + +== Автоматически генерируемый заголовочный файл + +На этапе конфигурирования проекта можно сгенерировать файл, в который +будут записаны собранные значения параметров. В библиотеке CMLib +присутствует функция `cmlib_config_hpp_generate()`, создающая файл +`${CMAKE_BINARY_DIR}/include/cmlib_private_config.hpp`, в который +записывается информация о имени и версии проекта, дате и типе сборки. + +[source,cmake] +---- +# Автоматически генерируемый заголовочный файл +cmlib_config_hpp_generate() +---- + + +== Удаление установленных файлов + +В библиотеку CMLib добавлена цель `uninstall`, позволяющая удалить файлы, +которые могут быть установлены в результате выполнения цели `install`: + +[source,sh] +---- +cd _build/debug +make install +make uninstall +---- + + +== Архивирование проекта и создание пакетов + +Стандартный модуль `CPack` предназначен для архивирования исходных +текстов проекта и создания пакетов для установки в целевую систему. +Необходимые переменные устанавливаются в файле `cmake/etc/Variables.cmake` +<>. + +Устанавливаемые файлы делятся на две группы `MAIN` и `DEV` с помощью +параметра `COMPONENT` функции `install`. В группу `MAIN` необходимо +помещать файлы для установки на целевую систему (исполняемые файлы, +файлы настроек, файлы данных, разделяемые библиотеки), а в группу `DEV` --- +для установки на систему для разработки (заголовочные файлы, статические +библиотеки). + +По умолчанию цель для упаковки исходных текстов называется `package_source`. +Бинарные пакеты создаются программой `cpack`. Пример: + +[source,sh] +---- +cd _build/debug +make +make package_source +cpack +---- + + +== Примеры библиотек и приложений + + +=== Базовая библиотека + +Проект с базовой библиотекой реализован на основе <>. +Исходные тексты содержат комментарии, объясняющие назначение используемых функций. +Проект можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-library[здесь] +или сделать его копию командой: + +[source,sh] +---- +git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-library +---- + +В файл `CMakeLists.txt`, находящийся в корневом каталоге проекта, нужно добавить: + +[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) + +# Автоматически генерируемый заголовочный файл +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`: + +[source,cmake] +---- +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT cmlib-example) + +# Список файлов исходных текстов +set(TRGT_sources ${CMAKE_CURRENT_SOURCE_DIR}/init.cpp) + +# Список заголовочных файлов (используется для установки) +set(TRGT_headers ${CMAKE_CURRENT_SOURCE_DIR}/init.hpp) + +# Функция для создания цели, результатом которой будет сборка библиотеки +add_common_library(TARGET ${TRGT} SOURCES ${TRGT_sources}) +common_target_properties(${TRGT}) + +# Добавление к пути поиска заголовочных файлов +target_include_directories(${TRGT} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) + +# Цель, используемая только для установки +# заголовочных файлов без компиляции проекта +add_custom_target(${TRGT}-install-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=DEV -P + "${CMAKE_BINARY_DIR}/cmake_install.cmake") + +# Установка статической библиотеки +install(TARGETS ${TRGT}_static COMPONENT DEV ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +# Установка динамической библиотеки +if(BUILD_SHARED_LIBS) + install(TARGETS ${TRGT}_shared COMPONENT DEV LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +# Установка заголовочных файлов +install(FILES ${TRGT_headers} COMPONENT DEV DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${TRGT}) + +# Установка файла для pkg-config +install(FILES ${CMAKE_BINARY_DIR}/${TRGT}.pc COMPONENT DEV DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +---- + + +файл `init.hpp`: + +[source,cpp] +---- +#ifndef CMLIB_EXAMPLE_HPP_ +#define CMLIB_EXAMPLE_HPP_ + +#include + +int32_t cmlib_example_init(int32_t i); + +#endif // CMLIB_EXAMPLE_HPP_ +---- + +и файл `init.cpp`: + +[source,cpp] +---- +#include "init.hpp" + +#include + +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; +} +---- + +=== Базовое приложение + +Проект с базовым приложением реализован на основе <>. +Исходные тексты содержат комментарии, объясняющие назначение используемых функций. +Проект можно посмотреть https://git.246060.ru/f1x1t/cmlib-example-app[здесь] +или сделать его копию командой: + +[source,sh] +---- +git clone --recursive https://git.246060.ru/f1x1t/cmlib-example-app +---- + +В файл `CMakeLists.txt`, находящийся в корневом каталоге проекта, нужно добавить: + +[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) + +# Автоматически генерируемый заголовочный файл +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`: + +[source,cmake] +---- +# Название основной цели и имя библиотеки в текущем каталоге +set(TRGT cmlib-example) + +# Список файлов исходных текстов +set(TRGT_sources ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) + +# Функция для создания цели, результатом которой будет сборка приложения +add_executable(${TRGT} ${TRGT_sources}) +common_target_properties(${TRGT}) + +# Добавление к пути поиска заголовочных файлов +target_include_directories(${TRGT} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) + +# Имя целевого каталога и выходного файла для цели +set_target_properties(${TRGT} + PROPERTIES + OUTPUT_NAME ${TRGT} + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR} + ) + +# Правила для установки +install(TARGETS ${TRGT} COMPONENT MAIN RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +---- + +и файл `main.cpp`: + +[source,cpp] +---- +#include "compiler_features.hpp" +#include "cmlib_private_config.hpp" + +#include +#include + +int32_t nsum(int32_t i = 0) +{ + int32_t s = 0; + for ( auto r : boost::counting_range( 1, i ) ) + { + s += r; + } + return s; +} + +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; + + auto s = nsum( argc ); + std::cout << s << std::endl; + + return ( s ); +} +---- + + +ПИШУ ЗДЕСЬ!!! + + +== Подключение внешнего проекта + +В каталоге `cmex/thirdparty` нужно создать каталог `cmext` с проектом, +состоящим из файла `cmext.hpp`: + +[source,c] +---- +#ifndef CMEXT_CMEXT_HPP_ +#define CMEXT_CMEXT_HPP_ + +#include + +int32_t cmext_init(int32_t i); + +#endif +---- + +файла `cmext.cpp`: + +[source,c] +---- +#include "cmext.hpp" + +int32_t cmext_init(int32_t i = 0) { + return i; +} +---- + +и файла `CMakeLists.txt`: + +[source,cmake] +---- +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}) +---- + +В файле `cmex/CMakeLists.txt` нужно подключить стандартный модуль +`ExternalProject` и описать правила для его загрузки, настройки, +компиляции и установки для сопряжения с текущим проектом: + +[source,cmake] +---- +# Подключение внешних проектов +include(ExternalProject) + +ExternalProject_Add(cmext + EXCLUDE_FROM_ALL TRUE + SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/cmext + INSTALL_DIR ${CMAKE_BINARY_DIR} + DOWNLOAD_COMMAND "" + BUILD_BYPRODUCTS /lib/libcmext.a + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_BUILD_TYPE=Release + ) +---- + +Вызовы этих функций нужно сделать до функций `add_subdirectories`, чтобы +в подключенных подкаталогах можно было использовать цель `cmext` для +определения зависимостей. + +В файле `cmex/src/cmex/CMakeLists.txt` нужно подключить внешний проект +`cmext`: + +[source,cmake] +---- +# Зависимость от библиотеки из внешнего проекта проекта +add_dependencies(${current_target} cmext) +---- + +[source,cmake] +---- +# Добавление каталога, в который устанавливаются заголовочные файлы от внешнего +# проекта cmext, к списку путей для поиска заголовочных файлов +target_include_directories(${current_target} PUBLIC + $) +---- + +[source,cmake] +---- +# Библиотека из внешнего проекта cmext +target_link_libraries(${current_target} ${CMAKE_BINARY_DIR}/lib/libcmext.a) +---- + +Для проверки работоспособности в файле `cmex/src/cmex/main.cpp` нужно +вызвать функцию `cmext_init` из библиотеки, предоставляемой внешним +проектом. Например, можно заменить его содержимое на: + +[source,cpp] +---- +#include "compiler_features.hpp" +#include "cmlib_config.hpp" + +#include +#include + +#include "cmex.hpp" + +QTextStream& qStdOut() +{ + static QTextStream ts(stdout); + return ts; +} + +int main(int argc, char **argv) { + // Значение из compiler_features.hpp + qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl; + // Значение из cmlib_config.hpp + qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl; + // Значение из cmlib_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; + + return 0; +} +---- + +== Qt5 + +Для поиска необходимых компонентов Qt5 нужно в файл `cmex/CMakeLists.txt` +перед вызовом функции `cmlib_config_hpp_generate()` нужно добавить строку: + +[source,cmake] +---- +find_package(Qt5 COMPONENTS Core Network Gui Widgets DBus Concurrent Sql REQUIRED) +---- + +Библиотека CMLib автоматически подключает вызов препроцессора `moc` и +компилятора ресурсов `rcc`, если цель использует модуль `Core`, и +вызывает компилятор файлов описания интерфейса, если цель использует +модуль `Widgets`. + +== Консольное приложение + +В файл `cmex/src/cmex/CMakeLists.txt` добавить строки: + +[source,cmake] +---- +# 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) +---- + +Для проверки работоспособности подключения Qt5 файл +`cmex/src/cmex/main.cpp` нужно заменить на: + +[source,cpp] +---- +#include "compiler_features.hpp" +#include "cmlib_config.hpp" + +#include +#include +#include + +#include "cmex.hpp" + +QTextStream& qStdOut() +{ + static QTextStream ts(stdout); + return ts; +} + +int main(int argc, char **argv) { + QCoreApplication app(argc, argv); + QTranslator translator; + + if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm"))) + { + app.installTranslator(&translator); + } + // Значение из compiler_features.hpp + qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl; + // Значение из cmlib_config.hpp + qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl; + // Значение из cmlib_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; + + return 0; +} +---- + +После сборки проекта в каталоге `cmex/l10n` появится файл +`cmex_app_ru_RU.ts`, в котором нужно отредактировать переводы с помощью +программы `linguist`. После сохранения переводов проект нужно +пересобрать, файл переводов в скомпилированном виде будет встроен в +исполняемый файл `cmex`, а доступ к нему будет осуществляться с помощью +кода: + +[source,cpp] +---- + if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm"))) + { + app.installTranslator(&translator); + } +---- + +== Графическое приложение + +Для создания минимального графического приложения нужно создать файл +описания интерфейса `cmex/src/cmex/my_main_window.ui`: + +[source,xml] +---- + + + MyMainWindow + + + + 0 + 0 + 678 + 415 + + + + Main Window + + + + + + +---- + +заголовочный файл `cmex/src/cmex/my_main_window.hpp`: + +[source,cpp] +---- +#ifndef CMEX_MY_MAIN_WINDOW_HPP_ +#define CMEX_MY_MAIN_WINDOW_HPP_ + +#include +#include "ui_my_main_window.h" + +class MyMainWindow : public QWidget, private Ui::MyMainWindow { + Q_OBJECT + public: + MyMainWindow(QWidget* parent = 0); + virtual ~MyMainWindow(); +}; + +#endif /* CMEX_MY_MAIN_WINDOW_HPP_ */ +---- + +и файл с реализацией конструктора и деструктора +`cmex/src/cmex/my_main_window.cpp`: + +[source,cpp] +---- +#include "my_main_window.hpp" + +MyMainWindow::MyMainWindow(QWidget* parent) { + +} + +MyMainWindow::~MyMainWindow() { + +} +---- + +Для отображения графического окна нужно заменить файл +`cmex/src/cmex/main.cpp` на: + +[source,cpp] +---- +#include "compiler_features.hpp" +#include "cmlib_config.hpp" + +#include +#include +#include +#include + +#include "cmex.hpp" +#include "my_main_window.hpp" + +QTextStream& qStdOut() +{ + static QTextStream ts(stdout); + return ts; +} + +int main(int argc, char **argv) { + QApplication app(argc, argv); + QTranslator translator; + + if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm"))) + { + app.installTranslator(&translator); + } + + // Значение из compiler_features.hpp + qStdOut() << QObject::tr("Compiler version: ") << CMEX_COMPILER_VERSION_MAJOR << endl; + // Значение из cmlib_config.hpp + qStdOut() << QObject::tr("Project version: ") << CMEX_VERSION_STR << endl; + // Значение из cmlib_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; + + MyMainWindow* mmw = new MyMainWindow(); + mmw->show(); + return app.exec(); +} +---- + +В файле `cmex/src/cmex/CMakeLists.txt` добавить новые файлы к списку +файлов, используемых для компиляции: + +[source,cmake] +---- +set(current_target_sources + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/my_main_window.cpp + ) + +set(current_target_uis + ${CMAKE_CURRENT_SOURCE_DIR}/my_main_window.ui + ) +---- + +[source,cmake] +---- +# Цель для создания исполняемого файла +add_executable(${current_target} ${current_target_sources} ${current_target_uis}) +---- + +и добавить строки для подключения графических библиотек Qt5 и +соответствующих им заголовочных файлов: + +[source,cmake] +---- +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) +---- + +Во время сборки проекта в файл переводов `cmex/l10n/cmex_app_ru_RU.ts` +будут добавлены новые строки, их нужно перевести с помощью `linguist` и +снова скомпилировать проект. +