Добрый день, уважаемые читатели!
В этой статье обсудим, каким образом можно добавлять к вашему проекту, созданному в VSCode + PlatformIO, какие-либо “внешние” (и не только) библиотеки. Причем в контексте данной статьи не так уж и важно – для какого микроконтроллера и на какой платформе вы создаете свой код – принципы работы менеджера библиотек PlatformIO одинаковы. Я буду приводить примеры для ESP32 и платформы ESP-IDF, но то же самое можно производить и для платформы Arduino, и для других микроконтроллеров. Одно ограничение – все нижесказанное относится к языку Си / С++ в применении к программированию микроконтроллеров.
Предупреждения
- Я работаю в ОС Windows, поэтому все пути и “слеши” записаны применительно к этой операционной системе – C:\dir\subdir1\subdir2\… Если вы используете любую ОС семейства Linux – учитывайте особенности вашей ОС, в них я не “специалист”.
- Статья является художественным пересказом справочной системы PlatformIO, посвященной менеджеру библиотек и системе поиска зависимостей. Разумеется, в данной статье содержится только малая толика информации, но я постарался донести её до вас в более понятной форме. Все ссылки в тесте статьи ведут на соответствующие разделы справочной системы PlatformIO. Рекомендую вам кроме моего текста, ознакомиться с оригиналами – кроме того, там нет рекламы. Со временем, возможно, ссылки могут устареть и перестать работать. Да и я могу чего-нибудь напутать.
- Эта статья рассчитана на начинающих и в ней я не буду рассматривать управление библиотеками вручную с помощью PlatformIO Core (CLI) и инструментов командной строки вроде pio pkg install.
Как всегда немного пустых теоретических разглагольствований
Современные программные проекты редко работают изолированно. В большинстве случаев любой проект опирается на повторно используемые функциональные возможности в виде библиотек или разбивается на отдельные компоненты для создания модульной системы. Если вы работали хотя бы с одним, самым маленьким и простым проектом Arduino, то наверняка уже поняли, что без добавления стороннего кода к вашему проекту не обойтись никак. Как минимум вы подключаете к вашему коду какие-либо системные или платформенные библиотеки посредством директивы #include. Для взаимодействия с периферийным оборудованием и датчиками почти всегда используются сторонние библиотеки от производителя или других разработчиков. Ну и наконец, когда ваших проектов станет несколько, вы неизбежно столкнетесь с необходимостью “вынести” повторяющийся в разных проектах код в свои личные библиотеки.
При компиляции проекта в PlatformIO поиском и подключением к вашему проекту необходимых библиотек занимается специальный компонент – Library Dependency Finder (LDF) (система поиска зависимостей библиотек) — это основная часть системы сборки PlatformIO, которая работает с исходными файлами C/C++ и ищет директивы #include, чтобы узнать, какие каталоги заголовков включить для компилятора. Её функционал мы подробнее рассмотрим ниже.
Дабы внести ясность в дальнейший текст, условно разделим все включаемые в проект библиотеки на несколько условных групп. Я отнюдь не претендую на академичность названий, но предложенная классификация, на мой взгляд, позволит проще понять суть дальнейшего словоблудия.
- Системные и платформенные библиотеки – то есть те, которые уже изначально включены в тот framework, который вы используете. Например ESP-IDF или Arduino32. Они устанавливаются автоматически при установке платформы в вашу IDE и не требуют отдельной установки – вам требуется только подключить их к вашему коду с помощью соответствующий директивы #include. Однако при этом в VSCode бывают проблемы с IntelliSense с платформенными библиотеками, как это исправить я уже писал ранее.
- Сторонние библиотеки – то есть файлы, которые вы разрабатывали не сами и не производитель программной платформы (framework-а). Это могут быть драйвера дисплеев, датчиков, устройств, библиотеки для работы с различными протоколами передачи и форматами данных. Прежде чем вы подключите такую библиотеку к вашему проекту с помощью #include, вам потребуется вначале скачать и установить её в вашу IDE. Сделать это можно обычно разными способами, например так:
- из стандартного каталога библиотек вашей IDE, используя соответствующий графический или командный интерфейс. Для Aduino IDE это “Управление библиотеками…”, для PlatformIO – “Реестр библиотек“.
- из архива .zip, *.rar, *.tar (и других), который вы скачали с сайта разработчика или иного источника.
- из репозитория систем управления версиями VCS (Git, Hg, SVN). Менеджер библиотек PlatformIO позволяет автоматически скачивать и устанавливать необходимые библиотеки прямиком из репозиториев, что несомненно, очень удобно. Но об этом чуть позже.
- Локальные библиотеки – под этим термином я называю свои библиотеки, которые написал я и использую в своих проектах. Они “лежат” в определенных папках на диске моего компьютера, и мне только нужно указать компилятору, где их искать. Разумеется, сторонние библиотеки, скачанные в виде готовых архивов и (или) файлов, так же полностью можно считать локальными библиотеками. Локальные библиотеки можно условно разделить на два подвида:
- частные библиотеки проекта – часть кода, вынесенного из общей кодовой базы проекта в отдельные файлы для более удобного редактирования и управления ими. На самом деле в PlatformIO гораздо удобнее работать с 10 небольшими файлами кода, чем с одним файлом в 65535 строк – листать его то ещё удовольствие. В проектах PlatformIO такие библиотеки расположены в папке <project>\lib проекта и дополнительно подключать их к проекту не требуется.
- общие локальные библиотеки – общая кодовая база, которая используется (или планируется к использованию) в нескольких проектах одновременно. Как правило, они физически (на диске) расположены вне каталога проекта и доступны всем проектам сразу.
Настройки проекта PlatformIO
Все настройки проекта PlatformIO, в том числе и сведения о подключаемых библиотеках, осуществляются и хранятся в файле platformio.ini. Иного способа, насколько я знаю, не существует. Файл этот расположен в корневом каталоге вашего проекта.
В platformio.ini имеется 2 раздела, в которых можно объявить зависимости от используемых библиотек:
- Общий раздел [env] — объявляет общие параметры для всех рабочих сред, если их несколько.
- Рабочий раздел [env:NAME] — объявляет конкретные параметры для выбранной рабочей среды с именем NAME.
Например вы можете объявить две рабочих среды [env:esp32debug] и [env:esp32release] с разными параметрами. В том числе, например, использовать различные версии библиотек. Или другие опции сборки. А можно создать несколько разных рабочих сред под разные версии микроконтроллера – здесь всё зависит от ваших конкретных задач и фантазии.
В тестовом проекте, который вы найдете на GitHub, настроен общий раздел и одна рабочая среда [esp32dev]:
; Общие параметры для всех рабочих сред проекта [env] ; Рабочие параметры для платы esp32dev и фреймворка espidf [env:esp32dev] platform = espressif32 board = esp32dev framework = espidf
В этих самых разделах platformio.ini, в том числе, хранятся и параметры зависимостей от библиотек, использованных в вашем проекте. Параметров управления библиотеками не много, а очень много, поэтому осваивать их будем постепенно, по мере прочтения статьи. А начать, наверное, стоит с того, где хранятся эти самые библиотеки.
Хранилища библиотек
Как я уже сказал, прежде чем вы сможете использовать ту или иную библиотеку в проекте, вы должны её вначале скачать и установить в вашу систему. Все скачанные библиотеки (или созданные вами локальные библиотеки) могут находиться в одном из нескольких хранилищ. Хранилище по своей сути – это просто папка на диске вашего компьютера. Эти хранилища (папки) имеют приоритет и LDF работает с ними в следующем порядке:
- lib_dir — собственное/частное хранилище библиотек, индивидуальных для каждого проекта . По умолчанию это подкаталог <project>\lib вашего проекта.
- libdeps_dir — хранилище библиотек проекта, используемое Library Manager-ом. Менеджер библиотек помещает сюда библиотеки, подключенные к проекту по ссылкам в сети Интернет, например (как конкретно это сделать, подробнее рассмотрим ниже). По умолчанию это workspace_dir\libdeps, где workspace_dir = <project>\.pio, то есть libdeps_dir это подкаталоги <project>\.pio\libdeps.
- core_dir\lib — глобальное хранилище библиотек для всех проектов. Справочная система PlatformIO, однако, говорит о том, что эта возможность устарела и они не рекомендуют использование глобальных библиотек. В этом я с ними согласен – не слишком хорошая идея пихать в один каталог библиотеки для разных платформ и микроконтроллеров.
- Библиотечные хранилища, встроенные в фреймворки, SDK и т.д. Здесь всё будет зависеть от того, какую SDK или платформу вы используете. PlatformIO автоматически находит библиотеки платформ и SDK при компиляции, дополнительно их подключать к проекту не требуется.
Все описанные ниже каталоги хранения (хранилища библиотек) можно перенастроить через различные опции platformio.ini.
Частное хранилище библиотек проекта
Частные библиотеки проекта находятся в папке (каталоге) <project>\lib вашего проекта. Изменить это поведение при необходимости можно с помощью опции lib_dir, поместив его в одну из упомянутых выше секций. Например если мне не нравиться имя каталога в единственном числе <project>\lib, то я могу поменять его на <project>\libs так: lib_dir=libs. На самом деле, я никогда этой опцией не пользуюсь – слишком много настроек, отличных от “стандартных” усложняют работу над проектом, всё хорошо в меру.
LDF автоматически находит все частные библиотеки, и вам ничего не нужно указывать и настраивать дополнительно. Частные библиотеки, расположенные в одном проекте, будут не доступны для другого проекта, но на то они и частные. Частные библиотеки отлично походят для структуризации кода больших проектов на более мелкие функциональные составляющие.
Хранилище библиотек проекта PlatformIO Library Manager
Условно назовём это хранилище системным, так как мы сами, своими шаловливыми ручками, помещать в него ничего не должны. Этим хранилищем управляет PlatformIO Library Manager, целиком и полностью. В него он поместит библиотеки, которые мы подключили к проекту с помощью ссылок на GitHub и другие источники библиотек в сети интернет. Как это сделать, я расскажу ниже.
По умолчанию менеджер библиотек использует под это хранилище каталог <project>\.pio\libdeps вашего проекта. Но вы можете изменить это поведение с помощью опций libdeps_dir и (или) workspace_dir. Вопрос только в том – а надо ли?
Глобальное хранилище библиотек
Глобальное хранилище используется для всех проектов сразу. По умолчанию глобальное хранилище настроено как core_dir/lib. Здесь core_dir – это каталог, куда был установлен PlatformIO. Если ваш профиль в Windows записан латиницей, то это скорее всего %USERPROFILE%\.platformio, иначе это может быть C:\.platformio. Соответственно глобальное хранилище библиотек – это либо %USERPROFILE%\.platformio\lib либо C:\.platformio\lib. Сюда вы можете поместить все свои глобальные библиотеки. Это же хранилище используется командой pio pkg install с опцией -g.
Управляется это хранилище опцией globallib_dir. Однако, если вы перейдете по данной ссылке на справочную систему, по наверняка заметите такое вот предупреждение:
Эта опция УСТАРЕЛА. Мы не рекомендуем использовать глобальные библиотеки для новых проектов. Пожалуйста, используйте декларативный подход для критически важной для безопасности встроенной разработки и объявляйте зависимости проекта с помощью опции lib_deps.
Штош… Не очень-то и хотелось!
Библиотечные хранилища, встроенные в фреймворки, SDK
Тут на самом деле всё очень просто – PlatformIO сам разберется, где хранить платформы и фреймворки, и где потом искать те или иные “системные” библиотеки из них. Можно изменить корневой каталог platformio, если это необходимо, с помощью опции core_dir – в данный каталог и устанавливаются все платформы, frameworks и инструменты. По умолчанию это %HOMEPATH%\.platformio. Но, учитывая, что данная опция может повлиять на все проекты сразу, вряд ли оптимально делать это в platformio.ini конкретного проекта.
Как подключить локальные библиотеки к проекту
Теперь, когда мы разобрались с видами хранилищ библиотек, можно уже начинать пробовать подключать библиотеки к нашему тестовому проекту. Для начала стоит рассмотреть простейшие случаи, когда ваши библиотеки находятся на вашем же компьютере. Итак.
Частные библиотеки проекта
Тут всё предельно просто – создаете внутри папки <project>\lib нужные вам подкаталоги и файлы и компилируете! Все! Никаких изменений в platformio.ini в данном случае вносить не требуется.
И таки да, вы можете создавать внутри данного хранилища произвольное количество подкаталогов для различных модулей проекта, например так:
C:\PlatformIO\<project_name>\ |--lib | |--ioext | | |--ioext.h | | |--ioext.c | |--sensors | | |--sensors.h | | |--sensors.c | |--alarm | |--alarm.h | |--alarm.c |--src | |--main.c |--platformio.ini
При этом библиотеки “внутри” <project>\lib могут ссылаться друг на друга, но старайтесь избегать циклических зависимостей.
Общие локальные библиотеки
А что если необходимо подключить к проекту общие локальные библиотеки, которые можно было бы использовать в различных проектах одновременно. Допустим, у меня есть парочка десятков собственных библиотек, которые “лежат” в каталоге C:\PlatformIO\libs_espidf\ и я таки имею страстное желание использовать их в нескольких проектах одновременно. Примечание: в данном конкретном случае я пока что рассматриваю библиотеки, которые хранятся на дисках в виде обычных папок (каталогов) и файлов внутри них; подключение к проекта библиотек в виде скачанных и не только архивов рассмотрим ниже.
Для этого существует как минимум несколько способов. В данном разделе я расскажу о двух (которыми и сам пользуюсь), а в следующем – ещё о нескольких. Почему так – станет понятно по ходу пьесы статьи.
Способ 1. Используем глобальное хранилище библиотек
Самый простой способ – переместить наши / ваши общие библиотеки в глобальное хранилище – core_dir/lib
. Получается также просто, как и в предыдущем случае. Для примера я поместил в тестовый проект одну глобальную библиотеку (к сожалению, она на GitHub не попадет, но я их положил в “отдельную” папочку).
Но справочная система не рекомендует нам этого делать. И я с ней согласен. Хотя бы потому, что из этой одной единственной папки потянуться в проект самые разные библиотеки для разных платформ и микроконтроллеров – и нужные и ненужные. Конечно, компилятор умный, он их не будет включать без соответствующих #include, но как поведет себя система поиска зависимостей, написанная на питоне – вопрос. Не наш метод.
Способ 2. Используем параметр lib_extra_dirs
Для platformio.ini существует (пока существует) опция lib_extra_dirs, через которую системе поиска зависимостей можно указать, где искать наши локально-расшаренные библиотеки. Допустим, я поместил их в С:\PlatformIO\libs_espidf\shared_lib_1 и С:\PlatformIO\libs_espidf\shared_lib_2, как и в случае с частными библиотеками (эти библиотеки, расположенные “вне” каталога проекта, также не попадут на GitHub).
В platformio.ini добавляем параметр lib_extra_dirs, в котором указываем их расположение:
; Общие параметры для всех рабочих сред проекта [env] ; Каталог общих локальных библиотек lib_extra_dirs=C:\PlatformIO\libs_espidf ; Рабочие параметры для платы esp32dev и фреймворка espidf [env:esp32dev] platform = espressif32 board = esp32dev framework = espidf
После этого мы можем вполне успешно использовать их в проекте, как и частные, и глобальные. Я пока что использую данный метод в большинстве прежних проектов (просто создав разные наборы библиотек для разных платформ), но, походу, от него придется избавляться.
Примечание: а данной опции указывать путь к библиотекам нужно только до предпоследнего уровня, то есть не нужно перечислять и указывать конкретные каталоги с библиотеками. В примере в общих экстра библиотеках у меня всего один уровень и два подкаталога. Но если структура ваших библиотек включает больше вложенных уровней – необходимо будет перечислить все уровни, но так же до предпоследнего, например так:
; Локальные библиотеки lib_extra_dirs = // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\certs // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\system // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\peripherals // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\sensors // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\wifi // внутри несколько папок с разными библиотеками C:\Projects\PlatformIO\libs\clouds
Проверяем – проект успешно компилируется и работает:
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf LDF Modes: Finder ~ chain, Compatibility ~ soft Found 5 compatible libraries Scanning dependencies... Dependency Graph |-- global_lib_1 |-- project_lib_1 |-- project_lib_2 |-- shared_lib_1 |-- shared_lib_2 Building in release mode Retrieving maximum program size .pio\build\esp32dev\firmware.elf Checking size .pio\build\esp32dev\firmware.elf Advanced Memory Usage is available via "PlatformIO Home > Project Inspect" RAM: [ ] 3.2% (used 10604 bytes from 327680 bytes) Flash: [== ] 16.7% (used 175017 bytes from 1048576 bytes)
Но есть небольшая проблемка: опция lib_extra_dirs устарела с версии 6.0 и будет удалена в следующем основном выпуске PlatformIO. А это значит, от неё придется избавляться. Но – не страшно, у нас есть более универсальный и более удобный вариант, который мы и рассмотрим в следующем разделе.
Универсальный метод подключения библиотек к проекту
Самый универсальный механизм подключения библиотек к вашему проекту PlatformIO – использовать опцию lib_deps в одной из двух секций platformio.ini. В терминологии PlatformIO это называется не “подключение библиотеки“, а “объявление зависимостей“. Эта опция управляет зависимостями вашего проекта от сторонних библиотек и позволяет подключить библиотеки из самых разных источников (окромя частных библиотек проекта, разумеется):
- из общих (для разных проектов) локальных папок
- из локальных архивов zip или tar (имеется в виду без предварительной распаковки архива вручную)
- из архивов zip или tar где-то в интернете без предварительного скачивания и распаковки
- из реестра библиотек PlatformIO
- из репозиториев Git, GitHub, Hg, Svn (в том числе через самые разные протоколы – HTTPS и SSH и т.д.),
Эта опция может иметь сразу несколько значений одинаковых или разных типов, при этом каждое новое значение должно начинаться с новой строки.
[env] lib_deps = ; на основе только имени библиотеки (например это встроенная библиотека в framework) SPI ; на основе владельца и имени библиотеки (из реестра библиотек PlatformIO) knolleary/PubSubClient ; из локальной папки на вашем компьютере Windows file://C:/local/path/to/the/package/dir ; Внешний Git репозиторий, получаемый по HTTPS-протоколу https://github.com/gioblu/PJON.git ; ZIP-архив с дополнительным указанием имени библиотеки IRremoteESP8266=https://github.com/markszabo/IRremoteESP8266/archive/master.zip
Обязательным условием во всех случаях является наличие у подключаемой библиотеки файла манифеста, в котором как минимум должны быть объявлены имя библиотеки и её версия в формате Semantic Versioning 2.0.0 <MAJOR>.<MINOR>.<PATCH>
. Этот файл и зачем он так необходим мы подробнее рассмотрим в следующих главах. Иначе вы рискуете получить сообщение вида:
MissingPackageManifestError: Could not find one of 'library.json, library.properties, module.json' manifest files in the package
Если вы объявляете зависимость от удаленной библиотеки (не на вашем компьютере), то вам не требуется её скачивать – все необходимые действия будут выполнены автоматически. Скачанные и распакованные файлы будут помещены в хранилище библиотек проекта PlatformIO Library Manager, про которое я и рассказывал выше (а иначе зачем бы), то есть в папку <project>\.pio\libdeps вашего проекта.
Все эти варианты мы и рассмотрим далее. Начнем с уже начатой темы – а именно подключения локальных общих библиотек.
Подключение локальной папки с библиотекой
Для подключения к проекту общих локальных библиотек мы можем использовать два префикса:
- [<name>=]file://C:/local/path/to/the/lib_directory
- [<name>=]symlink://C:/local/path/to/the/lib_directory
В первом случае каталог, указанный после ключевого слова file://, рассматривается только как первоначальный источник библиотеки, после чего её содержимое копируется в хранилище библиотек проекта (каталог <project>\.pio\libdeps). Последующее внесение изменений в исходную папку НЕ повлияет на уже установленный пакет библиотеки.
Во втором случае библиотека никуда не копируется и не переносится, а используется “как есть”, то есть в исходной папке. Внесение изменений в исходную папку сразу же повлияет на установленный пакет.
В любом случае папка пакета должна содержать файл манифеста ( Library.json , platform.json или package.json) со свойствами имени и версии. Но в случае использования префикса file:// умный PlatformIO создаст манифест автоматически, а в случае с symlink:// – изругается самыми грязными выражениями.
Вы также можете переопределить имя папки пакета в хранилище диспетчера пакетов, используя синтаксис <name>=
(не обязательно). Если вы используете операционную систему семейства windows, то указывать пути можно как в windows-нотации, так и в linux-нотации, например это может выглядеть так:
[env] lib_deps= MyLib1=file://C:/PlatformIO/libs_symlink/symlink_lib_1 symlink://C:\PlatformIO\libs_symlink\symlink_lib_2
Главным недостатком такого подхода я считаю необходимость подключения к каждому проекту каждой вашей библиотеки отдельно, в отличие от lib_extra_dirs, которая позволяет грузить апельсины бочками. На текущий момент у меня используется несколько десятков библиотек, и все их придется подключать отдельной строкой. Поэтому я и не спешу переходить на этот способ.
Подключение библиотек из архивов ZIP и TAR
Спецификация: [<name>=]file://C:/local/path/to/the/archive.zip
Ок, с папками разобрались. А что если мы где-то когда-то скачали файл библиотеки, и хотим применить в нашем проекте. Можно конечно, распаковать этот архив, содержимое поместить в какой-нибудь каталог и подключить к проекту одним из вышеперечисленных способов, например через file:// или symlink://.
Но настоящие программисты настолько суровы, что им лень распаковывать архив. Поэтому они подключают архив к проекту целиком и сразу – без распаковки. Делается это с помощью того же самого префикса file://, при этом расширение файла должно быть одно из .tar.gz
, .tar
, .tgz
, или .zip
. И “опять и снова” обязательное условие – внутри архива должен быть файл манифеста ( Library.json , platform.json или package.json) со свойствами имени и версии.
[env] lib_deps = file://C:\local\path\to\the\archive.zip
PlatformIO распакует такой файл и поместит его содержимое в то же самое хранилище – каталог <project>\.pio\libdeps.
На самом деле, подключать библиотеки к проекты в виде локальных архивов – лично на мой взгляд дело сомнительной необходимости. Но вот подтянуть библиотеку в виде архива сразу из интернета с какого-то сайта – это то что доктор прописал.
Спецификация: [<name>=]http(s)://remote/path/to/the/archive.zip
Например с GitHub:
[env] lib_deps = https://github.com/bblanchon/ArduinoJson/archive/refs/heads/6.x.zip
PlatformIO сам скачает такой архив и распакует его, поместит куда нужно. Удобно? Конечно! Но есть способ лучше – клонировать репозиторий сам по себе, возможно с указанием дополнительных параметров.
Подключение библиотек из реестра PlatformIO
Как и Arduino IDE, PlatformIO имеет собственный каталог библиотек и пакетов, именуемый реестром библиотек PlatformIO. В нем можно найти библиотеки для множества систем и платформ почти на все случаи жизни. Установить библиотеку из него можно двумя способами.
Способ 1. Интуитивно понятный, через меню и кнопочки
Перейти в него проще всего из Visual studio code → PIO Home → Librares. Там вы ищите и выбираете нужную вам библиотеку и жмете кнопку [ Add To Project ]. Это действие приводит к немедленной установке выбранной библиотеки куда? Правильно – в тот же самый грешный каталог <project>\.pio\libdeps вашего проекта. То есть библиотека устанавливается не для всех проектов сразу, а только для текущего! При этом ничего дополнительно в platformio.ini не добавляется.
Способ 2. Ручками, через platformio.ini
Спецификация: <owner>/<name>@<version requirements>
Если вам известны имя библиотеки и её владелец, то нет необходимости шарить по реестру библиотек, можно сделать это быстро и аккуратно, использовав все тот же самый механизм, например так:
[env] lib_deps = kotyara12/rLed32 @ ^1.1.1
Символы после @ определяют используемую версию библиотеки <version requirements>
– я расскажу чуть ниже, потерпите немного. В этом случае выбранная библиотека будет автоматически скачана и установлена в хранилище при первой компиляции проекта. На мой взгляд этот способ несомненно удобнее, надежнее и практичнее – по крайней мере при клонировании проекта или переносе проекта с компьютера на компьютер вам не потребуется повторно устанавливать библиотеки вручную. Согласитесь – это ведь гораздо удобнее, чем в Arduino IDE?
Клонирование библиотек из репозиториев Git, GitHub, Hg, Svn
Спецификация: [<name>=][<scheme>://][<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish|branch|tag>]
Ну и напоследок рассмотрим вариант автоматической загрузки библиотек из различных публичных и непубличных репозиториев. Поддерживаются Git, GitHub, Hg и Svn. Например на GitHub-е опубликованы большинство публичных библиотек для Arduino и ESP, там достаточно удобный поиск, поэтому имеет очень большой смысл тянуть их сразу оттуда. При загрузке можно использовать следующие схемы: http, https, git, git+http, git+https, git+ssh, hg+http, hg+https, hg+ssh, svn+http, svn+https, svn+ssh.
Примеры подключения библиотеки с GitHub:
[env] lib_deps = https://github.com/kotyara12/rLog.git
или так:
[env] lib_deps = git@github.com:kotyara12/rLog.git
При первой компиляции PlatformIO сам клонирует указанный вами репозиторий и поместит его в хранилище проекта, то есть в тот же самый пресловутый каталог <project>\.pio\libdeps. Вы можете указать имя пользователя и пароль, тем самым подключать библиотеки не только из публичных репозиторием; а также можно задать ветку или конкретный коммит при необходимости.
Управление версиями библиотек
Теперь, когда мы рассмотрели основные варианты подключение библиотек, стоит отдельно упомянуть систему указания версий библиотек. Ничего не стоит на месте, и многие разработчики постоянно дорабатывают свои библиотеки – добавляют новые функции и устраняют найденные ошибки. Это, безусловно, очень неплохо, но иногда это может принести дополнительные проблемы. Собрали вы, скажем, свой проект с использованием чьей-то сторонней библиотеки или платформы, а она раз – и обновилась! И проект вдруг перестал компилироваться из-за новых функций или ещё каких-либо изменений. И вам потребуется дополнительное время, дабы привести вроде бы работающий уже проект под новые данные. И времени часто не хватает, а заказчик / начальник “руками сучит, ногами стучит, очами вращает, в обчем, стращает” (с) Леонид Филатов.
Разумеется, разработчики предусмотрели специальный механизм, который называется Version Requirements. Работает это не только для библиотек, но и для всех других пакетов – например так можно указывать версию платформы Arduino или ESP-IDF для вашего проекта.
Если кратко, то заключается он в следующем – после указания ссылки на библиотеку или иной пакет вы можете дополнительно задать требуемую версию пакета или библиотеки. Версия указывается после символа @, и может быть записана в нескольких вариантах (см. шпаргалку Semver):
-
^1.2.3
– любая совместимая версия (допускаются новые функции с обратной совместимостью и исправления, 1.xx). -
~1.2.3
– любая версия с одинаковыми основными и второстепенными версиями, а также равная или более высокая версия исправления -
>1.2.3
– любая версия выше1.2.3
, вы также можете использовать другие операторы сравнения:>=
,<
,<=
. -
>0.1.0,!=0.2.0,<0.3.0
– совмещенная запись: любая версия больше0.1.0
, не равна0.2.0
и меньше0.3.0
-
1.2.3
– точный номер версии. PlatformIO попробует загрузить только эту точно заданную версию и ничто иное.
То есть если я записал выше:
[env] lib_deps = kotyara12/rLed32 @ ^1.1.1
то это означает, что PlatformIO попытается установить любую совместимую версию указанной библиотеки. Осталось понять – откуда он знает эту самую. Верно – из того самого файла манифеста.
Необходимо отметить, что указанная версия скачивается один раз при первой компиляции проекта, и в последующем без особого указания с вашей стороны не обновляется. Для загрузки свежих версий библиотек, платформ, фреймворков и иных пакетов в последующем используйте команду pio pkg update
.
Файл манифеста библиотеки PlatformIO
Каждая ваша или сторонняя библиотека, которую вы создали сами или загрузили со стороны, должна иметь файл манифеста, который должен иметь имя library.json , platform.json
или package.json
– как вы, наверное, уже догадались, для библиотеки, платформы или иного пакета соответственно. Это позволяет разработчикам сохранять структуру проекта и определять:
- совместимые фреймворки и платформы
- внешние зависимости от других библиотек
- расширенные настройки сборки.
Информация в файле library.json
должна быть представлена в стиле JSON через ассоциативный массив (пары имя/значение). Порядок записей не имеет значения. Допустимые поля (имена из пар) описаны в справочной системе – особого смысла перечислять все из здесь я не вижу. Приведу только некоторые из них, которые могут относиться к нашим библиотекам:
name
– имя библиотеки. Должно быть уникальным в реестре PlatformIO. Может содержать AZ, цифры и тире (но не может начинаться или заканчиваться ими).version
– версия текущего исходного кода библиотеки. Может содержать az, цифры, точки или тире и должен быть совместим с семантическим управлением версиями.description
– описание библиотеки. Поле помогает пользователям искать вашу библиотеку в каталоге.keywords
– ключевые слова. Помогает облегчить поиск вашей библиотеки, при этом людям не нужно знать ее название.homepage
– домашняя страница библиотеки (если она отличается от URL репозитория).repository
– репозиторий, в котором можно найти исходный кодauthors
– контактная информация автораframeworks
– cписок совместимых фреймворковplatforms
– cписок совместимых платформ разработки
Для библиотек, которые вы создаете сами, вы должны указать хотя бы два параметра – name
и version
– они выделены жирным шрифтом. В качестве примера приведу один из своих файлов:
{ "name": "reSensor", "version": "3.2.0", "description": "Unified sensor base class used by sensor libraries", "keywords": "sensors", "authors": [ { "name": "Alexander Razzhivin", "email": "kotyara12@yandex.ru", "url": "https://kotyara12.ru" } ], "license": "MIT", "frameworks": ["arduino", "espidf"], "platforms": ["espressif32"] }
Опции поиска зависимостей библиотек
Ни для кого не секрет, что библиотеки часто ссылаются друг на друга, то есть зависят друг от друга. И библиотеки, которые вы перечислили явным образом, могут тянуть за собой множество других библиотек и пакетов, от которых они зависят. Например многие библиотеки сенсоров от Adafruit требуют обязательного наличия базового класса Adafruit Unified Sensor Driver. В Arduino IDE вам пришлось бы устанавливать его вручную отдельно, PlatformIO же вполне может установить его в ваш проект неявно, без вашего активного вмешательства.
Здесь стоит немного остановиться на поиске зависимостей библиотек. Этим занимается специальный механизм – Library Dependency Finder (LDF). Средство поиска зависимостей библиотек — это основная часть системы сборки PlatformIO, которая работает с исходными файлами C/C++ и ищет директивы #include, чтобы узнать, какие из заголовков подключить к компилятору. Library Dependency Finder всегда начинает работу с анализа исходных файлов проекта ( src_dir ) и может работать в следующих режимах:
off
: «Ручной режим», не обрабатывает исходные файлы проекта и зависимости. Собирает только те библиотеки, которые явно указаны с использованием параметра lib_deps или их манифестах ( library.json , module.json).chain
: Анализирует ВСЕ исходные файлы проекта на C/C++ и следует только по вложенным включениям (цепочкам) из библиотек. Он также анализирует файлы C, CC, CPP из библиотек, которые имеют то же имя, что и включенный заголовочный файл. Не оценивает условный синтаксис препроцессора C/C++ .deep
: Анализирует ВСЕ исходные файлы C/C++ проекта и анализирует ВСЕ исходные файлы C/C++ каждой найденной зависимости (рекурсивно). Не оценивает условный синтаксис препроцессора C/C++ .chain+
: То же поведение, что и дляchain
, но при этом он учитывает условный синтаксис препроцессора C/C++ .deep+
: То же поведение, что и дляdeep
, но при этом он учитывает условный синтаксис препроцессора C/C++ .
Режим можно изменить с помощью опции lib_ldf_mode в platformio.ini (файле конфигурации проекта). Значение по умолчанию установлено как chain
. Поэтому, если вы, например, желаете отключить какие-то библиотеки с помощью макросов #if … #endif, то вам желательно перейти на chain+
. Но скажу сразу – работает это пока кривовато.
Библиотеки и IntelliSence
Подключение библиотек к проекту через platformio.ini вовсе не означает, что у вас сразу же заработает подсветка синтаксиса и автодополнение кода для вновь подключенных библиотек. Скорее всего – наоборот – будет вагон и маленькая тележка разнообразных “псевдоошибок” от системы IntelliSence. Как с эти бороться?
Во первых попробовать компилировать проект и обновить индексы IntelliSence. Сделать это можно с помощью команды VSCode → Menu: View → Command Palette… → PlatformIO: Rebuild C/C++ Project Index. Это перестроит индексы системы IntelliSence и, возможно, решит данную проблему.
Если предыдущий вариант не помогает, следует подсказать IntelliSence, где искать библиотеки и фреймворки, где искать ваши исходные файлы. Ищем каталог .vscode, а в нем файл c_cpp_properties.json. Открываем его с помощью любого тестового редактора. И добавляем в массив includePath все пути, которые вы используете. Дабы они обрабатывались рекурсивно, в конце пути должны быть символы **. Например у меня это выглядит так:
{ "configurations": [ { "name": "Win32", "includePath": [ "${workspaceFolder}/**", "C:/Projects/PlatformIO/libs/**", "${env:USERPROFILE}/.platformio/packages/framework-espidf/components/**", "${env:USERPROFILE}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/**", "${env:USERPROFILE}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/**", "${env:USERPROFILE}/.platformio/packages/toolchain-xtensa-esp32/lib/gcc/xtensa-esp32-elf/**", "${env:USERPROFILE}/.platformio/packages/toolchain-xtensa32/lib/gcc/xtensa-esp32-elf/**" ], "defines": [ "_DEBUG", "UNICODE", "_UNICODE" ], "cStandard": "c17", "cppStandard": "c++17", "intelliSenseMode": "windows-msvc-x64", "compileCommands": "${workspaceFolder}/.pio/build/esp32dev/compile_commands.json" } ], "version": 4 }
После этого не забываем заново перестроить индексы, как описано выше. После этого проблема самоликвидируется.
Ну а на этом у меня на сегодня всё, с вами был ваш Александр aka kotyara12. Надеюсь, статья будет вам полезна. Вы можете оценить её – но это строго по желанию, так как ни на что особо не влияет. Благодарю за внимание.
Ссылки
- Репозиторий примера на GitHub
- Документация: менеджер библиотек PlatformIO
- Реестр библиотек PlatformIO
- Статья у AlexGyver
💠 Полный архив статей вы найдете здесь
Пожалуйста, оцените статью: