# Файлы ya.make

В предыдущем разделе мы познакомились с утилитой `ya`, используемой для сборки и тестирования исходного кода. Описание того, что будет делать команда `ya make` при вызове в каждом конкретном каталоге единого репозитория, хранится в файлах **ya.make**.

## Структура { #structure }

Каждый каталог, в корне которого лежит файл **ya.make**, называется **модулем**. Типичный файл **ya.make** имеет следующую структуру:

```yamake
OWNER(username) # Владелец модуля

PROGRAM() # Начало описания модуля

SRCS( # Список файлов с исходными кодами
    main.cpp
)

END() # Конец описания модуля
```

Каждое из выражений в этом файле, содержащее скобки, называется **макросом**.

{% note info %}

Описания всех доступных макросов можно посмотреть [здесь](https://a.yandex-team.ru/arc/trunk/arcadia/build/docs/readme.md).

{% endnote %}

Например, макрос **OWNER()** позволяет определить список владельцев модуля. Список используется для уведомления сотрудников о новых пулл-реквестах в данный модуль. Поддерживается два варианта указания владельца:

1. Перечисление конкретных пользователей:

    ```yamake
    OWNER(
        prettyboy
        vania-pooh
    )
    ```

2. Указание группы пользователей:
    ```yamake
    OWNER(g:sandbox) # Префикс "g:" означает, что указана группа
    ```
    Название групп и списки пользователей, входящих в группу, хранятся в каталоге [/groups](https://a.yandex-team.ru/arc/trunk/arcadia/groups) единого репозитория.

Любой файл **ya.make** содержит описание **одного модуля**. Такое описание начинается с объявления типа модуля, т.е. содержит информацию о том, что за модуль собираем: программу, тесты, библиотеку и т.п. В зависимости от используемого языка программирования макрос называется по-разному, например:

* **Исполняемая программа:** `PROGRAM()` для C++, `PY2_PROGRAM()` для Python, `JAVA_PROGRAM()` для Java, `GO_PROGRAM()` для Go;
* **Библиотека**: `LIBRARY()` для C++, `PY2_LIBRARY()` для Python, `JAVA_LIBRARY()` для Java, `GO_LIBRARY()` для Go;
* **Тесты**: `UNITTEST()` для C++, `PY2TEST()` для Python, `JUNIT5()` для Java и т.п.

После объявления типа модуля идет набор макросов с описанием модуля. Например, здесь указывается список файлов с исходными кодами, тестами, внешние зависимости, различные настройки параметров сборки и так далее. Описание модуля всегда завершается макросом `END()`.

## Многомодульные проекты { #multi-module }

В каждый каталог единого репозитория можно положить только один файл **ya.make**. Это позволяет объявить только **один модуль**. В реальных проектах используются сразу несколько типов модулей. Например, почти всегда нужно **скомпилировать исходный код** и **выполнить тесты**. Чтобы иметь возможность собирать проекты, состоящие из нескольких модулей, существует специальный макрос `RECURSE()`. Обычно он используется в одном из двух вариантов:

1. **Только объявление списка модулей:**

    ```yamake
    OWNER(g:my-group)

    # Здесь ничего собирать не требуется

    RECURSE( # Выполнение ya make в каталоге с этим ya.make приведет к сборке указанных модулей
        module-1 # Здесь лежит свой ya.make
        module-2
        module-3
    )
    ```

2. **Сборка программы и ее модулей:**

    ```yamake
    OWNER(g:my-group)

    PROGRAM()

    SRCS(
        main.cpp
    )

    END()

    RECURSE( # Перед сборкой программы, происходит сборка связанных модулей
        module-1
        module-2
        module-3
    )
    ```

## Зависимости { #peerdir }

Большинство проектов имеют зависимости от [внешних библиотек](../rules/contrib/add.md) или других независимых проектов. Объявление таких внешних зависимостей делается с помощью макроса `PEERDIR()`:

```yamake
PY2_LIBRARY()

OWNER(g:my-group)

PY_SRCS(
    __init__.py
    auth.py
)

PEERDIR( # Список внешних зависимостей
    contrib/python/requests # Каталоги берутся от корня единого репозитория
    contrib/python/six
)

END()
```

## Повторяющиеся макросы { #include }

Бывают случаи, когда требуется включить в несколько **ya.make** файлов, абсолютно одинаковые макросы. Такая задача решается вынесением повторяющихся макросов в отдельный файл (по соглашению он имеет расширение ***.inc**) и использованием макроса `INCLUDE()`:

```yamake
OWNER(g:my-group)

PY3TEST()

SIZE(MEDIUM)

INCLUDE(${ARCADIA_ROOT}/my-project/util/common.inc) # Содержимое файла /my-project/util/common.inc будет вставлено вместо этого макроса при чтении ya.make

PY_SRCS(
    base.py
)

TEST_SRCS(
    cases/auth.py
    cases/crypto.py
)

END()
```
