Сборочная система¶
Обзор¶
Ü обладает своей собственной сборочной системой под названием Bürokratie. Она упрощает сборку сложных программ, написанных на Ü, в сравнении с прямым использованием компилятора Ü. Рекомендуется использовать её для сборки проектов, написанных на Ü.
Собираемый проект состоит из одного или нескольких пакетов. Существует корневой пакет, который может зависеть от других пакетов.
Каждый пакет должен содержать файл build.u в его корневой директории. Этот файл - просто исходный файл Ü, с содержимым вроде такого:
import "/build_system.uh"
fn GetPackageInfo( BK::BuildSystemInterface &mut build_system_interface ) : BK::PackageInfo
{
ust::ignore_unused( build_system_interface );
var BK::BuildTarget mut target{ .target_type = BK::BuildTargetType::Executable };
target.source_files.push_back( "main.u" );
target.name= "hello_world";
return BK::PackageInfo{ .build_targets= ust::make_array( move(target) ) };
}
Этот файл должен определять функцию GetPackageInfo
как показано выше, которая возвращает структуру, описывающую данный пакет.
Сборочная система компилирует его в разделяемую библиотеку (в системозависимом формате), загружает её и вызывает эту функцию для получения информации о пакете.
Пакет состоит из сборочных целей, особых шагов сборки, зависимостей от других пакетов. Зависимые пакеты загружаются точно так же, как и корневой - со сборкой их build.u файла и загрузкой разделяемой библиотеки.
Сборочная система ответственна за непосредственно сборку проекта. Она запускает компилятор Ü для исходников, компонует исполняемые файлы, запускает особые шаги сборки и т. д. Она гарантирует, что порядок выполнения всех этих действий корректен и пытается использовать несколько ядер процессора, чтобы выполнить сборку побыстрее. Также она производит пересборку только того что нужно - пересобираются только те файлы, что изменились, а также зависимые от них файлы.
Язык Ü выбран для сборочных скриптов Ü для того, чтобы облегчить написание таких скриптов.
Не нужно учить ещё один язык для файлов описания проектов (вроде make или cmake) - достаточно лишь знать Ü.
Также использование Ü облегчает написание сложного кода, необходимого для сборки некоторых проектов, что могло бы быть не так просто с использованием других языков.
Наиглавнейший недостаток такого подхода - это отсутствие изоляции сборочных скриптов.
Можно привести к аварийному завершению сборочной системы используя halt
в сборочном скрипте, или же через некорректное использование небезопасного кода.
Функционал¶
Сборочные цели¶
Пакет может обладать нулём и более сборочных целей. Сборочная цель это основная логическая единица проекта.
Существуют следующие типы сборочных целей:
Исполняемый файл
Библиотека - сборочная цель, от которой могут зависеть другие сборочные цели и которые могут использовать код из неё
Разделяемая библиотека - в системозависимом формате, вроде dll или so
Объектный файл - в системозависимом формате
Сборочная цель должна обладать непустым именем, уникальным в рамках пакета. Имена результирующих файлов основаны на этом имени.
Каждая сборочная цель имеет список исходных файлов, список директорий публичных заголовочных файлов, список публичных и приватных зависимостей, указание внешних библиотек для компоновки и т. д.
Зависимости¶
Сборочная цель может зависеть от других сборочных целей, как своего пакета, так и других пакетов. Возможны зависимости от библиотек и разделяемых библиотек, но не от исполняемых и объектных файлов.
Зависимости сборочной цели перечисляются в списках public_dependencies
и private_dependencies
структуры сборочной цели.
Каждый элемент этого списка представляет собой комбинацию имени сборочной цели и имени пакета, которое по умолчанию равно текущему пакету.
Для зависимостей от сборочных целей других пакетов должно быть указано имя пакета - как под-пакет текущего пакета, глобальный версионируемый пакет или под-пакет глобального версионируемого пакета.
Публичные зависимости являются также зависимостями сборочных целей, которые зависят от данной сборочной цели. Обычно зависимость должна быть публичной, если объявления из её заголовочных файлов используются в публичных заголовочных файлах текущей сборочной цели. Но могут быть и другие причины для зависимости быть публичной. Если зависимость используется только внутренне (например если её заголовочные файлы импортируются только в исходных файлах), она должна быть приватной.
Сборочная цель может обладать нулём и боле публичных директорий импорта - директорий, где расположены публичные заголовочные файлы. Файлы из этих директорий могут быть импортированы сборочными целями, зависящими от данной. При импорте файла из данной директории имя сборочной цели может быть использовано в качестве префикса, как в примере ниже:
import "/SomeLibrary/some_library_header.uh"
SomeLibrary - это имя сборочной цели. Такая директива импорта может быть использована как в сборочной цели SomeLibrary, так и в сборочных целях, которые от неё зависят.
Сборочная цель не может зависеть от нескольких сборочных целей с одним и тем же именем, пусть даже и из разных пакетов. Это ограничение существует, т. к. иначе могли бы быть конфликты при импорте файлов этих зависимостей.
Важно отметить, что для зависимостей от сборочных целей глобальных версионируемых пакетов не гарантируется, что будет использована в точности та версия, которая указана. Может быть использована более новая версия, если это необходимо для устранения общих зависимостей от сборочных целей различных версий.
Сторонние библиотеки¶
Возможно указать для сборочной цели зависимость от внешних библиотек - как разделяемых, так и статических.
Они указываются через список external_libraries
структуры сборочной цели.
Возможны как абсолютные, так и относительные пути, но последние могут работать только для системных библиотек (например kernel32).
Зависимости от внешних библиотек наследуются - если сборочная цель LibA имеет внешнюю зависимость от SomeLib, все сборочные цели, зависящие от LibA, будут скомпонованы с SomeLib.
Особые шаги сборки¶
Пакет может содержать особые шаги сборки - дополнительные действия, которые выполняются для сборки этого пакета. Обычно они используются для генерации кода, но могут быть использованы для других целей.
Каждый особый сборочных шаг обладает списком входных и выходных файлов. Рекомендуется располагать выходные файлы в сборочной директории текущего проекта. Данные списки используется для корректного определения момента запуска данного сборочного шага - чтобы удостовериться, что особый шаг сборки, генерирующий некий файл, запускается до других шагов сборки, которые этот файл используют.
Существуют несколько типов команд, которые возможны для особого сборочного шага:
Запуск внешнего исполняемого файла
Запуск исполняемого файла, который был ранее собран для хост-системы
Копирование файла
Создание файла с указанным содержимым
Особый шаг сборки может обладать комментарием, который отображается в процессе сборки. Рекомендуется указывать его.
Генерируемые исходные файлы¶
Особые сборочные шаги могут генерировать исходные или заголовочные файлы. Такие файлы должны быть размещены в директории генерируемых исходников или в директории генерируемых публичных заголовочных файлов сборочной цели.
Каждый генерируемый исходный файл должен быть перечислен в списке generated_source_files
- с именем, указанным относительно директории генерируемых исходников сборочной цели.
Каждый генерируемый приватный заголовочный файл должен быть перечислен в списке generated_private_header_files
- с именем, указанным относительно директории генерируемых исходников сборочной цели.
Каждый генерируемый публичный заголовочный файл должен быть перечислен в списке generated_public_header_files
- с именем, указанным относительно директории генерируемых публичных заголовочных файлов сборочной цели.
Сгенерированные файлы могут импортировать другие файлы, используя абсолютный путь с префиксом - именем сборочной цели. Сгенерированные файлы могут быть импортированы файлами данной сборочной цели и сборочных целей, которые от неё зависят, используя абсолютный путь с префиксом - именем сборочной цели.
Указание списков генерируемых исходных/заголовочных файлов необходимо, чтобы удостовериться, что особые сборочные шаги, которые генерируют эти файлы, запускаются до компиляции сборочных целей этих файлов.
Зависимости от пакетов¶
Пакет может зависеть от других пакетов. Эти пакеты могут быть под-пакетами текущего пакета (расположенными в поддиректории) или же глобальными версионируемыми пакетами (или их под-пакетами).
Если сборочные цели пакета зависят от сборочных целей другого пакета, эти пакеты должны быть перечислены в списке зависимых пакетов.
Существуют следующие варианты зависимости от пакета:
Зависимость целевой системы - умолчательный режим, который означает, что пакет должен быть собран для целевой системы и его сборочные цели могут быть использованы в качестве зависимостей сборочных целей текущего пакета
Зависимость хост-системы - пакет должен быть собран для хост-системы. Его сборочные цели-исполняемые файлы могут быть использованы в качестве команд для особых сборочных шагов.
Обе - комбинированная зависимость для целевой и хост систем
Интерфейс командной строки¶
Исполняемый файл сборочной системы поддерживает следующие команды:
build - осуществить сборку
init - создать шаблон проекта в текущей директории или директории, указанной через опцию
--project-directory
help - напечатать сообщение с помощью и выйти
Существуют также опции, которые влияют на некоторые команды.
Опция --project-directory
указывает путь к директории корневого пакета.
Значение по умолчанию - это текущая директория.
Опция --build-directory
служит для указания сборочной директории.
Значение по умолчанию это поддиректория build директории корневого пакета.
Опция --build-configuration
указывает сборочную конфигурацию.
Доступны конфигурации release
и debug
.
Опция --configuration-options
позволяет указать путь к JSON файлу с дополнительными опциями конфигурации.
Данный файл должен быть JSON-объектом со строковыми значениями.
Эти значения доступны для чтения из скриптов сборки пакетов.
Опция --target-triple
позволяет указать целевую архитектуру/систему в формате architecture-vendor-operating_system или architecture-vendor-operating_system-environment.
Например, x86_64-unknown-linux-gnu или i686-pc-windows-msvc.
Сборочная система произведёт сборку для указанных архитектуры/системы.
Опция --sysroot
позволяет указать путь к корневой директории тулченйна для целевой системы.
Это может быть необходимо для кросс-компиляции.
Опция --host-sysroot
может быть использована для указания пути к корневой директории тулченйна для сборки для хост-системы.
Опция -q
делает сборочную систему тихой - она выводит только сообщения об ошибках.
Опция -v
имеет противоположное значение - сборочная система выводит множество сообщений.
Опция -v
имеет больший приоритет, нежели -q
.
Опция -j
служит для указания количества потоков, использующихся при сборке.
Значение по умолчанию равно 0, что означает, что будут использоваться все доступные ядра процессора.
Опция --packages-repository-directory
служит для указания пути к директории с глобальными пакетами.
Данная директория должна содержать поддиректории (для каждого пакета) и одну или более директорию версии внутри директории пакета, в формате major.minor.patch.tweak.
Данная директория используется для поиска глобальных версионируемых пакетов.
Опции --compiler-executable
, --ustlib-path
, --build-system-imports-path
используются для переопределения путей к компонентам, использующимся сборочной системой - исполняемому файлу компилятора Ü, стандартной библиотеке, директории с заголовочными файлами системы сборки.
Не рекомендуется переопределять эти пути, разве только это действительно нужно.