From 014bf6fcdf918b5f397cc34a970bea186ecc96d7 Mon Sep 17 00:00:00 2001 From: Andrey Astafyev Date: Sat, 20 Apr 2019 11:38:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A2=D0=B5=D0=BA=D1=81=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wiki/Prog/CMake/CMake управление проектом.md | 671 +++++++++++++++++++ wiki/Prog/Git/Git замена адреса подмодуля.md | 7 +- wiki/Prog/Git/Git распаковка объекта.md | 6 +- 3 files changed, 679 insertions(+), 5 deletions(-) create mode 100644 wiki/Prog/CMake/CMake управление проектом.md diff --git a/wiki/Prog/CMake/CMake управление проектом.md b/wiki/Prog/CMake/CMake управление проектом.md new file mode 100644 index 0000000..4aa2833 --- /dev/null +++ b/wiki/Prog/CMake/CMake управление проектом.md @@ -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 + +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 + +#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 + $) + +# Имя выходного файла для цели (параметр 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 + +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 /lib/libcmext.a + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -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 + $) +``` + +```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 +#include + +#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 +#include +#include + +#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 + + + MyMainWindow + + + + 0 + 0 + 678 + 415 + + + + Main Window + + + + + + +``` + +заголовочный файл `cmex/src/cmex/my_main_window.hpp`: + +```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`: + +```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 +#include +#include +#include + +#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`. diff --git a/wiki/Prog/Git/Git замена адреса подмодуля.md b/wiki/Prog/Git/Git замена адреса подмодуля.md index 7b86704..8dc9e35 100644 --- a/wiki/Prog/Git/Git замена адреса подмодуля.md +++ b/wiki/Prog/Git/Git замена адреса подмодуля.md @@ -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`, в котором содержится информация об этом подмодуле, нужно выполнить команды: diff --git a/wiki/Prog/Git/Git распаковка объекта.md b/wiki/Prog/Git/Git распаковка объекта.md index 19a86a5..a7198ad 100644 --- a/wiki/Prog/Git/Git распаковка объекта.md +++ b/wiki/Prog/Git/Git распаковка объекта.md @@ -1,11 +1,13 @@ -# Git: распаковка объекта - --- title: "Git: распаковка объекта" category: Программирование tags: программирование, git summary: CSS: table-100.css +documentclass: extarticle +monofont: Pragmata Pro +monofontoptions: +- Scale=0.7 ... В случае повреждения репозитория можно восстановить отдельные