Предыстория
CLion — это среда для разработки на С/С++, близкий родственник IntelliJ IDEA и, соответственно, Android Studio.
Я представляю вниманию сообщества перевод моего блог поста, в котором по шагам описано, как использовать эту IDE для написания прошивок микроконтроллеров.
Примерно полтора года назад я написал блог-пост по английски, в котором рассказал, как можно использовать JetBrains CLion для программирования микроконтроллеров.
Если кратко, в тот раз я использовал одну из плат серии STM32-Discovery. Набортный программатор был перешит в совместимый с SEGGER JLink. Также был использован генератор кода STM32CubeMX, тулчейн GCC ARM и отладчик SEGGER Ozone. При помощи всего этого удалось поморгать светодиодиком :).
Такой набор инструментов в целом работал, но требовал перешивки программатора, запуска внешнего отладчика (зачем он нам, если есть замечательный CLion?), кроме того, SEGGER накладывает довольно жесткие лицензионные ограничения на такие перепрошитые программаторы.
Естественно, все эти проблемы меня не радовали, и я пытался найти решение получше. К счастью, прогресс не стоит на месте, и за прошедшее время и CLion, и CubeMX были существенно улучшены, и самое главное, CLion теперь поддерживает Remote GDB. Теперь стало реально использовать OpenOCD (Open On-Chip-Debugger) как ПО для заливки и отладки прошивок микроконтроллеров. Таким образом можно избавиться от ограничений лицензии SEGGER в пользу инструментов с открытым исходным кодом. Более не требуются никакие перепрошивки программаторов, демо-платы можно использовать прямо так, даже для прошивки целевых устройств (см. документацию на платы ST Nucleo или Discovery).
Мне удавалось запустить это все на ванильном CLion, но настройка проектов была настолько сложной, что я в конце концов пришел к мысли написать свой собственный плагин, который позволит увязать друг с другом все инструменты сразу. И вот, я довел плагин до бета-версии, опубликовал в репозитории JetBrains, и готов показать, как это все это функционирует. Для примера мы сделаем небольшой демо проект (сюрприз! Мы будем мигать светодиодами!), используя одну из самых популярных плат от ST Microelectronics – STM32F4-Discovery. Тот же самый пример, с небольшими изменениями, может быть запущен на любой плате из серий STM32 Nucleo, Discovery или EVAL, поскольку светодиоды есть на каждой из них.
Инструментарий
CLion
Прежде всего, нам нужна, собственно, IDE. CLion доступен для загрузки на сайте JetBrains. Просто запустите инсталлятор и следуйте инструкциям. Вам понадобится лицензия, но месячного триала должно хватить на первое время. Инструкция по установке тут.
Плагин
Откройте настройки CLion, вкладку Plugins, нажмите Browse Repositories… и найдите плагин по ключевому слову openocd. Далее Install и рестарт CLion.

Теперь в CLion появился еще один Run Configuration, два дополнительных пункта в меню Tools еще одна вкладка в настройках.
Тулчейн
Тулчейн (toolchain) – это кросс-платформенный набор инструментов для сборки программ и прошивок. Кросс-платформенный – это значит, что компиляция происходит на PC или Mac, а результат сборки будет работать только на целевом устройстве. В нашем случае это ARM-совместимый МК.
Существует несколько разных тулчейнов, таких как свободные и поддерживаемые CLion’ом Clang или GCC, а так же несколько коммерческих (Keil, IAR, Raisonance, etc). Я использую GCC, скачанный из официального источника – https://developer.arm.com/open-source/gnu-toolchain/gnu-rm. Обратите внимание, после установки тулчейн должен включен в system path. Проверить это можно, запустив arm-none-eabi-gcc из командной строки.
OpenOCD
OpenOCD – это отладчик, поддерживающий аппаратную отладку различных МК с помощью одного из множества поддерживаемых программаторов. Также он может прошивать FPGA и flash-память. Таким образом, потенциально можно работать с огромным количеством разных чипов, не ограничиваясь продукцией ST.
Из всех возможностей OpenOCD плагин использует три:
- поддержка прошивальщика ST-Link/V2
- Поддержку МК с ядром ARM Cortex M
- Поддержку протокола Remote GDB
OpenOCD официально распространяется в виде исходников, но существуют также полуофициальные сборки под все популярные платформы. Более подробно смотрите тут: http://openocd.org/getting-openocd/. Под Windows еще нужен драйвер для ST-LINK/V2. Драйвер обычно идет в сборке OpenOCD для Windows, но можно его скачать и напрямую, с сайта ST, вместе с весьма удобной утилитой для прошивки МК, вот отсюда: http://www.st.com/en/development-tools/stsw-link004.html.
STM32CubeMX
STM32CubeMX – это бесплатный генератор кода для любых МК STM32. В нем можно настроить конфигурацию выводов, периферийных устройств, тактирование ЦПУ и так далее. Все это происходит в весьма удобном визуальном редакторе. После этого Cube создает костяк исходного кода, то есть все необходимые .c и .h файлы, а также файлы проекта для одной из поддерживаемых IDE (в число которых CLion, увы, не входит). Cube состоит из собственно редактора-генератора и подгружаемых т.н. «Firmware Packages», по одному на каждое семейство МК. Сам генератор доступен для загрузки здесь.
Приступим
Одна из самых популярных плат для STмовских МК – STM32F4-Discovery. Ее и возьмем для нашего примера. На борту довольно мощный (хотя и не топовый) МК – STM32F407, прошиватель, совместимый с ST-LINK/V2, и 4 управляемых светодиода. Там еще микрофон, звуковой выход, акселерометр, USB, но в этой статье мы не будем углубляться в них – займемся только светодиодами. Если у вас уже есть какая-нибудь другая плата из серий STM32 Discovery, Eval или Nucleo, то это не беда, вы можете сделать все тоже самое на любой из них, т.к. там есть как минимум один светодиод.
Настройка платы
После установки всех инструментов давайте, наконец, напишем «улучшенную мигалку» для нашей STM32F4-Discovery. Перво-наперво, запускаем CubeMX. При старте он загружает список доступных МК и плат из сети, и после этого можно выбрать любой из МК. Естественно, мы больше заинтересованы в платах. Переходим в “Board Selector”, находим и дважды кликаем STM32F4DISCOVERY.

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

Поскольку мы начали не с «голого» МК, а с платы, то кое-что уже сделано для нас. В частности, настроены нужные нам GPIO для светодиодов, им даже присвоены имена LD3. LD6. Нам только требуется донастроить сам проект и сгенерировать код. Нужно выбрать папку проектов, имя собственно проекта и задать SW4STM32 в качестве Toolchain/IDE.

Теперь нужно закрыть настройки и нажать Generate Code, т.е. кнопку с шестеренкой. Когда генерация кода закончена, просто закройте финальный диалог (т.е. не надо трогать кнопку «Open Project»).

Наконец мы можем открыть полученный год с помощью CLion. Выберите File -> Import из главного меню или Import Project from Sources из Welcome screen. В процессе импорта CLIon может показывать диалоги подтверждения или показывать ошибки – просто игнорируйте это. Когда проект будет, наконец, импортирован, следует выбрать в меню Tools->Update CMake project with STM32CubeMX project.
В этот момент плагин перепишет CMakeLists.txt полностью, и, таким образом, подключит тулчейн и все необходимые скрипты. Теперь CLion сможет скомпилировать и собрать проект. Кроме того, плагин настраивает новую Run Configuration для заливки и отладки скомпилированного проекта.
Настройка параметров плагина.
Снова откройте настройки CLion, на этот раз вкладку OpenOCD Support в группе Build, Execution, Deployment.

Там необходимо указать папку, где находится OpenOCD и файл конфигурации для платы. Плагин пытается найти OpenOCD в system path сам, но иногда нужно явно прописать точное местонахождение. В большинстве случаев настройки портов и путь к GDB вам менять не надо, однако пользователям Mac все-таки нужен другой gdb. Например, можно взять arm-none-eabi-gdb из тулчейна.
Самое последнее, что нужно сделать – выбрать файл конфигурации платы (Board Config File) с помощью соответствующего диалога. Эти файлы находятся в подпапке boards инсталляции OpenOCD. Для данного проекта наилучшим выбором является, очевидно, stm32f4discovery.cfg.
А теперь добавим кода
Вот теперь мы все необходимые настройки сделаны, можно писать код. Открываем main.c, находим бесконечный цикл while и добавляем туда несколько строк, см. строки 106-111:

Эти строки зажигают случайную комбинацию светодиодов каждые 300 мсек.
Также можно добавить несколько директив #pragma (строки 100, 101 и 113) чтобы избавиться от предупреждений CLion – бесконечные циклы не используются в «нормальных» программах на C и, поэтому, они не нравятся нашей IDE.
Ключ на старт!
Настал момент поставить breakpoint где-нибудь внутри тела main() и запустить это все! CLion соберет проект, загрузит в нашу плату, запустит отладчик и сбросит МК. Теперь можно пользоваться breakpoints и watches для отладки.
Лучше один раз увидеть, чем три раза прочесть:
Что дальше?
Если уважаемому читателю удалось проделать все вышеописанное, то простенький пример прошивки работает. Но как писать код далее? Окей, вот несколько советов в форме вопрос-ответ.
Q: Какие платы поддерживаются?
A: Более-менее любые демо платы STMicroelectronics серий STM32 Discovery, Nucleo или EVAL должны работать.
Q: Что делать, если мне надо поменять аппаратную конфигурацию МК?
A: Запустите STM32CubeMX снова и откройте ваш проект, сделайте необходимые изменения и перегрерируйте код. Плагин в IDE спросит, не надо ли обновить проект. Просто ответьте «Yes».
Q: Как я могу защитить написанный мной код от перезаписи в момент генерации?
A: Всегда пишите свой код между псевдокомментариями
/* USER CODE BEGIN . */ и /* USER CODE END . */ .
Cube не трогает эти фрагменты при генерации кода. Не забывайте переносить автоматически добавляемые директивы #include в такие места. Альтернативный подход для больших кусков кода – отдельные файлы .c/.h.
Q: Мне нужно добавить внешнюю библиотеку, подключить FPU, сделать еще какие-то изменения в CMakeLists.txt. Но как?
A: CMakeLists.txt автоматически перезаписывается плагином из шаблона, напрямую там лучше ничего не менять. Сам шаблон автоматически записывается среди файлов проекта, следует сделать изменения там, после чего обновить проект, используя пункт меню Tools->Update CMake project with STM32CubeMX.
Q: Я хочу использовать CLion для моих разработок на базе ARM, но не на STM32. Могу я использовать этот плагин?
A: Скорее всего, да. Надо установить все те же инструменты (кроме STM32CubeMX), а затем написать свой собственный CMakeLists.txt (вот шаблон), скрипт для линкера и файл конфигурации платы. Когда все готово, выберите Tools -> CMake -> Reset Cache and Reload Project и создайте свою Run Configuration типа OpenOCD Download & Run. Один из пользователей плагина все это проделал для Atmel SAM E70.
Q: Я хочу использовать CLion и плагин для моих разработок, но не для ARM. Это возможно?
A: Ну, если ваш МК поддерживается GCC, прошиватель совместим с OpenOCD, то как минимум можно попробовать. Возьмите подходящий тулчейн и см. предыдущий ответ.
Q: Я не могу подобрать подходящий файл конфигурации платы. Я могу использовать несколько отдельных файлов конфигурации?
A: Можно написать свой файл конфигурации платы, скомбинировав их. Положите его в свой проект, а за образец возьмите один из стандартных.
Q: А мне нравится! Могу я как-нибудь поддержать проект или поучаствовать в нем?
A: Конечно!
Ссылки
- Сам пример https://github.com/elmot/f4-blog
- CLion
- Страничка плагина, исходный код и багтрекер, документация
- OpenOCD
- Toolchain
- STM32CubeMX
Кросс компиляция пакета для роутера на примере Qbittorrent

Добрый день друзья. Как-то мне захотелось установить Qbittorrent на мой роутер который оснащен OpenWRT. Конечно создатели OpenWRT уже предусмотрели возможность сборки кастомных пакетов об этом можно почитать вот тут: https://habr.com/ru/company/ruvds/blog/530984/ . Но данный способ очень долгий, приходится скачивать исходники OpenWRT, компилировать тулчейн и прочее. И я подумал, а почему-бы просто не скачать тулчейн и собрать проект обычным образом. Под катом мой опыт.
Тулчейны что это такое
Итак, для людей которые недавно познакомились с Linux (как впрочем и я) поясняю тулчейн это набор пакетов необходимый для сборки приложения. В него входят компилятор, линкер и т. д, программой которая вызывает всю цепочку пакетов называется gcc. Для Linux существует множество тулчейнов которые позволяют собирать программы как под другие операционные системы (Windows и т. д) так и под другие платформы (Arm и т. д). Например тулчейн для Windows называется MinGW. При помощи него можно компилировать программы для Windows прямо из под Linux звучит как магия.
Подготовка
Что нам нужно? Нам нужен Linux все опыты проводились в Linux Mint. На него нужно установить следующие пакеты:
sudo apt update sudo apt install build-essential curl pkg-config automake libtool \ git perl python3 python3-dev python3-numpy \ unzip cmake ninja
Также нам нужен тулчейн. Какие бывают тулчейны? Ну во первых они отличаются архитектурой под которую они собирают пакеты. Также они могут иметь разные стандартные библиотеки языка C. Наиболее распространённая библиотека это glibc, но нам она не подойдет, поскольку OpenWRT использует библиотеку musl. Поэтому заходим по ссылке https://musl.cc/#binaries и качаем нужный тулчейн. Поскольку мой роутер использует процессор с архитектурой aarch64, то я выберу aarch64-linux-musl-cross и скачаю его. Распаковываем его в папку, путь к которой далее я буду называть crosshost_dir для краткости.
Также нам необходимы исходники не только Qbittorrent, но и исходники всех библиотек которые используются в Qbittorrent.
- zlib https://github.com/madler/zlib
- openssl https://github.com/openssl/openssl Нужна версия с l (OpenSSL_1_1_1l)
- boost https://boostorg.jfrog.io/ui/native/main/release/1.77.0/source
- libtorrent https://github.com/arvidn/libtorrent Версию 2 поддерживает только qbittorrent 4.4
- qt-everywhere https://download.qt.io/archive/qt/5.15/5.15.2/single/
- qbittorrent https://github.com/qbittorrent/qBittorrent
Также нужно создать папку в которой мы будем работать и распаковать в неё все эти архивы. Эту папку я далее буду называть Install_dir. В ней нужно создать папку Build в которую будут складываться результаты наших трудов.
Теория
Во первых хочется предупредить об одной вещи. Если внутри параметра который вы передаёте в консоль присутствует пробел, то этот параметр обязательно должен быть помещен в кавычки. Иначе система посчитает что вы передаете ей два параметра.
Существует два типа связывания библиотек это статический и динамический. При статическом связывании код библиотеки помещается внутрь программы. При динамическом линкер создаст специальный раздел программы называемый таблицей импорта. При старте программы, загрузчик читает эту таблицу импорта и подгружает библиотеки из внешних файлов которые имеют расширение .so .
К сожалению если мы применим динамическое связывание наша программа не запустится. Система будет жаловаться на неопределённые символы. Поэтому мы применим статическое. Одним из плюсов данного подхода будет то, что у нас будет самая актуальная версия библиотек. А это очень важно например в случае с Libtorrent эта библиотека очень быстро обновляется и сильно влияет на работу Qbittorrent. Но отрицательной стороной данного подхода является сильно разросшийся размер программы. Например у меня получился Qbittorrent размером 22 МБ . Кажется это немного, но нужно помнить что ещё недавно у роутеров было 4 МБ флэш памяти и 4 МБ оперативной памяти.
Сборка любого проекта состоит из 3-х этапов
- Конфигурирование
- Сборка
- Инсталляция пакета. То есть перенос его в нужную директорию.
В Linux существует две системы сборки проектов это Autotools и Сmake. Autotools это устаревшая система но некоторые проекты до сих пор используют её. Поэтому мы будем использовать и ту и другую.
Сборка
Перед началом сборки нужно добавить несколько переменных окружения которые скажут системе где расположен наш проект и наш тулчейн, а также под какую платформу мы будем компилировать. Для тех кто не знает, все значения переменных окружения хранятся лишь до тех пор пока вы не закрыли терминал. То есть закрыли открыли терминал вводите переменные заново.
PATH=crosshost_dir/bin:$PATH PATH=Install_dir/Build/bin:$PATH CHOST=aarch64-linux-musl CC=aarch64-linux-musl-gcc AR=aarch64-linux-musl-ar CXX=aarch64-linux-musl-g++ PKG_CONFIG_PATH="Install_dir/Build/lib/pkgconfig" LD_LIBRARY_PATH=-L"Install_dir/Build/lib" BOOST_ROOT="Install_dir/Build/boost" BOOST_INCLUDEDIR="Install_dir/Build/boost" BOOST_BUILD_PATH="Install_dir/Build/boost"
aarch64-linux-musl надо заменить на тот тулчейн который вы скачали.
Zlib
./configure --prefix=Install_dir/Build --static make -j8 CC=aarch64-linux-musl-gcc AR=aarch64-linux-musl-ar \ CXX=aarch64-linux-musl-g++ \ CXXFLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" \ CPPFLAGS="-static -w -s -IInstall_dir/Build/include" \ LDFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread" make install
После -j нужно поставить количество ядер вашего процессора у меня их 8. Zlib упорно не хотел воспринимать переменные среды поэтому пришлось передать их вместе с командой make.
OpenSSl
./Configure "linux-aarch64" --prefix=Install_dir/Build \ --openssldir="/etc/ssl" threads no-shared no-dso no-comp make -j8 CC=aarch64-linux-musl-gcc AR=aarch64-linux-musl-ar \ CXX=aarch64-linux-musl-g++ \ CXXFLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" \ CPPFLAGS="-static -w -s -IInstall_dir/Build/include" \ LDFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread" make install_sw
Тут все похоже на прошлый.
Boost
Boost устанавливать не надо. Нужно просто переместить его в папку Install_dir/Build. И переименовать его папку просто в boost. А проекты которые от него зависят сами возьмут из этой папки что им надо.
Libtorrent
mkdir -p Install_dir/Build/graphs/libtorrent-rasterbar patch -p1 < patch-libtorrent cmake -Wno-dev -Wno-deprecated \ --graphviz=Install_dir/Build/graphs/libtorrent-rasterbar/dep-graph.dot \ -G Ninja -B build -DCMAKE_CXX_COMPILER=aarch64-linux-musl-g++ \ -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_PREFIX_PATH="Install_dir/Build;Install_dir/Build/boost" \ -DBoost_NO_BOOST_CMAKE=TRUE \ -DCMAKE_CXX_FLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" \ -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="Install_dir/Build" cmake --build build cmake --install build
Для того чтобы собрать Libtorrent нужно применить патч . Здесь уже используется cmake.
Qt
Надо отметить что Qbittorrent до сих пор не поддерживает Qt 6-й версии поэтому нужно брать пятую. Перед сборкой нужно зайти в файл qt-everywhere_dir/qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf и заменить aarch64-linux-gnu на aarch64-linux-musl или на вашу архитектуру если у вас другой тулчейн.
./configure -xplatform "linux-aarch64-gnu-g++" -prefix "Install_dir/Build" \ -no-icu -no-iconv -opensource -confirm-license -release -static -c++std "c++17" \ -qt-pcre -no-feature-glib -no-feature-opengl -no-feature-dbus -no-feature-gui \ -no-feature-widgets -no-feature-testlib -no-compile-examples -nomake examples \ -nomake tests -no-opengl -skip 3d -skip activeqt -skip androidextras \ -skip datavis3d -skip doc -skip macextras -skip quick3d -skip quickcontrols \ -skip quicktimeline -skip translations -skip wayland -skip webengine \ -skip webglplugin -skip winextras -skip x11extras -I"Install_dir/Build/include" \ -L"Install_dir/Build/lib" \ QMAKE_LFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread" make -j8 make install
Qbittorrent
mkdir -p Install_dir/Build/graphs/qBittorrent-release-4.4.0beta3 cmake -Wno-dev -Wno-deprecated \ --graphviz="Install_dir/Build/graphs/qBittorrent-release-4.4.0beta3/dep-graph.dot" \ -G Ninja -B build -DCMAKE_CXX_COMPILER="aarch64-linux-musl-g++" \ -DCMAKE_BUILD_TYPE="release" -DCMAKE_CXX_STANDARD="17" \ -DCMAKE_PREFIX_PATH="Install_dir/Build;Install_dir/Build/boost" \ -DBoost_NO_BOOST_CMAKE=TRUE \ -DCMAKE_CXX_FLAGS="-std=c++17 -static -w -s -I"Install_dir/Build/include"" \ -DSTACKTRACE=OFF -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DGUI=OFF \ -DCMAKE_INSTALL_PREFIX="Install_dir/Build" cmake --build build cmake --install build
Настройка и запуск Qbittorrent
Первым делом нужно переместить файл qbittorrent-nox в директорию \usr\bin вашего роутера. Теперь можно попробовать его запустить с опцией -d чтобы он запустился в режиме демона, иначе он выключится как только вы закроете окно putty. Но во первых делать это каждый раз неудобно да и qbittorrent запускается с правами root а это небезопасно. Поэтому сначала добавляем пользователя qbittorrent:
echo qbittorrent:x:227:227:qbittorrent:/home/qbittorrent:/bin/false >> /etc/passwd echo qbittorrent:x:227:qbittorrent >> /etc/group echo qbittorrent:x:0:0:99999:7. >> /etc/shadow
После этого создаете файл /etc/init.d/qbittorrent
#! /bin/sh /etc/rc.common USE_PROCD=1 START=98 STOP=01 DAEMON="/usr/bin/qbittorrent-nox" USER="qbittorrent" GROUP="qbittorrent" home_dir="/home/qbittorrent" start_service() < [ -d "$home_dir" ] || < mkdir -p "$home_dir" chmod 0755 "$home_dir" chown "$USER:$GROUP" "$home_dir" >procd_open_instance procd_set_param command "$DAEMON" procd_set_param user $USER procd_set_param group $GROUP procd_set_param env HOME="$home_dir" procd_close_instance >
И разрешаете выполнение:
chmod 755 /etc/init.d/qbittorrent
Теперь qbittorrent'ом можно управлять как и другими демонами из веб интерфейса.
Сколько стоит компилятор?
Компилирующий тулчейн является одним из самых больших и самых сложных компонентов любой системы, и, как правило, основан на опенсорсном коде, либо GCC, либо LLVM. На Linux-системе, только ядро операционной системы и браузер имеют больше строк кода. Для коммерческих систем, компилятор должен быть абсолютно надёжным, каким бы ни был исходный код, он должен генерировать надёжный, высокопроизводительный бинарный код.
Сколько стоит такой большой, сложный и важный компонент системы? Благодаря опенсорсу, не так много, как вы можете подумать. В этом посте, я приведу реальный пример, который показывает нам, что построение нового коммерческого компилирующего тулчейна возможно без огромных затрат.
Сколько нужно кода?
Анализ, проделанный с помощью (SLOCCount, автор David A Wheeler) показывает, что GCC содержит больше 5 миллионов строк. LLVM меньше, всего 1.6миллионов строк, но он более молодой, поддерживает по умолчанию только C и C++ и имеет в три раза меньше целевых архитектур. Однако полезный тулчейен имеет больше компонентов.
- Отладчик: либо GDB (800К строк), либо LLDB (600К строк)
- Линкер: GNU ld (160К строк), gold (140К строк), либо lld (60К строк)
- Ассемблер/дизассемблер: GNU gas (850К строк), либо ассемблер LLVM
- Binary utilities: GNU (90К строк) и/или LLVM (включено в исходники LLVM)
- Emulation library: libgcc (входит в исходники GCC) или CompilerRT (340К строк)
- Стандартная библиотека C: newlib (850К строк), glibc (1.2M строк), musl (82К строк) или uClibC-ng (251К строк)
Что нужно для портирования компилятора?
Нам нужно портировать тулчейн для коммерческого применения. Многие аспиранты по всему миру портируют компиляторы в ходе своих исследований, но их усилия сосредоточены в одной узкой области данного исследования. В результате компилятор портируется быстро, но он не является ни полным, ни надёжным, так как это не было целью исследовательской программы.
Эта статья посвящена созданию набора инструментальных средств, который надёжно генерирует корректные и эффективные бинарники для любого исходного кода, и предназначен для коммерческого и индустриального применения.
К счастью, большая часть огромной кодовой базы является обобщённой. При разработке всех основных компиляторов были приложены значительные усилия для хорошего отделения кода, зависящего от целевой платформы, и портирование компиляторного тулчейна на новую архитектуру является посильной задачей. Эта задача включает в себя пять стадий.
1. Прототипирование
Вначале создаётся порт, содержащий все компоненты. Создание прототипа важно для того, чтобы выявить наиболее проблемные места при полном портировании, и должно занять несколько месяцев. По окончании этой стадии мы должны уметь компилировать программы, демонстрирующие, что все компоненты работают вместе, как ожидается.
2. Реализация полной функциональности
Завершение всех функций компилятора и других инструментов. Атрибуты, встроенные/intrinsic — функции, а также эмуляция недостающей функциональности должны быть завершены. Должен работать линкер, написан BSP, и, при необходимости, добавлены кастомные опции. В конце этого процесса пользователь получает полнофункциональный тулчейн. Самое важное, полный набор регрессионных тестов должен проходить.
3. Тестирование.
Самая большая часть проекта. Тестирование должно покрывать три области:
— регрессионное тестирование, показывающее, что тулчейн не сломан и может работать для разных архитектур.
-Аттестационное тестирование (compliance testing), часто используются тесты заказчика, показывающие, что вся требуемая функциональность присутствует.
-бенчмарки, показывающие, что сгенерированный тулчейном код удовлетворяет критериям требуемой скорости выполнения кода, размера кода и энергоэффективности.
4. Развёртывание
На этой стадии вам нужно помочь пользователям изучить новый компилятор и то, насколько он отличается от предыдущих инструментов, и обычно для этого нужны руководства в письменной форме и на видео. Будут обнаруживаться новые баги, и также будет много сообщений о багах, вызванных различиями между старым и новым компилятором. Так бывает, когда LLVM и GCC заменяют старые проприетарные компиляторы, в связи с тем, что они гораздо более развиты в плане функциональности. Если пользовательская база велика, фаза развёртывания становится очень существенной.
5. Сопровождение
LLVM и GCC очень активно развиваются, и новая функциональность добавляется постоянно, как для поддержки новых языковых стандартов во фронтенд, так и для добавления новых оптимизаций в бэкенд. Вы должны поддерживать свой компилятор в актуальном состоянии при всех этих изменениях. Плюс к этому, конечно, у вас будет новая функциональность, специфичная для целевой архитектуры, и багрепорты от пользователей.
Сколько нужно усилий в общем случае
Рассмотрим общий случай. Новая архитектура с большой пользовательской базой, должна поддерживать C и C++, и для bare metal, и для Linux. В этом случае, вероятно, архитектура поддерживает различные реализации, от маленьких процессоров, используемых для bare metal приложений или RTOS во встраиваемых системах, до больших процессоров, способных выполнять полноценное Linux-окружение.
Полный релиз такого тулчейна занимает 1-3 человеко-года. Начальная версия тулчейна (proof of concept) должна быть реализована в течение 3-х месяцев. Реализация всей функциональности должна занять 6-9 месяцев, и ещё 3 месяца, если требуется поддержка bare metal и Linux.
Тестирование занимает как минимум 6 месяцев, но с большим количеством специфических тестов может занять до 12 месяцев. Начальное развёртывание занимает 3 месяца, но с большой пользовательской базой, может занять на 9 месяцев больше.
Усилия по поддержке сильно зависят от количества репортов от пользователей и количества новых функций. Эти усилия могут отнимать от 0,5 человеко-месяца в месяц до, что более вероятно, 1 человеко-месяца в месяц.
Важно отметить, что над проектом должна работать целая команда инженеров: специалист по компиляторам, специалист по отладке, инженер по реализации библиотеки и т.д. Разработка компиляторов является одной из наиболее сложных дисциплин, и ни один инженер не может иметь опыт сразу во всех областях.
Сколько нужно усилий в простейшем случае
Не всегда нужен компилятор, который будет использоваться большим количеством пользователей. Существуют различные специфичные процессоры, особенно DSP, которые разработаны в маленьких компаниях, состоящих из одного инженера. Там, где такие процессоры доказали свою коммерческую успешность, они начинают развиваться, и вместо крошечного ядра, программируемого на ассемблере инженером-одиночкой, становятся гораздо более мощными процессорами с большой командой программистов на ассемблере. В этом случае переход на компиляцию языка С будет означать огромный прирост продуктивности и снижение стоимости разработки.
Для таких случаев, тулчейн должен поддерживать С, без С++, и минимально необходимую библиотеку С. Также архитектура может иметь уже готовый ассемблер и линковщик, который можно использовать. Это сильно уменьшает усилия, до одного человеко-года для создания полностью работающего компилятора.
Стадия proof-of-concept по-прежнему занимает 3 месяца, но затем доводится до полнофункциональной версии ещё за 3 месяца. Тестирование по-прежнему занимает больше всего усилий, и продолжается от 3 до 6 месяцев, но при маленькой пользовательской базе 3 месяца более чем достаточно.
Поддержка также необходима, но для маленькой системы с небольшой пользовательской базой будет достаточно 0,25 человеко-месяца в месяц.
Для маленьких заказчиков, может быть важно остановиться после реализации всей функциональности. Если небольшая горстка стандартных программ компилируется, этого может быть достаточно для демонстрации эффективности компилятора, без прохождения полного набора тестов.
Исследование темы
В 2016 году в Embecosm обратилась компания, занимающаяся разработкой микроэлектроники, которая много лет использовала свой собственный DSP c 16-битным адресным пространством, разработнный специально для их узкой области. Они использовали уже третье поколение своего процессора, когда осознали, что тратят слишком большие усилия на программирование на ассемблере. Ситуация усугублялась тем, что стандартные кодеки, которые они использовали, имели референсную реализацию на С. У них был компилятор, но очень старый, и портирование кода на новое поколение DSP было невозможно.
Embecosm был заказан тулчейн на основе LLVM, способный компилировать кодеки LLVM и производить высококачественный код. Предполагалось, что код при необходимости будет дорабатываться вручную. У заказчика был готовый ассеблер и линковщик, который комбинировал все ассемблерные файлы в один, связывал все ссылки, и генерировал бинарный файл, загружаемый в DSP. Заказчик также хотел получить опыт построения компиляторов, поэтому один из инженеров заказчика присоединился к команде Embecosm и занимался поддержкой компилятора, когда проект был закончен.
В первые три месяца мы разработали тулчейн на основе существующего ассемблера и дизассемблера. Для того, чтобы использовать newlib, мы создали псевдолинкер, который извлекает требуемые файлы из newlib в виде ассемблерных исходников, и объединяет их с тестовой программой. Т.к. процессор в кремнии был недоступен, мы проводили тестирование на Verilator-модели чипа. Для этого мы написали gdb-сервер, позволяющий GDB взаимодействовать с моделью. При отсутствии ELF, отладка на уровне исходника невозможна, но GDB способен загрузить программу и получить результат, что достаточно для тестирования.
Это позволило нам скомпилировать тестовую программу и продемонстрировать, что компилирующий тулчейн работает. Стало ясно, что есть два препятствия для достижения полной функциональности: 1) отсутствие поддержки бинарных ELF-файлов и 2) отсутствие поддержки 16-битных char.
На второй фазе мы реализовали GNU-ассемблер/дизассемблер, используя CGEN, на это ушло около 10 дней. Мы также реализовали поддержку 16-битных char в LLVM, как описано в этом посте. С этими двумя вещами завершение полнофункционального тулчейна стало более простым, и мы смогли запускать стандартные LLVM lit и регрессионные тесты GCC для тулчейна, большинство из которых прошли успешно. DSP имеет ряд специальных режимов поддержки арифметики с фиксированной точкой. Для их поддержки мы реализовали специальные встроенные и intrinsic-функции.
На этой стадии у нас получился компилятор, который корректно компилирует код заказчика. Поддержка ELF означает, что возможны такие техники, как link-time optimization (LTO) и garbage collection для секций, что приводит к успешной оптимизации кода, и это соответствует требованиям заказчика при ограниченном объёме памяти. При затратах в 120 человеко-дней, была достигнута цель компиляции С-кода для нового DSP.
Заказчик решил, что на этой стадии функциональность его устраивает, и продолжения работы не требуется. Если они решат, что компилятор будет доступен широкому потребителю, они могут продолжить работу с полным тестированием тулчейна.
Выводы
Два фактора сделали возможным построение полнофункционального компилирующего тулчейна за 120 человеко-дней.
Использование опенсорсного компилятора
Инструменты, использованные в проекте, представляют собой результат общих усилий в тысячи человеко-лет, потраченных компиляторным сообществом на протяжении последних трёх десятилетий. Наши заказчики смогли использовать это преимущество для получения современного тулчейна.
Команда экспертов
Хотя это был проект на 120 дней, над ним работала команда из пяти человек, каждый из которых имеет многолетний опыт. Ни один человек не может знать всё про эмуляцию, GDB, CGEN-ассемблеры, GNU-линкер и компилятор LLVM.
- Open source
- Программирование
- Анализ и проектирование систем
- Компиляторы
CLion 2021.3: новый механизм удаленной разработки, тулчейн для Docker, улучшения отладчика и многое другое
Традиционно начало декабря — время, когда релизятся все продукты JetBrains. И сегодня мы расскажем о CLion 2021.3 — новой версии нашей кроссплатформенной IDE для разработки на C и C++.

Решения для удаленной разработки
Главная новость прошедшей релизной недели — выпуск нового решения для удаленной разработки. Его модель предполагает, что исходный код, тулчейн и бэкенд IDE находятся на удаленном сервере, а для взаимодействия с IDE используется тонкий клиент, запущенный на локальной машине. Таким образом решается несколько проблем:

- Вам не нужно загружать код на локальную машину. Он хранится на удаленном (и, вероятно, защищенном) сервере — вам просто нужно подключиться к нему.
- Локальной машине не обязательно быть мощной, так как бэкенд IDE запускается на удаленной машине.
- Вам не придется тратить время на настройку окружения. Достаточно один раз настроить набор стандартных сред, после чего ваша команда сможет ими пользоваться. В будущем, если среда «прогрета», вам даже не придется даже ждать окончания индексации — просто открывайте локальный клиент, подключайтесь и сразу приступайте к работе.
Именно об этой возможности вы давно нас просили! Ведь старый удаленный режим — при котором CLion запускается на локальной машине, код синхронизируется с удаленной на локальную машину, а компиляция и сборка выполняются удаленно — не всех устраивал. Пока что новое решение имеет ряд ограничений. Рекомендуем вам предварительно ознакомиться с ними.
Другие обновления в CLion 2021.3
Следующие улучшения будут полезны независимо от используемой вами платформы и специфики разработки:
- работа с тулчейнами — оптимизация и новые возможности;
- отладчик — улучшенное представление данных;
- редактор — подсказки для выведенных типов;
- анализ кода — повышение точности и новые возможности;
- новая опция для представления структуры текущего файла.
А теперь разберем все в деталях.
Тулчейны
Мы поддержали новый тип тулчейна для работы с контейнерами Docker. Раньше мы предлагали использовать для этого тулчейн Remote. Но копирование исходного кода в контейнер по ssh давало лишние накладные расходы. Новый тулчейн Docker просто монтирует директорию с проектом к контейнеру. Подробнее об особенностях работы нового тулчейна на Windows и о том, как его настроить на любой из платформ, рассказывает наш новый девелопер-адвокат Тимур Думлер (на английском):
Для пользователей Windows мы подготовили сразу несколько улучшений:

- MinGW теперь включен в поставку CLion, чтобы сэкономить время на предварительную конфигурацию окружения тем, кто только начинает работу в CLion. В настоящее время в CLion встроена версия MinGW-w64 9.0 с параметром languages=c,c++, потоками POSIX и структурированной обработкой исключений (SEH).
- Тулчейн System позволяет настроить исполняемые файлы для CMake, компилятора и отладчика, не указывая заранее настроенное окружение (MinGW, Cygwin, WSL, Visual Studio и пр.). Версия тулчейна для Windows работает аналогично версиям для Linux и macOS.
Также есть несколько важных улучшений для разработчиков встроенных систем. Появилась опция Custom Compiler, позволяющая использовать компиляторы, которые не поддерживаются из коробки. Теперь таким компиляторам не придется «маскироваться» под GCC или Clang. Достаточно прописать компиляторные определения в файле формата *.yaml и указать этот файл в настройках Settings/Preferences | Build, Execution, Deployment | Toolchains | Custom Defined Compiler:

Теперь CLion умеет работать с заданными таким образом компиляторами. Мы создали специальный GitHub-репозиторий, в который будем добавлять конфигурационные файлы для популярных компиляторов. Некоторые из них мы уже добавили:

В некоторых случаях окружение компилятора можно настроить с помощью скрипта. В нем вы сможете инициализировать переменные окружения, настроить переменную PATH и пр. Теперь CLion позволяет указать такой скрипт в настройках тулчейна и исполняет его при первом запуске тулчейна. Кстати, похоже, что таким образом можно научить CLion работать с новым компилятором от Intel на базе LLVM. Мы еще не до конца исследовали этот вопрос, но пока тестирование проходит успешно.
Большинство наших пользователей предпочитает работать над проектами CMake (тогда как CLion также еще поддерживает Makefile, compilation database, и совместим с плагинами для Gradle и Bazel). В качестве генератора CMake большинство пользователей предпочитают Ninja. CLion 2021.3 включает Ninja v1.10.2. Если вы откроете или создадите проект в CLion с CMake v3.20+, то при запуске локальных тулчейнов по умолчанию будет использован именно Ninja. Управлять используемым в CMake генератором теперь можно не только через опции CMake, но и из интерфейса CLion: Settings/Preferences | Build, Execution, Deployment | CMake.

Отладчик
В этом релизе нам удалось улучшить отладчик в двух направлениях. Улучшение, которое касается всех пользователей: мы расширили настройки отображения данных в отладчике. Мы заметили, что шаблонизированные типы стандартной библиотеки и спецификаторы пространств имен (особенно ABI) зачастую перегружают окно отладчика. При этом пользователю, как правило, важнее знать значения переменных. Теперь вы можете настроить отображение типов переменных и функций в окне фреймов, исходя из ваших предпочтений:

Например, можно не отображать в окне отладчика вспомогательные пространства имен, глобальные спецификаторы и спецификаторы для областей доступа отдельных функций, а также пространства имен версии ABI стандартной библиотеки. Можно вообще не отображать типы. Посмотрите, насколько существенным может быть отличие:

В окне фреймов можно убрать тип возвращаемого значения функции, скрыть ее параметры и аргументы шаблона. Также можно и добавлять: например, добавьте имя модуля, чтобы видеть, какой файл выполняется в данный момент времени и какой идентификатор потока передан ОС при запуске:

Новое действие View as Array доступно для всех переменных типа указатель. Оно добавляет представление значение указателя в виде массива в список просматриваемых переменных. Чтобы запустить действие, откройте контекстное меню для переменной и укажите размер массива:
В прошлой версии CLion шестнадцатеричное представление числовых переменных было экспериментальной функцией. В новой версии мы улучшили эту возможность и добавили ее на страницу настроек. Также появилась возможность просмотра параллельных стеков при отладке многопоточных приложений. А встроенный LLDB был обновлен до 13-й версии.
Также мы добавили ряд важных улучшений для разработчиков встроенных систем на базе RTOS. Помимо FreeRTOS, CLion теперь поддерживает Zephyr RTOS. Что касается FreeRTOS, мы поддержали дополнительные таблицы — для просмотра выполняющихся задач, активных очередей, программных таймеров, а также использования кучи и распределения блоков памяти:

Подсказки для выведенных типов
В современном C++ можно не указывать тип явно, а скрыть его ключевым словом auto либо спрятать в структурное связывание или лямбду. Однако при работе с таким кодом разработчику нужно знать тип переменной или возвращаемого значения. Поэтому мы добавили в редактор подсказки для выведенных типов. CLion показывает актуальный тип прямо в редакторе:

Анализ кода
Мы обновили инструменты LLVM до версии 14.0.0. Это касается как кастомизированного нами языкового движка Clangd, так и инструментов Clang-Tidy и ClangFormat. Благодаря этому языковые функции работают точнее, а демон Clangd — реже падает. Также в анализаторе Clang-Tidy появились новые проверки — сразу после обновления версии CLion спросит вас, какие из них вам нужны.
В прошлых релизах мы перевели анализ потока данных (DFA) на Clangd и реализовали его в глобальном контексте (то есть не просто в теле функции, а в рамках единицы трансляции). В новом релизе разные вызовы функций рассматриваются по-разному: параметры и возвращаемые значения для разных точек вызова анализируются отдельно. Это уменьшило количество ложных срабатываний анализатора и повысило точность его работы. Вот типичный пример с поиском подвисшего указателя (dangling pointer):

К слову, мы улучшили анализ времени жизни объекта (реализован в CLion через DFA на основе предложения Герба Саттера Lifetime Safety), и теперь он отлавливает больше проблемных случаев.
Мы продолжаем работу по поддержке MISRA C 2012 и MISRA C++ 2008 в CLion. В этом релизе добавилось много новых проверок. Полный список доступен по ссылке. В следующем году планируем, вероятно, добраться и до спецификации AUTOSAR.
Структура текущего файла
В новой версии CLion квалифицированные имена функций-членов отображаются полностью. Благодаря этому при анализе структуры файла в окне Structure вы сможете легко различать функции с одинаковыми именами. Настроить отображение можно с помощью специальной настройки в верхней панели:
Мы планируем доработать эту функциональность в следующей версии, а также добавить возможность группировки членов классов в окне Structure.
В качестве эпилога
На этом у нас все. Если вы дочитали до конца, напишите в комментариях ваше любимое сочетание клавиш в CLion 🙂 (Я так пишу каждый релиз, но пока никто не поделился с нами в комментариях любимым сочетанием… Кто же станет первым?)
Новую версию можно скачать на нашем сайте и попробовать бесплатно в течение 30 дней. Если у вас есть активная подписка на CLion или All Products Pack, просто обновите версию до 2021.3. Напоминаем, что при покупке годовой подписки на любой продукт JetBrains вы получите резервную бессрочную лицензию.
Оставляйте ваши вопросы, мысли и предложения в комментариях — нам интересно, что вы думаете, и мы всегда рады помочь!
Ваша команда CLion
The Drive to Develop
Оригинал статьи опубликован на Habr.com.
