Модульность

Модель сборки

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

Технически возможна компоновка с объектными файлами, полученными компиляцией исходных файлов других языков, например C или C++.

Включение

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

Для импортирования следует в начале файла исходного кода, до всех объявлений, указать дерективу import и путь к импортируемому файлу в "" скобках. Путь может быть абсолютным - начинающимся с /, или относительным в противном случае. Если путь абсолютный - файл для импорта будет искаться начиная с одной из корневых директорий, которыми можно управлять через соответствующие опции компилятора. Если путь относительный - файл для импорта будет искаться относительно текущего файла.

import "a.u" // Импортируем файл, находящийся рядом с текущим
import "../b.u" // Импортируем файл, находящийся на уровень выше от текущего в файловой системе
import "cc/c.u" // Импортируем файл, находящийся в директории "cc", находящейся в одной директории с текущим файлом
import "/d.u" // Импортируем файл, находящийся в корневой директории компилятора

Механизм работы включения

Включаемый файл компилируется как обычно, возможно с включением других файлов. Объявления из каждого включённого файла объединяются и становятся видимыми в текущем файле. Порядок включений не влияет на компиляцию включаемых файлов, как и не влияет на файл, в котором происходит включение. При любом порядке набор видимых объявлений будет одним и тем же.

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

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

a.u
 fn GetX() : i32 { return 42; }
b.u
 import "a.u"
c.u
 import "a.u"

При компоновке программы из файлов "b.u" и "c.u" в итоговую программу попадёт только одна копия функции GetX().

Правило единственности определения

Каждая сущность итоговой программы на Ü должна быть объявлена только в одном месте. Не допускается, чтобы существовало более одной сущности с одним и тем же именем (и сигнатурой, для функций). При импорте компилятор проверяет, что сущности из разных файлов не конфликтуют друг с другом - имена не переопределяются, не существует одноимённых функций с одинаковой сигнатурой и т. д.

Но не во всех случаях компилятор может проверить корректность правила единственности определения. Программист может объявить локально в двух исходных файлах сущности с одним и тем же именем, скомпилировать эти файлы раздельно и попытаться скомпоновать их. Компилятор такой ошибки обнаружить не сможет, также не гарантируется, что компоновщик её найдёт. Поэтому ответственность за то, чтобы правило единственности определения не нарушалось, лежит на программисте.