Найти в Дзене
mamaich

Сборка исходников Яндекса с помощью ya make

Я являюсь активным пользователем нескольких устройств Яндекса и ряда их сервисов, а так же периодически что-то программлю/реверсю для себя в качестве хобби. Вот на днях стало интересно - а как же построен процесс сборки кода в этой крупной ИТ компании.

Яндекс опубликовал исходники пары своих проектов: catboost и ydb. В обоих для сборки используется утилита "ya make" их собственной разработки. Ниже расскажу свой опыт работы с ней.

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

Буквально пару дней назад (вторая неделя февраля 2023 г.) оказалось, что из указанных проектов была удалена утилита "ya" и все "ya.make" файлы. Но git всё помнит, так что их можно найти покопавшись в прошлых ветках. Что странно, документацию по сборке, с использованием данной утилиты из проекта catboost не удалили.

К слову. Рекомендую на машину для сборки установить nix. Ya make с ним дружит, и при его отсутствии у меня возникали проблемы (не вспомню уже какие).

На своей "сборочной" виртуалке, для удобства, я объединил вручную исходники всех проектов в папку /ya. Тем самым объединились не только проекты, но и используемые ими библиотеки.

В проекте catboost утилита ya, библиотеки и скрипты новее, чем в ydb, поэтому при объединении я отдавал приоритет им.

Если посмотреть в упомянутые исходники, то видно, что для работы ya make требуется определенная структура вспомогательных папок:

build - скрипты для сборки
certs - сертификаты, если потребуется подписать файлы
contrib - исходники сторонних библиотек
и утилит вроде bison
library
- исходники сторонних библиотек (не знаю по какому принципу код попадает в contrib или library)
tools - утилиты собственной разработки Яндекса, использующиеся в процессе сборки
util - тоже исходники каких-то библиотек
ya - сама утилита

Для начала, в качестве проверки работоспособности среды, можно собрать вспомогательную утилиту, например rescompiler. Для этого переходим в tools/rescompiler, запускаем "/ya/ya make" и получаем облом:

Первые две "Downloading" - загрузка бинарника ya и приблуд к нему, а далее идет неудачная попытка загрузки инструментария под мою операционную систему. У меня на виртуалке ubuntu 18, и судя по файлу build/platform/linux_sdk/ya.make, для нее нужен пакет OS_SDK_ROOT-sbr:617908641 (как расшифровывается аббревиатура sbr - сборка?). Ссылки на загрузки файлов находятся в build/mapping.conf.json - но 617908641 там нет. Можно, конечно, поподбирать URL - но проще поднять Ubuntu 14, либо исправить build/ymake_conf.py, чтобы он вместо 'ubuntu-18' возвращал 'ubuntu-14'.

Вариант с установкой Ubuntu 14 более правильный - просто потому что временами нам может потребоваться использовать "родной" компилятор из операционной системы, а мешать в одном проекте библиотеки, собранные разными компиляторами не есть гуд. Но у меня работало и с правкой скрипта.

После проделанных действий, ya make возвращает зелёное Ok:

-2

Далее можно попробовать собрать уже сам исходник проекта. И тут нас поджидает еще один "нюанс": ошибка "can't resolve sysincl target: ${ARCADIA_ROOT}/DO_NOT_INCLUDE_NON_STANDARD_EXPERIMENTAL_SOURCE_LOCATION". Я не стал вникать в ее причину, а просто начал использовать "ya make -k" для пропуска ошибок. Благо, эта ошибка возникает на стадии проверки заголовочных файлов и на итог сборки не влияет.

А вот далее - собственно то, ради чего я и затеял написание данной статьи.

Если хотим дорабатывать существующий проект, то может случиться, что нужной нам библиотеки не окажется в contrib или library. В таком случае есть два варианта:

  1. Правильный. Так поступает Яндекс. Берется их собственная утилита yamaker, и с ее помощью создается ya.make. Но, так как эта утилита есть только у Яндекса - это не наш способ.
  2. Болезненный. Вручную создаем файл ya.make по аналогии с существующими.

Я пошел третьим путём.
Мне надо было добавить в проект использование библиотеки jsoncpp. Посмотрев в ya.make файле от ydb, я узнал, что такая библиотека уже была у Яндекса и лежала в папке contrib/deprecated/jsoncpp. Естественно, в двух публичных проектах Яндекса по данному пути ничего не оказалось.

Скачиваю библиотеку в эту же папку (пусть будет как у Яндекса), после чего собираю ее как обычно компилятором из операционной системы (именно поэтому я и рекомендовал выше использовать Ubuntu 14).

Чтобы в процессе сборки эта библиотека подключилась к проекту - надо в "родном" ya.make бинарника проекта добавить в раздел PEERDIR ее путь:

-3

тем самым мы говорим, что надо собрать с исходников данную папку, а, в случае библиотеки, это добавит соответствующий .a файл при линковке проекта. Возможно, того же эффекта можно достичь конструкцией LDFLAGS(-ljsoncpp) в ya.make, но я не проверял.

Чтобы компилятору передали путь, где лежат заголовочные файлы jsoncpp - нужно добавить в тот ya.make, в котором указаны наши C/CPP файлы, их использующие, строки:

-4

я не знаю, что значит GLOBAL, а играться, добавляя и убирая его было лень - поэтому добавил путь до jsoncpp/include два раза. Если секции ADDINCL не было - не забудьте закрывающую скобку (на скриншоте ее отрезало). Возможно, с добавлением путей до include файлов поможет конструкция CFLAGS(-I contrib/deprecated/jsoncpp/include) - но и это я тоже не пробовал.

Чтобы ya make воспринял папку contrib/deprecated/jsoncpp как расположение библиотеки и при линковке проекта передал линкеру файл libjsoncpp.a, нужно создать в папке contrib/deprecated/jsoncpp файл ya.make такого содержания:

-5

то есть, я указываю те же пути include и "левый" файл a.cpp (если файл не указать, то ya make не станет добавлять libjsoncpp.a к командной строке линкера). Я создал файл a.cpp размером 0 байт - надо просто чтобы он был.

Также надо скопировать libjsoncpp.a непосредственно в папку contrib/deprecated/jsoncpp - там его будет искать линкер. Имя .a файла - это то, что указано в LIBRARY(), с добавлением lib в начало. Если оставить пустым - имя сгенерируется автоматически по полному пути папки (например, libcontrib-deprecated-jsoncpp.a).

Для проверки, что ya.make для библиотеки сделан правильно, запускаем ya make из папки с библиотекой:

-6

Видим Ok, на ворнинг с симлинком не обращаем внимания (это он пытался заменить нашу добавленную библиотеку тем мусором, что он собрал из пустого файла a.cpp).

Для чего я написал эту статью? В интернете всякое встречается. Возможно, кто-то наткнется на исходники других проектов Яндекса, у которых будет не хватать библиотек - а здесь я рассказал, как можно их добавить с минимумом усилий. Да и просто интересно было, например, я узнал о существовании утилиты fptrace, с помощью которой можно записать в лог или в виде SH скрипта все команды, которые запускает интересующий нас процесс. Обязательно буду пользоваться ей в будущем.