Мы строили, строили и наконец — построили!

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

Итак. Системы сборки — это правильно. Целый день только и делаю, что пишу, собираю, запускаю, пишу, собираю, запускаю. Особенно меня волнует второй этап — этап сборки (потому что я в нем не принимаю участия).
Я например, очень люблю ant, но собирать не-java проект с помощью ant я бы не решился. То же самое касается scons и прочих языко-специфичных систем сборки.

Поэтому в основном я использую старый добрый GNU Make. Был у меня однажды проект, так его makefile был настолько раздут, что проверял корректность переменных окружения до того, как выполнить какую-либо команду. Ну и самих переменных окружения было за полсотни. Он еще и дату билда сам считал и вшивал в бинарник (хотя надо это было далеко не всегда). Меня все устраивало, хотя сейчас я бы не хотел в нем разбираться.

Теперь ключевой момент проповеди: я узнал о ninja, и это заставило меня перевернуть свои взгляды на жизнь системы сборки.

Создан был ninja под крылом гугла, как система сборки для chromium (до этого у них был scons и GNU Make). Основная причина перехода — скорость. Я был очень удивлен, когда узнал, что GNU Make последних версий для правила foo: foo.c начинает искать каталоги RCS и SCSS (это же сколько лет прошло с тех пор, как перестали пользоваться rcs!). Ninja в этом плане более современен.

Так вот, ninja не рекомендует создавать makefile вручную. Разработчики считают, что лучше сделать скрипт типа configure, который сам сгенерирует build-файл, на основе которого уже пойдет сборка. Человек ошибается чаще, чем скрипт. А значит действия человека надо перепроверять. Вроде бы очевидная вещь, но я лично не задумывался. Действительно, когда система сборки сама начинает принимать решения (проверять условия, контролировать корректность переменных) — начинает уходить много времени. За день я делаю несколько десятков (сотен?) билдов. Конфигурация моей машины при этом не меняется месяцами. Так зачем перепроверять есть ли у меня та или иная зависимость каждый раз? Только потому что я человек и могу сделать опечатку в названии какой-то библиотеки?

Ninja избавлен от этих сложностей.

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

Собираем систему сборки

Сам проект лежит здесь. Сборка происходит просто и быстро:

$ git clone https://github.com/martine/ninja.git
$ cd ninja
$ ./bootstrap.sh

Все. У вас есть ninja.

По умолчанию билд-файл называется build.ninja. Никаких неявных правил (как в make, например, для компиляции C файлов: $(CC) -c $(CFLAGS) $^ -o $@) здесь нет.

Изучаем

Билд-файл может содержать переменные, правила и зависимости.

С переменными все просто:

myvar = myvalue
cflags = -Wall -g -O2 -I/path/to/some/includes
ldflags = -L/path/to/some/libraries

Обращение к переменной как в GNU Make: $myvar, $cflags, $ldflags.
Важно: переменные не могут менять своего значения, они константны.

Правила — это сокращенная запись для команд. Правило начинается с ключевого слова rule, потом идет имя правила, а следом определения переменных. Переменная command зарезервирована и определяет действия, которые выполняются при обращении к правилу.

rule cc
  command = gcc $cflags -c $in -o $out

Переменные $in и $out служебные, они есть у любого правила и хранят список входных и выходных файлов соответственно.

Зависимости указываются следующим образом (начинаются со слова build):

build foo.o: cc foo.c
build special.o: cc special.c
  cflags = -Wall

Зависимость для special.o интересна тем, что она «затеняет» предыдущее значение cflags, и в данном случае в правиле cc для файла special.c значение флагов будет «-Wall».

Вот и все основы ninja. За счет такой простоты говорят, что инкрементальная сборка хромиума сократилась с 20 секунд до 6 после перехода на ninja.

Выводы

Я не перешел на ninja, потому что она еще мало поддерживается дистрибутивами. Но мне нравится легкость создания build-файлов и их понимания.
По крайней мере я перевел несколько своих проектов на упрощенные makefile и несложный скриптик для их генерации. Но до сих пор жду когда в ninja добавят поддержку inotify для непрерывных билдов — скорость действительно позволяет. Да и в целом философия ninja мне очень близка, желаю и вам к ней приобщиться.

Реклама

2 comments on “Мы строили, строили и наконец — построили!

  1. StepLg:

    Не смог найти в документации — есть ли подобия wildcard? То есть я по шаблону хочу получить список всех файлов, например *.cpp, и включить их в сборку.

    • Бегло пробежался по исходникам — скорее всего не поддерживается.
      Потому разработчики и советуют генерировать build.ninja скриптом, например:

      #!/bin/sh
      echo "rule cc" > build.ninja
      echo "	command = gcc -c $in -o $out" >> build.ninja
      for f in *.c; do
      	obj=`basename $f .c`
      	echo "build $obj.o : cc $f" >> build.ninja
      done

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s