= Программный проект и иерархия каталогов
:title-separator: {sp}|
:category: Программирование
:tags: Linux, программирование, cmake

Для операционных систем типа Linux принят стандарт
https://ru.wikipedia.org/wiki/FHS[FHS] («стандарт иерархии файловой
системы»), унифицирующий местонахождение файлов и каталогов с общим
назначением в файловой системе. Полная текущая версия стандарта
находится http://refspecs.linuxfoundation.org/fhs.shtml[здесь].

== Типы расположения проекта

В соответствии с данным стандартом, а также принятыми в ведущих
дистрибутивах правилами размещения исполняемых файлов в каталогах
пользователей, можно выделить следующие типы расположения:

* системная иерархия в каталоге `/usr` используется для установки
бинарных пакетов для данного дистрибутива;

* системная иерархия в каталоге `/usr/local` используется для установки
программного обеспечения системным администратором без использования
пакетов (не рекомендуется для использования из-за проблем поддержки
в актуальном состоянии);

* системная иерархия в каталоге `/opt` используется для установки
стороннего программного обеспечения. В рамках данной иерархии
предполагается, что каждый программный продукт располагается в
собственном каталоге. При таком типе сборки обычно используются
дополнительные методы (статическая компоновка, включение в состав
пакета своего набора динамических библиотек) для обеспечения работы
пакета в операционных системам с отличающимся составом библиотек
и другим циклом обновления;

* системная иерархия в домашнем каталоге пользователя не имеет
определённого стандарта, обычно производители дистрибутивов
предлагают использовать для исполняемых файлов каталоги
`$HOME/bin` или `$HOME/.local/bin`.

Система автоматизации сборки программного обеспечения `CMake` позволяет
организовать окружение подобное перечисленным выше. На этапе сборки
проекта можно создать структуру каталогов, которая будет отвечать
требованиям по логическому разделению файлов на исполняемые,
заголовочные, библиотеки, файлы настроек и т.д.

== Автоматическая адаптация к текущему окружению

Для обеспечения единообразной работы вне зависимости от варианта
иерархии каталогов, в которой находится исполняемый файл, можно
выполнять автоматическую настройку на работу в текущем окружении.

В библиотеке https://git.246060.ru/f1x1t/myxlib[myxlib] реализован
класс, который анализирует расположение и окружение исполняемого
файла и предоставляет методы для получения имён каталогов,
соответствующих текущему окружению. Названия методов и описания
возвращаемых значений приведены в таблице.

[cols="2m,4",options="header",]
|===
| Метод                      | Описание
| homeDirectory()            | Полный путь к домашнему каталогу текущего пользователя
| tempDirectory()            | Полный путь к каталогу с временными файлами
| userConfigDirectory()      | Полный путь к пользовательскому каталогу с файлами настройки
| userConstDataDirectory()   | Полный путь к пользовательскому каталогу с неизменяемыми файлами
| userVarDataDirectory()     | Полный путь к пользовательскому каталогу с изменяемыми файлами
| userLogDirectory()         | Полный путь к пользовательскому каталогу с журналами работы
| binaryDirectory()          | Полный путь к каталогу с исполняемым файлом
| systemConfigDirectory()    | Полный путь к системному каталогу с файлами настройки
| configFilePath()           | Полный путь к файлу настройки
| systemVarDataDirectory()   | Полный путь к системному каталогу с изменяемыми файлами
| systemConstDataDirectory() | Полный путь к системному каталогу с неизменяемыми файлами
| systemLogDirectory()       | Полный путь к системному каталогу с журналами работы
| projectName()              | Имя подкаталога для проекта
| executableFileName()       | Имя исполняемого файла
| executableFilePath()       | Полный путь к исполняемому файлу
|===

Пример использования:

[source,cpp]
----
#include <myx/filesystem/paths.hpp>
namespace MF = myx::filesystem;

MF::Paths& paths = MF::Paths::instance();
paths.init( QStringLiteral( "project_name" ), QStringLiteral( "conf" ) );
qDebug() << paths.systemConstDataDirectory().path();
----

=== Правила выбора типа окружения

Класс `myx::filesystem::Paths` реализован в виде синглтона,
чтобы повторно не выполнять проверку окружения в разных частях программы.
Сначала определяются имена пользовательского и временного каталогов с
помощью вызовов функций https://doc.qt.io/qt-5/qdir.html#homePath[`QDir::homePath`]
и https://doc.qt.io/qt-5/qdir.html#tempPath[`QDir::tempPath`], затем
имена пользовательских каталогов для настроек, постоянных и изменяемых
данных и журналов. Эти значения не зависят от расположения исполняемого,
а определяются согласно значениям переменных окружения, либо значениям
принятыми в стандартах. Пример имён каталогов для пользователя `user`
и проекта `project` приведён в таблице.


[cols="3,3m,5m",options="header",]
|===
| Назначение каталога | Метод                    | Значение
| Домашний каталог    | homeDirectory()          | /home/user
| Временные файлы     | tempDirectory()          | /tmp
| Файлы настройки     | userConfigDirectory()    | /home/user/.config/project
| Неизменяемые файлы  | userConstDataDirectory() | /home/user/.local/share/project/data
| Изменяемые файлы    | userVarDataDirectory()   | /home/user/.local/share/project/lib
| Журналы работы      | userLogDirectory()       | /home/user/.local/share/project/log
|===


Для определения типа текущего окружения используется полный путь
к исполняемому файлу, если он находится в каталоге `bin`, то выполняются
проверки работы в одной из возможных вариантов иерархий, иначе
делается заключение о том, что файлы всех типов находятся в одном
каталоге с исполняемым.

