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