Текст
This commit is contained in:
		
							
								
								
									
										671
									
								
								wiki/Prog/CMake/CMake управление проектом.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										671
									
								
								wiki/Prog/CMake/CMake управление проектом.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,671 @@
 | 
			
		||||
---
 | 
			
		||||
title: "CMake: управление проектом"
 | 
			
		||||
category: Программирование
 | 
			
		||||
tags: программирование, cmake
 | 
			
		||||
summary: ""
 | 
			
		||||
CSS: table-100.css
 | 
			
		||||
documentclass: extarticle
 | 
			
		||||
monofont: Pragmata Pro
 | 
			
		||||
monofontoptions:
 | 
			
		||||
- Scale=0.7
 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[TOC]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Полезные ссылки
 | 
			
		||||
 | 
			
		||||
* [Каталог ссылок](https://github.com/onqtam/awesome-cmake)
 | 
			
		||||
* [CGold: The Hitchhiker’s Guide to the CMake](https://cgold.readthedocs.io/en/latest/index.html)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Структура каталогов проекта
 | 
			
		||||
 | 
			
		||||
Файлы проекта и результаты компиляции размещаются в каталогах:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
└── cmex
 | 
			
		||||
    ├── _build
 | 
			
		||||
    │   ├── Debug
 | 
			
		||||
    │   └── Release
 | 
			
		||||
    ├── .git
 | 
			
		||||
    ├── cmake
 | 
			
		||||
    │   ├── cmlib
 | 
			
		||||
    │   ├── etc
 | 
			
		||||
    │   ├── find
 | 
			
		||||
    │   └── generators
 | 
			
		||||
    ├── doc
 | 
			
		||||
    ├── files
 | 
			
		||||
    │   ├── etc
 | 
			
		||||
    │   ├── share
 | 
			
		||||
    │   └── var
 | 
			
		||||
    ├── l10n
 | 
			
		||||
    ├── src
 | 
			
		||||
    │   ├── app
 | 
			
		||||
    │   └── lib
 | 
			
		||||
    ├── thirdparty
 | 
			
		||||
    └── tools
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Назначение каталогов приведено в таблице.
 | 
			
		||||
 | 
			
		||||
Каталог                  | Назначение
 | 
			
		||||
-------------------------|----------------------------------------------
 | 
			
		||||
`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`             | Дополнительные утилиты
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Каталог `_build` создаётся, чтобы избежать попадания получаемых во время
 | 
			
		||||
сборки файлов в иерархию основного проекта.
 | 
			
		||||
Запись результатов сборки проекта внутрь иерархии каталогов с исходными текстами
 | 
			
		||||
приводит к засорению формируемыми на этапе сборки файлами, которые затрудняют
 | 
			
		||||
разработку, поиск в оригинальных файлах и мешают ориентироваться в проекте.
 | 
			
		||||
При работе с несколькими типами сборки, например, отладка и выпуск, появляется
 | 
			
		||||
необходимость корректного полного удаления результатов предыдущего тип сборки.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Начало проекта
 | 
			
		||||
 | 
			
		||||
В каталоге `cmex` нужно создать файл `CMakeLists.txt`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Минимальная версия Cmake
 | 
			
		||||
cmake_minimum_required(VERSION 3.3)
 | 
			
		||||
cmake_policy(VERSION 3.0.2..3.7)
 | 
			
		||||
 | 
			
		||||
# Название и версия проекта и используемые языки программирования
 | 
			
		||||
project(cmex VERSION 0.2.0 LANGUAGES C CXX)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Значение версии следует формировать согласно правилам
 | 
			
		||||
[семантического версионирования](https://semver.org/lang/ru/).
 | 
			
		||||
 | 
			
		||||
В каталог `cmake/cmlib` установить субмодуль CMLib, содержащий функции для CMake:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
git submodule add ssh://git@gitlab-server/root/cmlib cmake/cmlib
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и подключить в файле `CMakeLists.txt`:
 | 
			
		||||
 | 
			
		||||
```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)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
В файле `cmake/etc/organization.txt` записать название
 | 
			
		||||
организации, которой принадлежит проект:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
ORG, Inc.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
В файле `cmake/etc/cpack_ignore.txt` перечислить шаблоны
 | 
			
		||||
для исключения из создаваемого целью `dist` архива. Например:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
cmake/lib/.git$
 | 
			
		||||
.git$
 | 
			
		||||
files/var
 | 
			
		||||
CMakeLists.txt.user
 | 
			
		||||
~$
 | 
			
		||||
\\\\..*\\\\.bak$
 | 
			
		||||
\\\\..*\\\\.tmp$
 | 
			
		||||
\\\\..*\\\\.swp$
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Чтобы проверить корректность файла `CMakeLists.txt`, нужно создать каталог
 | 
			
		||||
`_build` в каталоге `cmex`, перейти в него и выполнить команды:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
cmake ..
 | 
			
		||||
make
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Поиск системных библиотек
 | 
			
		||||
 | 
			
		||||
Системные библиотеки можно искать с помощью программы `pkgconfig`,
 | 
			
		||||
которая хранит базу данных параметров, включающую пути к заголовочным
 | 
			
		||||
файлами и перечни библиотек, необходимых для компоновки.
 | 
			
		||||
Сначала производится наличие модуля `PkgConfig`, в котором определена
 | 
			
		||||
функция `pkg_check_modules`, которая и осуществляет поиск. Например,
 | 
			
		||||
для поиска библиотек `gsl`, `fftw3` и `udev` можно написать:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Поиск библиотек с помощью pkgconfig
 | 
			
		||||
find_package(PkgConfig)
 | 
			
		||||
pkg_check_modules(GSL REQUIRED gsl)
 | 
			
		||||
pkg_check_modules(FFTW3 REQUIRED fftw3)
 | 
			
		||||
pkg_check_modules(UDEV udev)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Если системная библиотека поставляется без файла описания для `pkgconfig`,
 | 
			
		||||
то для её поиска может быть написан специальный модуль для `CMake`,
 | 
			
		||||
который вызывается функцией `find_package`. Кроме того функция `find_package`
 | 
			
		||||
может возвращать дополнительные значения, например, пути к исполняемым файлам.
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Поиск с помощью функции find_package
 | 
			
		||||
find_package(LibXml2)
 | 
			
		||||
find_package(CURL)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Если для библиотеки нет модуля, выполняющего её поиск, то можно
 | 
			
		||||
произвести поиск с помощью функции `find_library`. Например,
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Поиск библиотеки с помощью функции 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)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Автоматически генерируемый заголовочный файл
 | 
			
		||||
 | 
			
		||||
На этапе конфигурирования проекта можно создать файл, в который будут
 | 
			
		||||
записаны параметры, полученные на данной стадии. В библиотеке CMLib
 | 
			
		||||
присутствует функция `cmlib_config_hpp_generate()`, создающая файл
 | 
			
		||||
`${CMAKE_BUILD_DIR}/include/config.hpp`, в который записывается
 | 
			
		||||
информация о имени и версии проекта, дате и типе сборки. 
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Автоматически генерируемый заголовочный файл
 | 
			
		||||
cmlib_config_hpp_generate()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Базовая библиотека
 | 
			
		||||
 | 
			
		||||
В файле `cmex/CMakeLists.txt` должна быть строка, включающая
 | 
			
		||||
поиск файла `CMakeLists.txt` в подкаталоге `src/lib`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
add_subdirectory(src/libcmex)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
В каталоге `cmex/src/libcmex` нужно создать файл `cmex.hpp`:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
#ifndef LIBCMEX_CMEX_HPP_
 | 
			
		||||
#define LIBCMEX_CMEX_HPP_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
int32_t cmex_init(int32_t i);
 | 
			
		||||
 | 
			
		||||
#endif // LIBCMEX_CMEX_HPP_
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
файл `cmex.cpp`:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
#include "cmex.hpp"
 | 
			
		||||
 | 
			
		||||
int32_t cmex_init(int32_t i = 0) {
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и файл `CMakeLists.txt`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Название основной цели и имя библиотеки в текущем каталоге
 | 
			
		||||
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})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Базовое приложение
 | 
			
		||||
 | 
			
		||||
В файле `cmex/CMakeLists.txt` должна быть строка, включающая поиск файла `CMakeLists.txt`
 | 
			
		||||
в подкаталоге `src/cmex`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
add_subdirectory(src/cmex)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
В каталоге `cmex/src/cmex` нужно создать файл `main.cpp`:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#include "compiler_features.hpp"
 | 
			
		||||
#include "config.hpp"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "cmex.hpp"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и файл `CMakeLists.txt`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Название основной цели в текущем каталоге
 | 
			
		||||
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})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Подключение внешнего проекта
 | 
			
		||||
 | 
			
		||||
В каталоге `cmex/thirdparty` нужно создать каталог `cmext` с проектом,
 | 
			
		||||
состоящим из файлов `cmext.hpp`:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
#ifndef CMEXT_CMEXT_HPP_
 | 
			
		||||
#define CMEXT_CMEXT_HPP_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
int32_t cmext_init(int32_t i);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`cmext.cpp`:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
#include "cmext.hpp"
 | 
			
		||||
 | 
			
		||||
int32_t cmext_init(int32_t i = 0) {
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и `CMakeLists.txt`:
 | 
			
		||||
 | 
			
		||||
```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` и описать правила для его загрузки, настройки,
 | 
			
		||||
компиляции и установки для сопряжения с текущим проектом:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Подключение внешних проектов
 | 
			
		||||
include(ExternalProject)
 | 
			
		||||
 | 
			
		||||
ExternalProject_Add(cmext
 | 
			
		||||
  EXCLUDE_FROM_ALL  TRUE
 | 
			
		||||
  SOURCE_DIR        ${CMAKE_SOURCE_DIR}/thirdparty/libcmext
 | 
			
		||||
  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
 | 
			
		||||
  )
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Вызовы этих функций нужно сделать до функций `add_subdirectories`,
 | 
			
		||||
чтобы в подключенных подкаталогах можно было использовать цель `cmext`
 | 
			
		||||
для определения зависимостей.
 | 
			
		||||
 | 
			
		||||
В файле `cmex/src/cmex/CMakeLists.txt` нужно подключить внешний проект `cmext`:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Зависимость от библиотеки из внешнего проекта проекта
 | 
			
		||||
add_dependencies(${current_target} cmext)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Добавление каталога, в который устанавливаются заголовочные файлы от внешнего
 | 
			
		||||
# проекта cmext, к списку путей для поиска заголовочных файлов
 | 
			
		||||
target_include_directories(${current_target} PUBLIC
 | 
			
		||||
  $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include/cmext>)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Библиотека из внешнего проекта cmext
 | 
			
		||||
target_link_libraries(${current_target} ${CMAKE_BINARY_DIR}/lib/libcmext.a)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Для проверки работоспособности в файле `cmex/src/cmex/main.cpp` нужно вызвать
 | 
			
		||||
функцию `cmext_init` из библиотеки, предоставляемой внешним проектом.
 | 
			
		||||
Например:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#include "compiler_features.hpp"
 | 
			
		||||
#include "config.hpp"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cmext/cmext.hpp>
 | 
			
		||||
 | 
			
		||||
#include "cmex.hpp"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	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;                 // Функция из внутренней библиотеки
 | 
			
		||||
	std::cout << cmext_init(9) << std::endl;                // Функция из внешней библиотеки
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Qt5
 | 
			
		||||
 | 
			
		||||
Для поиска необходимых компонентов Qt5 нужно в файл `cmex/CMakeLists.txt`
 | 
			
		||||
добавить строки:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
find_package(Qt5 COMPONENTS Core Network Gui Widgets DBus Concurrent Sql REQUIRED)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Библиотека CMLib автоматически подключает вызов препроцессора `moc`
 | 
			
		||||
и компилятора ресурсов `rcc`, если цель использует модуль `Core`, и
 | 
			
		||||
вызывает компилятор файлов описания интерфейса, если цель использует
 | 
			
		||||
модуль `Widgets`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Консольное приложение
 | 
			
		||||
 | 
			
		||||
В файл `cmex/src/cmex/CMakeLists.txt` добавить строки:
 | 
			
		||||
 | 
			
		||||
```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`
 | 
			
		||||
нужно заменить на:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#include "compiler_features.hpp"
 | 
			
		||||
#include "config.hpp"
 | 
			
		||||
 | 
			
		||||
#include <QtCore>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cmext/cmext.hpp>
 | 
			
		||||
 | 
			
		||||
#include "cmex.hpp"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	QCoreApplication app(argc, argv);
 | 
			
		||||
	QTranslator translator;
 | 
			
		||||
 | 
			
		||||
	if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
 | 
			
		||||
	{
 | 
			
		||||
		app.installTranslator(&translator);
 | 
			
		||||
	}
 | 
			
		||||
	std::cout << QObject::tr("Compiler version: ").toStdString()       << CMEX_COMPILER_VERSION_MAJOR << std::endl; // Значение из compiler_features.hpp
 | 
			
		||||
	std::cout << QObject::tr("Project version: ").toStdString()        << CMEX_VERSION_STR            << std::endl; // Значение из config.hpp
 | 
			
		||||
	std::cout << QObject::tr("Build type: ").toStdString()             << BUILD_TYPE                  << std::endl; // Значение из config.hpp
 | 
			
		||||
	std::cout << QObject::tr("libcmex function call: ").toStdString()  << cmex_init(4)                << std::endl; // Функция из внутренней библиотеки
 | 
			
		||||
	std::cout << QObject::tr("libcmext function call: ").toStdString() << cmext_init(9)               << std::endl; // Функция из внешней библиотеки
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
После сборки проекта в каталоге `cmex/l10n` появится файл `cmex_app_ru_RU.ts`,
 | 
			
		||||
в котором нужно отредактировать переводы с помощью программы `linguist`. 
 | 
			
		||||
После сохранения переводов проект нужно пересобрать, файл переводов в
 | 
			
		||||
скопилированном виде будет встроен в исполняемый файл `cmex`, а доступ
 | 
			
		||||
к нему будет осуществляться с помощью кода:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
	if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
 | 
			
		||||
	{
 | 
			
		||||
		app.installTranslator(&translator);
 | 
			
		||||
	}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Графическое приложение
 | 
			
		||||
 | 
			
		||||
Для создания минимального графического приложения нужно создать
 | 
			
		||||
файл описания интерфейса `cmex/src/cmex/my_main_window.ui`:
 | 
			
		||||
 | 
			
		||||
```xml
 | 
			
		||||
<?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>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
заголовочный файл `cmex/src/cmex/my_main_window.hpp`:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#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 {
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
	public:
 | 
			
		||||
		MyMainWindow(QWidget* parent = 0);
 | 
			
		||||
		virtual ~MyMainWindow();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* CMEX_MY_MAIN_WINDOW_HPP_ */
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и файл с реализацией конструктора и деструктора `cmex/src/cmex/my_main_window.cpp`:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#include "my_main_window.hpp"
 | 
			
		||||
 | 
			
		||||
MyMainWindow::MyMainWindow(QWidget* parent) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MyMainWindow::~MyMainWindow() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Для отображения графического окна нужно заменить файл
 | 
			
		||||
`cmex/src/cmex/main.cpp` на:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
#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"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
	QApplication app(argc, argv);
 | 
			
		||||
	QTranslator translator;
 | 
			
		||||
 | 
			
		||||
	if (translator.load(QLocale(), "cmex_app", QLatin1String("_"), QLatin1String(":/qm")))
 | 
			
		||||
	{
 | 
			
		||||
		app.installTranslator(&translator);
 | 
			
		||||
	}
 | 
			
		||||
	std::cout << QObject::tr("Compiler version: ").toStdString()       << CMEX_COMPILER_VERSION_MAJOR << std::endl; // Значение из compiler_features.hpp
 | 
			
		||||
	std::cout << QObject::tr("Project version: ").toStdString()        << CMEX_VERSION_STR            << std::endl; // Значение из config.hpp
 | 
			
		||||
	std::cout << QObject::tr("Build type: ").toStdString()             << BUILD_TYPE                  << std::endl; // Значение из config.hpp
 | 
			
		||||
	std::cout << QObject::tr("libcmex function call: ").toStdString()  << cmex_init(4)                << std::endl; // Функция из внутренней библиотеки
 | 
			
		||||
	std::cout << QObject::tr("libcmext function call: ").toStdString() << cmext_init(9)               << std::endl; // Функция из внешней библиотеки
 | 
			
		||||
 | 
			
		||||
	MyMainWindow* mmw = new MyMainWindow();
 | 
			
		||||
	mmw->show();
 | 
			
		||||
	return app.exec();
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
В файле `cmex/src/cmex/CMakeLists.txt` добавить новые файлы
 | 
			
		||||
к списку файлов, используемых для компиляции:
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
set(current_target_sources
 | 
			
		||||
  main.cpp
 | 
			
		||||
  my_main_window.cpp
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
set(current_target_uis
 | 
			
		||||
  my_main_window.ui
 | 
			
		||||
  )
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```cmake
 | 
			
		||||
# Цель для создания исполняемого файла
 | 
			
		||||
add_executable(${current_target} ${current_target_sources} ${current_target_uis})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
и добавить строки для подключения графических библиотек Qt5
 | 
			
		||||
и соответствующих им заголовочных файлов:
 | 
			
		||||
 | 
			
		||||
```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`
 | 
			
		||||
и снова скомпилировать проект.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Удаление установленных файлов
 | 
			
		||||
 | 
			
		||||
В библиотеку CMLib добавлена цель `uninstall`, позволяющая удалить
 | 
			
		||||
файлы, перечисленные в файле `${CMAKE_BUILD_DIR}/install_manifest.txt`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Архивирование проекта
 | 
			
		||||
 | 
			
		||||
Стандарный модуль `CPack` осуществляет архивирование проекта. В файле
 | 
			
		||||
`cproj/cmake/etc/cpack_ignore.txt` определён список типовых масок файлов для
 | 
			
		||||
исключения из архива:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
.git$
 | 
			
		||||
files/var
 | 
			
		||||
CMakeLists.txt.user
 | 
			
		||||
~$
 | 
			
		||||
\\\\..*\\\\.bak$
 | 
			
		||||
\\\\..*\\\\.tmp$
 | 
			
		||||
\\\\..*\\\\.swp$
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
По умолчанию цель для упаковки проекта называется `package_source`.
 | 
			
		||||
В библиотеке CMLib определены значения основных параметров, а также
 | 
			
		||||
дополнительная цель `dist`.
 | 
			
		||||
@@ -1,14 +1,15 @@
 | 
			
		||||
# Git: замена адреса подмодуля
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
title: "Git: замена адреса подмодуля"
 | 
			
		||||
category: Программирование
 | 
			
		||||
tags: программирование, git
 | 
			
		||||
summary:
 | 
			
		||||
CSS: table-100.css
 | 
			
		||||
documentclass: extarticle
 | 
			
		||||
monofont: Pragmata Pro
 | 
			
		||||
monofontoptions:
 | 
			
		||||
- Scale=0.7
 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Если у подмодуля `thirdparty/example` нужно заменить адрес синхронизации
 | 
			
		||||
и имя используемой ветки, то в каталоге с файлом `.gitmodules`, в котором
 | 
			
		||||
содержится информация об этом подмодуле, нужно выполнить команды:
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,13 @@
 | 
			
		||||
# Git: распаковка объекта
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
title: "Git: распаковка объекта"
 | 
			
		||||
category: Программирование
 | 
			
		||||
tags: программирование, git
 | 
			
		||||
summary:
 | 
			
		||||
CSS: table-100.css
 | 
			
		||||
documentclass: extarticle
 | 
			
		||||
monofont: Pragmata Pro
 | 
			
		||||
monofontoptions:
 | 
			
		||||
- Scale=0.7
 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
В случае повреждения репозитория можно восстановить отдельные
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user