CLion 2020.2: поддержка проектной модели Makefile, больше C++20 и не только
Привет, Хабр!
У нашей команды выдалось очень насыщенное лето, результатами которого мы и спешим сегодня поделиться. Итак, встречайте новый релиз CLion 2020.2!
Коротко о том, что вошло в новую версию:
- Поддержка проектной модели Makefile.
- Последние обновления в CMake.
- Новые возможности C++20:
explicit(bool)
, назначенные инициализаторы (designated initializers), циклыfor
на основе диапазонов с инициализаторами. - Обновленный статический анализатор кода: анализ на висячие указатели (dangling pointers), поиск возможностей упрощения кода, поиск неиспользуемого кода, анализ возвращаемого значения функции, ограниченной концептом.
- Юнит-тестирование: поддержка нового фреймворка doctest, новые возможности Catch2 и Google Test. А также упрощение сбора метрик покрытия кода.
- Обновления в плагине PlatformIO для разработки встроенных систем.
- Улучшения в поддержке систем контроля версий.
- Улучшения производительности редактора.
- Исправления в отладчиках.
Поддержка проектной модели Makefile
Отметив этой весной пятилетие CLion, мы тут же включились в активную доработку самой ожидаемой возможности в IDE — поддержки проектов на основе Makefile. До этого у нас был только сырой прототип, который мы давали попробовать в частном порядке самым смелым нашим пользователям. Благодаря им мы смогли проверить прототип на широкой выборке Makefile-проектов, исправить множество проблем в нем и понять текущие (надеемся, временные) ограничения нашего решения. Наша цель — позволить пользователям работать с проектом на основе Makefile в CLion со всеми умными возможностями IDE, такими как навигация, рефакторинги, статический анализ кода и другие.
Текущий подход вкратце выглядит так: CLion запускает команду make
на вашем проекте с дополнительной опцией --just-print
, чтобы сэкономить время на реальной сборке. Если CLion может успешно распарсить вывод команды, то проект открывается и все работает!
Сразу оговоримся, работа над поддержкой Makefile в CLion еще далека от завершения — известных ограничений и недоделок еще много. Самое заметное:
- Не поддерживаются проекты, использующие libtool (CPP-19549), distcc и ccache (CPP-19305), и другие обертки, которые «скрывают» флаги компиляции из выдачи или вмешиваются в вывод команды
make
. - CLion пока не умеет работать с выводом non-GNU Makes (например, NMake, BSD) (CPP-18723).
- Не поддерживаются проекты, которые отключают вывод имен директорий в процессе сборки, так что CLion не может определить, к каким именно файлам относятся те или иные команды сборки.
Но даже текущее решение уже позволяет открыть в CLion ядро Линукса или код сервера базы данных PostgreSQL. Если интересно, то текущий список проектов, на которых наш прототип работает (а так же некоторые проекты, где он не работает, с указанными проблемами) можно найти на этой странице.
Попробовать на своем проекте очень просто:
- Подготовить проект, чтобы получить Makefile для него (например, во многих случаях надо запустить
./configure
, так как CLion пока что сам не умеет этого делать). - Открыть проект через File | Open и указать директорию, которая содержит самый главный проектный Makefile или прямо сам этот файл. Подтвердить, что открыть хотите как проект.
- CLion уточнит, запустить ли Clean. Это нужно, чтобы вызов команды
make
подхватил все файлы, а не только последние изменения. - Это, собственно, и все! Результат попытки загрузки проекта будет выведен в окно Build.
Вывод может содержать какие-то предупреждения, но если загрузка завершилась в целом успешно (около самой первой задачи должна быть зеленая отметка), то с проектом можно работать в CLion.
Настройки аргументов команды загрузки, тулчейн, используемый для загрузки, и другие опции можно найти в Settings/Preferences | Build, Execution, Deployment | Makefile:
Для запуска и отладки Makefile-приложений потребуется дополнительно создать конфигурации Makefile Application. При этом таргет можно будет выбрать из выпадающего списка — CLion подскажет, какие есть варианты:
В нашем блоге на английском языке можно найти больше информации о работе с проектами на Makefile в CLion. Также рекомендуем к просмотру короткое демо (на английском):
Последние обновления в CMake
Как показывает статистика, три самых популярных сейчас проектных модели среди разработчиков на C++, это CMake, msbuild и Makefile. И именно CMake возглавляет этот рейтинг уже три года и продолжает расти. Поэтому мы непрерывно обновляем забандленную в CLion версию CMake и работаем над поддержкой последних нововведений в самом CMake. В этот раз мы обновили версию до 3.17 и соответственно добавили поддержку двух новых полезных возможностей CMake:
- С Ninja Multi-Config теперь возможно генерировать все конфигурации (а не только выбранную Debug или Release) при использовании Ninja генератора (включается через
-G "Ninja Multi-Config"
). CLion правда пока использует только одну конфигурацию, указанную в настройках профиля CMake для проекта. Но это ограничение текущего UI, которое мы планируем исправить в будущем. - CMake precompiled headers заслуживают большего внимания. Вообще, идея предкомпилированных заголовочных файлов (PCH) не нова и поддерживается компиляторами уже давно. CLion также умеет работать с PCH довольно давно. Теперь же можно не вспоминать флаги компилятора для PCH и не передавать их в CMake каждому конкретному компилятору по-своему, а просто добавить заголовочные файлы в PCH-переменные таргета через команду
target_precompile_headers
. CLion 2020.2 теперь умеет с таким работать:
Заслуживает внимания и возможность открыть CMake проект в CLion из директории с результатом генерации CMake, теперь не только для генератора Makefile, но и для любого другого! Экономьте время — открывайте уже собранные проекты в CLion без перезапуска команды CMake на проекте.
С++20
А вы знаете, что, по нашим данным, в этом году уже 12% разработчиков на C++ используют стандарт C++20?! Поэтому мы, конечно, работаем активно над поддержкой новых возможностей в CLion. Но давайте сначала вспомним, что у нас вообще с языковым движками в CLion.
Итак, на текущий момент их два — встроенный на основе Java/Kotlin и довольно новый на основе Clangd, соответственно на С++ (для его разработки мы пользуемся CLion). Сейчас все усилия вкладываются в движок на основе Clangd. Он кажется хорошей перспективой, хотя действия на всем проекте (вроде рефакторингов) на нем пока делать нельзя — тут даже не идеальный и местами медленный Java-based движок выигрывает за счет всяких специфических оптимизаций и отложенных резолвов, ну и, конечно, за счет наличия кэша символов, необходимого для рефакторингов.
Но у Clangd есть один очень большой плюс — над поддержкой последних стандартов C++ в Clang там работает все сообщество, ведь проект открытый. Это, конечно, не означает, что нам совсем ничего не надо делать — эту поддержку все равно потом надо адаптировать под нужды CLion. Но это уже проще, чем писать поддержку возможностей C++ с нуля! А еще на основе поддержки в Clang можно писать свой специфический анализ или делать какие-то специальные фичи (так мы, например, сделали автодополнение для Concept-ов несколько релизов назад).
Мы убедились, что последнее обновление Clangd-движка, пришедшее с LLVM, стабильнее ведет себя на коде на C++20, да и в целом по нашей встроенной статистике Clangd-движок стал стабильнее. Поэтому убрали из настроек возможность полностью отключать Clangd-движок. Зато добавили в Settings/Preferences | Languages & Frameworks | C/C++ | Clangd информацию о той ревизии, с которой собран наш движок. Теперь вы знаете, чего ожидать от него в плане поддержки C++ и анализа встроенного Clang-Tidy:
Кстати, в нашем онлайн-хелпе есть отличная статья со сравнительным анализом двух движков в плане поддержки возможностей C++.
А теперь о том, что же собственно добавилось из поддержки C++20:
- Автодополнение для ключевых слов C++20:
char8_t
,consteval
иconstinit
,co_await
,co_return
, иco_yield
. - Автодополнение для полей из базового класса в назначенных инициализаторах:
- Конструкция
explicit(bool)
теперь правильно подсвечивается, в ней работают подсказки имен, навигация и рефакторинги: - Для циклов
for
на основе диапазонов с инициализаторами заработал рефакторинг Rename для переменных цикла.
Статический анализатор кода
В прошлом релизе мы перевели самый «тяжелый» наш анализ — анализ потока данных (Data Flow Analysis) — на движок на базе Clangd. Это сделано в основном для улучшения производительности. Но, как часто бывает, при рефакторинге было найдено много проблем и неаккуратностей. Так что мы в релизе 2020.2 продолжили улучшать этот анализ и исправлять баги в нем:
- Заметнее всего, наверное, был улучшен анализ на неиспользуемый код.
- На DFA также переехали такие вещи как Simplify code и Loop condition is never updated. Для первого в настройках теперь можно настраивать отдельно разные случаи, которые он умеет находить:
К тому же, он теперь более аккуратно работает в случае макросов и шаблонов:Второй же анализ позволяет находить потенциально бесконечные циклы из-за того, что условие цикла не обновляется внутри цикла. Знатоки могли бы заметить, что аналогичный анализ есть и в Clang-Tidy (clang-tidy: bugprone-infinite-loop), но там он не работает для циклов с точками выхода и зачастую ложно-срабатывает для лямбд и референсов. В CLion анализ работает в данных случаях аккуратно:
- В CLion появился анализ на висячие указатели (dangling pointers)! Несмотря на некоторые ограничения (например, он работает только в локальном скоупе), он все равно очень полезен:
- Для кода, использующего Concepts из C++20, появился анализ и квик-фикс на добавление концепта к объявлению переменной типа
auto
, в которую присваивают результат выдачи ограниченной концептом функции:
Окно результатов статического анализа
В этом релизе всеми любимый инспектор Гектор (которого некоторые наши пользователи даже тщетно пытались рассмешить) превратился в новый Inspection Widget, расположенный в правом верхнем углу области редактора. Теперь именно там находятся опции настройки уровня подсветки (от показа всех проблем до полного отключения анализатора кода), а при клике открывается окно результатов статического анализа для данного файла:
Юнит-тестирование
Уже упомянутое здесь не раз исследование показывает, что 34% разработчиков на С++ не пишет никаких юнит-тестов. Хочется верить, что взамен они ведут тестирование какими-то другими способами. Отчасти, проблема в том, что в C++ нет ни стандартной проектной модели, ни стандартного менеджера зависимостей, а значит добавить фреймворк для юнит-тестирования в свой проект ох как не просто. Но сейчас становятся особо популярны так называемые header-only фреймворки, которые подключить в свой проект легко — добавил заголовочный файл и пиши себе тесты. А мы со своей стороны в IDE стараемся поддержать как можно больше опций. В этом релизе к набору из Google Test, Catch, Boost.Test еще добавили doctest. У нас, кстати, некоторое время назад был гостевой блог пост от его автора, где Viktor рассказывал, в чем преимущества данного фреймворка.
Поддержка в CLion включает обычные вещи:
- Автоматическое определение тестов.
- Автоматическое создание конфигураций для запуска и отладки тестов.
- Вывод результатов теста в специальное встроенное окно с разнообразными возможностями фильтрации и упорядочивания, а также с переходом к исходному коду теста в один клик.
- Иконки в редакторе, в левой полосе, для запуска тестов и идентификации статуса последнего запуска тестов.
Поддержка Google Test и Catch2 также обновилась:
- Для Catch2 появилась поддержка шаблонных тестов.
- А для Google Test поддержка макроса
GTEST_SKIP()
, который может быть очень полезен, если хочется уметь пропускать какие-то тесты, например в специфических окружениях.
Небольшое обзорное видео про улучшения в поддержке юнит тестирования от нашего адвоката (кстати, автора фреймворка Catch/Catch2):
Предупреждая ваши вопросы про CTest: сделать его чуть сложнее, потому что это не «очередной» фреймворк, а некоторый уровень абстракции для запуска чего угодно в виде теста. Но мы планируем некоторую интеграцию уже в 2020.3!
А также
Самое интересно, пожалуй, обсудили, теперь коротко обо всем остальном. Надо было с этого начать, но CLion 2020.2 включает множество небольших, но важных улучшений производительности редактора и исправлений подвисаний редактора. Одно из таких улучшений, например, это вставка обратного слэша при нажатии Enter
внутри определения макроса. Казалось бы, как это помогает производительности редактора? Дело в том, что скорее всего новая строка — это часть определения текущего макроса, а вставка обратного слэша позволяет избежать ненужного репарсинга кучи кода, а значит и тормозов редактора.
Помимо этого:
- Для разработчиков встроенных систем добавилось несколько важных интеграционных изменений в плагине для PlatformIO — генерация большего количества конфигураций запуска и отладки, подсветка в конфигурационных
platformio.ini
файлах и создание необходимых проекту профилей CMake автоматически. - Как обычно, из платформы IntelliJ приехало много улучшений в поддержке систем контроля версий. Из значимого: расширенные возможности по работе с GitHub Pull Requests и поддержка Git на WSL2 (то есть при работе с проектами на WSL2, CLion умеет теперь использовать Git оттуда).
- По отладчикам в 2020.2 удалось сделать меньше, чем планировали. В основном, все большие задачи отодвинуты на 2020.3 (отладка от имени root-пользователя, отладка core-дампов). Но в этой версии мы проапгрейдили забандленную версию GDB до 9.2, а также обновили GDB STL pretty printers. Множество улучшений, как функциональных, так и по производительности и стабильности, было сделано в нашем отладчике на базе LLDB для тулчейна Microsoft Visual C++.
На этом на сегодня все. Дочитали до конца? Спасибо вам огромное за внимание! Пробуйте, пишите вопросы, предложения, восклицания в комментариях — мы всегда с радостью их читаем и отвечаем!
Команда CLion
The Drive to Develop