[build::eng]
раздел 02 · инструменты

ОТ MAKE ДО BAZEL

Один и тот же проект — четыре способа его описать. Сравним синтаксис, философию и скорость главных инструментов экосистемы.

2.1

Один проект — четыре описания

Makefile
CXX      := g++
CXXFLAGS := -std=c++20 -Wall -O2
SRC      := main.cpp parser.cpp engine.cpp
OBJ      := $(SRC:.cpp=.o)

app: $(OBJ)
	$(CXX) $(CXXFLAGS) -o $@ $^

%.o: %.cpp parser.h engine.h
	$(CXX) $(CXXFLAGS) -c $< -o $@

clean:
	rm -f app $(OBJ)

Сильные стороны

  • есть в любой UNIX-системе из коробки
  • нулевой порог входа для пары файлов
  • полный контроль над каждой командой

Слабые стороны

  • зависимости приходится поддерживать вручную
  • нет абстракции целей и переносимости на Windows
  • сложные проекты превращаются в спагетти
CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(engine_lab CXX)

add_library(core
    src/parser.cpp
    src/engine.cpp)
target_include_directories(core PUBLIC include)
target_compile_features(core PRIVATE cxx_std_20)

add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE core)

Сильные стороны

  • стандарт индустрии: почти все библиотеки «говорят» на нём
  • цели несут свойства: флаги, инклуды, зависимости — всё наследуется
  • генерирует проекты для любого нативного инструмента

Слабые стороны

  • исторический синтаксис требует дисциплины
  • легко выстрелить в ногу глобальными переменными
build.ninja
# обычно генерирует CMake — руками не пишут
rule cc
  command = g++ -std=c++20 -O2 -MMD -c $in -o $out
  depfile = $out.d
  description = CC $out

rule link
  command = g++ $in -o $out
  description = LINK $out

build main.o:   cc main.cpp
build parser.o: cc parser.cpp
build app:      link main.o parser.o

Сильные стороны

  • экстремально быстрый старт даже на десятках тысяч целей
  • точный учёт зависимостей через .d-файлы компилятора
  • минимализм: только исполнение графа

Слабые стороны

  • не предназначен для ручного написания
  • нет абстракций: библиотеки, флаги — всё этажом выше
meson.build
project('engine_lab', 'cpp',
  default_options : ['cpp_std=c++20', 'buildtype=release'])

src = ['src/main.cpp', 'src/parser.cpp', 'src/engine.cpp']
inc = include_directories('include')

executable('app', src,
  include_directories : inc,
  install : true)

Сильные стороны

  • человекочитаемый синтаксис в духе Python
  • скорость Ninja под капотом по умолчанию
  • внятные сообщения об ошибках

Слабые стороны

  • экосистема скромнее, чем у CMake
  • меньше примеров и ответов на stackoverflow
2.2

Сравнительная таблица

ИнструментУровеньЯзык описанияСкоростьКроссплатформаЭкосистема
MakeнизкийMakefile●●●●●●●●●●●●●●●
CMakeвысокийCMake-скрипт●●●●●●●●●●●●●●●
Ninjaгенераторгенерируемый●●●●●●●●●●●●●●●
MesonвысокийPython-подобный●●●●●●●●●●●●●●●
BazelмонорепоStarlark●●●●●●●●●●●●●●●
2.3

Что выбрать

// новый проект

Библиотека или приложение с прицелом на рост и интеграции.

→ CMake + генератор Ninja
// монорепозиторий

Сотни пакетов, много команд, нужна герметичность и удалённое кэширование.

→ Bazel / Buck2
// embedded и минимализм

Мало файлов, нестандартный тулчейн, хочется контролировать каждый флаг.

→ Make или xmake