История про CLion, docker, conan, cmake, ninja, cotire и gdb.
Небольшое предисловие
Разработкой на C++ я занимаюсь уже лет 15 и когда-то начинал с «Watcom С». О нем у меня остались самые теплые воспоминания. Но, так как мне больше приходилось писать для консоли UNIX, я перешел на vim в качестве IDE. В целом, он достаточно удобен. Его плагины творят чудеса, можно настроить autocomplete, просмотр иерархии классов, быстрый переход к определению или поиск, в общем всё, что должны уметь IDE, там можно поднять. Боль приходит в тот момент, когда ты пытаешься установить и освоить новый плагин. Это всё заводится не везде и не всегда, и, зачастую, жрет проц и память похлеще любой java.
Периодически я поглядывал на Qt Creator. Но так и не решился на него перейти.
Первое знакомство
И вот, в один из таких моментов мне на глаза попался CLion. После конструктора под названием vim очень хотелось получить решение «из коробки». На первый взгляд, он мне очень понравился. Быстрые подсказки, удобная навигация, работа с cmake проектами, как с родными, поддержка режима vim (правда, в последствии, я её отключил).
Облом случился довольно скоро. Дело в том что, хоть пишу я на данный момент в основном под linux, в качестве рабочей станции у меня macbook pro. Да, я такой! И искренне считаю извращенцами людей, которые, купив ноутбук apple, устанавливают на него что-нибудь кроме macOS. Поэтому, для меня критически важна возможность удаленной сборки или сборки через docker. А её, сколько пользователи ни просили, в CLion пока нет. Первая попытка перехода закончилась ничем — ведь решения «из коробки» нет.
Вторая попытка
Но боль с настройкой vim никуда не ушла, и я решил дать CLion второй шанс — попробовать решить те проблемы, которые передо мной встали, самостоятельно. А это:
- Отсутствие локально установленный библиотек. CLion не может выдавать подсказки по классам, описания которых не видит
- Собственно сама сборка
До этого, я пользовался библиотеками, которые поставляются в пакетах вместе ОС. С CLion мне бы пришлось все заголовочные файлы ОС закидывать к себе на Mac, чего категорически не хотелось. Но тут меня выручил conan. Он хранит все собранные библиотеки в отдельном каталоге, который легко можно подложить себе.
Со вторым все оказалось не так просто. Я решил просто подменить cmake на свой скрипт, который выполнит сборку внутри docker контейнера. Мне не улыбалось каждый раз, когда я синхронизирую свой код из репозитория или вливаю его обратно, добавлять/удалять дополнительный Target в CMakeLists.txt, как мне советовали. Хотелось иметь возможность склонировать любой проект и тут же собраться без танцев с бубном. Это оказалось не так просто. Основную сложность вызвала сборка тестового проекта CLion, которую он выполняет при смене toolchain, и проброс параметров содержащих пробелы внутрь контейнера. Но я справился.
Если у вас всё хорошо — вы просто ещё не всё знаете
Казалось бы — у меня получилось!
…
Я был наслышан, что сборка на С++ с использованием С++14 или С++17 — довольно медленная штука, и, поначалу, всё списывал на медлительность компилятора. Но потом заметил, что удаленно на выделенном сервере собирается уж как-то слишком шустро. Чем больше становился проект — тем большие сомнения рождались в моей душе.
Докер оказался с двойным дном. Да, сервер поднимается шустро, вот только компиляция на osxfs работает, как оказалось в ТРИ раза медленнее, чем на overlay. Поэтому пришлось перейти на использование rsync. Так же, я открыл для себя настройки томов docker. Если использовать delegated — скорость сборки увеличивается процентов на 15. Подробнее.
Попутно померил время сборки через ninja против стандартного make — разница вышла практически вдвое. Правда CLion требует собираться именно через make, иначе, прощайте подсказки. Пришлось прогонять сборку дважды, один раз через make, для CLion, второй — через ninja. Выигрыш тут в том, что проект меняется довольно редко, а собираться надо часто.
Еще, я попробовал использовать прекомпилированные заголовки (cotire) — эффект оказался неоднозначным. К тому же, это требовало вручную формировать stdafx.h (или любой другой файл) и включать его во все .cpp. А это, в свою очередь, не очень нравится CLion. Он начинает считать все остальные include лишними. Это можно было обойти, но выигрыш был не такой значительный.
Последнее, что я сделал — отказался от ccache. В моем случае, он давал задержку примерно в секунду. Да, если подходящий файл найден, это ускоряет сборку. Но такое не часто случается, когда ты пишешь новый код.
Аппетит приходит во время еды
Раз уж сборка у меня завелась, почему бы не попробовать растолкать и отладку!
Раньше я считал, что gdb внутри docker запустить невозможно. Оказалось, что это не так. Параметр --security-opt seccomp:unconfined снимает данную проблему. А статья подробно описывает, как и что надо настраивать. Но, и тут случился непредвиденный облом. Я собирался через clang (что логично), а для отладки надо использовать gcc. В противном случае, запустить приложение в отладчике вы сможете, но вот посмотреть значения внутри stl контейнеров уже нет. В принципе, собрать через gcc — не проблема. Тогда, и правда всё работает.
Эпилог
Мыши плакали, кололись, но продолжали есть кактус… Ждем! Ждем удаленную сборку. Ждем полноценную поддержку C++17. JetBrains и JFrog в своих рассылках постоянно поминают друг друга, но какой-либо интеграции пока нет. Даже, собираясь локально, придется вводить команды conan вручную. Ждёмс!
Еще было бы неплохо заполучить поддержку сборки через ninja. 50% производительности на дороге валяются.
Кому интересно, мои скрипты и Dockerfile для сборки шаблона можно найти на GitHub.
Автор: Doktor3lo