Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Настройка окружения

Вы можете использовать IDE по вкусу для выполнения практик/домашних заданий.

Чтобы ваш код был в определенном стиле и при написании кода вы быстро увидели опечатки/минорные баги — вам предоставлены .clang-tidy и .clang-format файлы в репозиториях.

В подразделах описаны этапы конфигурации некоторых IDE (рекомендуется CLion).

Окружение

Большинство заданий на курсе требуют корректности и переносимости исходного кода, что, к сожалению, нельзя провалидировать наверняка. Поэтому в качестве приближения к этой цели все задания проверяются на наборе конфигураций: с разными компиляторами и/или их флагами.

Поддерживать локально все тестовые конфигурации может быть проблематично: начиная от привязки к конкретным версиям компиляторов и заканчивая специфичными системными переменными окружения, влияющими на сборочный процесс. Поэтому советуем потратить время на ознакомление с Docker: таким образом вы сможете проверять свои решения в точности в таком же окружении, как и в CI, что облегчит отлов багов и сведет проблемы невоспроизводимости поведения к минимуму. Подробнее можно ознакомиться в репозитории с контейнерами.

Тем не менее, иметь в локальной системе какой-то сборочный тулчейн может быть удобно для быстрых проверок гипотез и общей адекватности вашего решения. Также может быть полезен онлайн-инструмент Compiler Explorer.

Warning

Если вы пользователь macOS, будьте внимательны к предустановленному с Xcode компилятору. Вероятно, это Apple Clangфорк Clang, кастомизированный под Apple и потенциально сильно отличающийся от используемого в CI.

CMake

Почти все задания этого курса собираются мета-системой сборки CMake, являющейся одной из самых распространенных систем для проектов на C++.

CMake — это не система сборки в классическом понимании, а способ её автоматизации. CMake генерирует конфигурационные файлы для существующих систем сборки, например для Make или Ninja, и затем использует их. Конфигурации CMake-проектов определяются файлом CMakeLists.txt в корне проекта (может использовать поддиректории со своими CMakeLists.txt, а также вспомогательные .cmake-файлы).

Сборку CMake-проекта можно разделить на три этапа:

  1. Конфигурация — CMake анализирует файл CMakeLists.txt, определяет компилятор, платформу, зависимости и другие параметры проекта. Результат этапа — внутреннее представление проекта в кэше CMake (файл CMakeCache.txt) и некоторые другие вспомогательные служебные файлы, которые создаются в билд-директории (отдельная директория, выделенная под артефакты сборки, чтобы не засорять дерево исходного кода).
  2. Генерация — на основе внутреннего представления CMake создаёт конфигурационные файлы для конкретной системы сборки (например, Makefile для Make или build.ninja для Ninja). Эти файлы описывают, какие команды компиляции или линковки нужно выполнить, в каком порядке и с какими флагами.
  3. Сборка — запуск выбранной системы сборки, которая уже непосредственно выполняет компиляцию и линковку проекта, и создаёт соответствующие артефакты в билд-директории.

На практике конфигурация и генерация выполняются одной командой, разделение их на два этапа лишь концептуально.

Рассмотрим простейший пример сборки CMake-проекта:

  1. Конфигурация и генерация:
    cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug -DCT_SANITIZED=ON
    
    где
    • -S — корневая директория CMake-проекта (в данном случае и по умолчанию — текущая);
    • -B — директория, куда CMake положит все генерируемые файлы конфигурации и артефакты (в данном случае — build-debug);
    • -DCMAKE_BUILD_TYPE=Debug — выставляет переменную CMAKE_BUILD_TYPE, определяющую режим сборки, что может влиять на различные флаги компилятора и линковщика (например, -g для дебага);
    • -DCT_SANITIZED — включает санитайзеры (см., как используется этот параметр в cmake/ConfigureCompiler.cmake в репозиториях с заданиями);
    • тут же могут передаваться другие переменные через -DVAR=Value, которые могут использоваться, например, для условной компиляции.
  2. Сборка:
    cmake --build build-debug -j <N>
    
    где
    • --build build-debug — директория, в котором лежат файлы конфигурации из предыдущего шага (в данном примере — build-debug);
    • -j <N> — количество потоков, которые вы готовы отдать системе сборки, благодаря чему будет достигаться параллелизм.

После описанных манипуляций в билд-директории (build-debug) появится целевой бинарный файл, который и нужно запустить.

Note

При изменении исходных файлов для перекомпиляции нет необходимости выполнять первый этап заново. Однако если меняется состав исходных файлов или cmake-скрипты, то нужно заново выполнить конфигурацию, чтобы CMake подтянул изменения в систему сборки.

CMake Presets

Во всех заданиях, собираемых CMake, используются пресеты сборки (указаны в CMakePresets.json в корне репозитория). Выбор пресета позволяет выбрать режим сборки и установить типичный для него набор флагов и опций. При ручном использовании CMake, пресет нужно задать флагом --preset на этапе конфигурации, например:

cmake --preset RelWithDebInfo

Параметр -S, как мы помним, по умолчанию является текущей директорией. Параметр -B задан в CMakePresets.json и в наших проектах будет build/RelWithDebInfo (и аналогично для других пресетов).

Далее сборку и запуск можно продолжать как описано выше.

Зачастую для упрощения процесса сборки из консоли можно пользоваться скриптом для CI (обычно ci-extra/build.sh в репозиториях).

Зависимости

У многих заданий курса будут зависимости (например, фреймворк для юнит-тестирования). Есть множество подходов к управлению такими зависимостями, одним из наиболее популярных и гибких в экосистеме CMake является FetchContent, который и применяется в репозиториях заданий (где такая необходимость возникает).

Отдельно что-то делать для установки таких зависимостей вам не требуется, они будут скачаны на этапе конфигурации CMake, и впоследствии собраны вместе с остальным проектом.

Sanitizers & Valgrind

Вы можете заметить, что существуют пресеты Sanitized и SanitizedDebug. Они добавляют дополнительные флаги компилятору и линкеру, благодаря чему в программе делается больше проверок корректности вашего кода. Проверка вашего решения на этих пресетах поможет вам отловить баги.

Также в CI существует шаг тестирования с Valgrind — это другой способ проверки корректности программы, которым также не стоит пренебрегать при поиске ошибок. Для тестирования с Valgrind можно обратиться к скрипту ci-extra/test-valgrind.sh.

Note

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

Опциональные утилиты

ccache

Для работы локально может быть удобен ccache: утилита, кэширующая стадию компиляции, что значительно ускоряет сборку проектов c большим количеством единиц трансляции. Тем не менее, в большинстве заданий курса она не принесет ощутимого выигрыша, но стоит иметь ее в виду для личных проектов. Пример настройки можно увидеть в Dockerfile в репозитории с контейнерами — изучите man page ccache самостоятельно, чтобы понять какие из переменных вам действительно необходимы.

Ninja

По умолчанию CMake генерирует Make. Тем не менее, Ninja лучше подходит для этой роли: в отличие от Make, он задизайнен быть генерируемым и эффективно параллелиться. Являясь очень простой системой сборки, Ninja собирается гораздо быстрее, чем Make, поэтому хорошая идея пользоваться им.