image

Поскольку я интенсивно занимаюсь разработкой в Arduino IDE, то этот вопрос меня неподдельно волновал. Почему скетч, написанный в одной версии среды разработки отказывается компилироваться в соседних версиях? Этим же вопросом меня заваливали пользователи системы Arduino Mega Server. Почему АМС компилируется в 1.6.5 и отказывается компилироваться в 1.6.4, 1.6.7 и 1.6.8?

И вот недавно, в процессе портирования Arduino Mega Server на новый контроллер Genuino 101, мне удалось разгадать эту великую загадку. И в этой статье я поделюсь с вами этим сакральным знанием и ваши скетчи после этого всегда будут успешно компилироваться. Итак…

Логика вещей


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

Внутренняя кухня


Чтобы это понять, нужно разобраться с тем, как формируются версии сред разработки Arduino IDE и как пользователи работают с этими средами разработки.

Начнём с пользователей. Большинство из них компилирует примитивные проекты, образно говоря, в 20 строк и с этими проектами никаких проблем не возникает. Эти проекты успешно компилируются в любой версии IDE потому, что используют только стандартные вызовы библиотечных функций и никак не модифицируют сами библиотеки.

Но сколько-нибудь развитый проект на Ардуино уже не умещается в «20 строк» и неизбежно пользуется менее распространёнными функциями из библиотек (которые более подвержены модификациям из версии в версию) и неизбежно приходят к необходимости модификации самих библиотек под свои специфические нужды проекта.

А один раз модифицировав системную библиотеку, вы становитесь её заложником и вынуждены «тащить» её за собой из версии в версию.

Теперь давайте разберёмся с тем, как формируются версии Arduino IDE. А формируются они по произволу (я подозреваю, что в конечном счёте, одного конкретного программиста, какого-нибудь Марио) выпускающей команды. И то, какая версия конкретной библиотеки будет включена в дистрибутив и в каком виде (с какими модификациями), остаётся на совести этого «Марио».

А теперь внимание, это очень важно! Выпускающая команда преследует только одну цель — чтобы дистрибутив одной версии был взаимно согласован и непротиворечив внутри себя. Их задача добиться того, чтобы все стандартные примеры работали корректно. И это всё! Задача совместимости между версиями вообще не ставится.

И поскольку 99% процентов пользователей компилирует проекты в «20 строк» этот подход прекрасно «прокатывает» на практике. А то, что сколько-нибудь серьёзные проекты не компилируются, это проблемы этих проектов. Слава Богу, теперь понятен механизм возникновения проблемы и теперь стало понятно, как с этим бороться.

Конкретный пример


image

Вспомним портирование АМС на Genuino 101 (работает начиная с версии 1.6.7 и выше). Тут команда Ардуино припасла для нас очередной прикол (молодцы ребята, не дают нам расслабляться).

Попытка откомпилировать проект для нового контроллера приводила к появлению множества ошибок компилятора. Анализ сообщений показал, что компилятору категорически не нравится наша Ethernet библиотека. Чем же она так не угодила компилятору?

Начинаем разбираться.

Наша библиотека: version=1.0.4 (не нравится компилятору)
Библиотека из IDE 1.6.7: version=1.0.4 (нравится компилятору)

Однако.

Наша библиотека: 31 файл (не нравится компилятору)
Библиотека из IDE 1.6.7: 31 файл (нравится компилятору)

Однако.

Наша библиотека: 123 КБ (не нравится компилятору)
Библиотека из IDE 1.6.7: 123 КБ (нравится компилятору)

Однако.

Другими словами, Марио «засунул» в IDE 1.6.7 Ethernet библиотеку с одним и тем же номером версии, что и в IDE 1.6.5, одним и тем же количеством файлов и с одним и тем же размером, но с РАЗНЫМ СОДЕРЖИМЫМ и забыл нас об этом предупредить. А это самое «разное содержимое» как паук держится своими лапками за IDE и другие библиотеки более низкого уровня (тоже модифицированные в 1.6.7).

Браво, Марио! С таким подходом ничего не будет компилироваться, кроме стандартных примеров и скетчей в 20 строк.

Практическое решение (головоломок от Ардуино)


Теперь стал кристально ясен механизм того, почему не компилируются проекты в разных версиях Arduino IDE и, соответственно, так же кристально стал ясен путь решения этой проблемы. В данном конкретном случае решение состоит из трёх частей.

  • Часть первая. Нахождение работающей библиотеки. Помните, задача у выпускающей команды создать непротиворечивую версию IDE? Значит где-то должна быть работающая версия нужной нам библиотеки.
  • Часть вторая. Перенесение работающей Ethernet библиотеки от шалуна Марио на её место в проекте Arduino Mega Server. Здесь нет ничего сложного — просто копируем её на место нашей неработающей в IDE 1.6.7 Ethernet библиотеки.
  • Часть третья. Модификация под проект Arduino Mega Server перенесённой и заведомо работающей в IDE 1.6.7 Ethernet библиотеки.

То же самое нужно проделать со всеми некомпилирующимися библиотеками проекта (то есть найти работающую версию библиотеки из IDE и перенести её на её место в проекте и модифицировать, если это необходимо). Но в данном случае нам повезло, все остальные библиотеки заработали нормально (потому, что Марио не успел их по-тихому модифицировать, хотя мог и обязательно сделает это в новых версиях IDE, но мы уже знаем как с этим бороться).

Заключение


Вот и весь секрет успешной работы в Arduino IDE со сложными проектами. Теперь вы можете чувствовать себя во всеоружии и для вас не составит труда заставить работать ваш проект в любой версии Arduino IDE.

Комментарии (19)


  1. GarryC
    15.04.2016 14:15

    и неизбежно приходят к необходимости модификации самих библиотек под свои специфические нужды проекта.
    А один раз модифицировав системную библиотеку
    — можно не продолжать.
    Я и не знал, что ТАК можно.


    1. kAIST
      15.04.2016 15:14

      Тоже не понял этого момента. Если ты меняешь что то в библиотеке, ее нужно форкнуть и работать уже непосредственно с ней, а тут сами себе проблемы создали.


      1. smart_alex
        15.04.2016 17:32

        Здесь речь даже не доходит до проблем с модифицированными библиотеками, здесь речь идёт о том, что Ардуино версии 1.6.5 содержит Ethernet библиотеку версии 1.0.4, содержащую 31 файл и занимающую 123 КБ памяти и Ардуино версии 1.6.7 содержит Ethernet библиотеку версии 1.0.4, содержащую 31 файл и занимающую 123 КБ памяти. Но это разные библиотеки и несовместимые между собой.

        И речь идёт о том, что Ардуино преследует только одну цель — собрать непротиворечивый дистрибутив, а какой при этом будет устроен ад из библиотек — не важно.

        Ардуино модифицирует системные библиотеки под версии своих IDE и даже не удосуживается формально изменить номер версии. И там и там — 1.0.4 (а библиотеки кардинально разные).


        1. GarryC
          15.04.2016 17:51

          Что такое — библиотеки кардинально разные?
          Разные модули, разные вызовы, разная функциональность?
          Если изменилась реализация, а интерфейс и функционал остался прежним, то в чем проблема? В этом и смысл библиотек.
          Вот если меняется интерфейс, то тогда, конечно, это недопустимо, но все-таки именно в этом дело?
          Вы сами написали про модификацию системных библиотек, это не я придумал.


          1. smart_alex
            15.04.2016 18:08

            Система Ардуино открытая и вы сами можете проанализировать внесённые разработчиками изменения. Мне ни их логика, ни их мотивация непонятны. Особенно мне непонятно, почему две разных библиотеки имеют один и тот же номер версии. И почему одна библиотека 1.04 компилируется только в 1.6.5, а другая 1.0.4 компилируется только в 1.6.7.


  1. evocatus
    15.04.2016 16:35
    +1

    Как перестать использовать Arduino IDE и начать писать для Arduino на C под Linux:

    1) устанавливаем gcc-avr, avr-libc, avrdude

    2) Пишем код. Например:

    #include <avr/io.h>

    main() {
    DDRD |= 1<<7; // настраиваем порт D, пин 7 на выход
    PORTD |= 1<<7; // посылаем туда 1
    }


    3) Собираем:
    avr-gcc -mmcu=atmega644pa -Os -o 1.o 1.c # естественно, здесь нужно подставить вашу модель МК вместо atmega644pa
    avr-objcopy -O ihex 1.o 1.hex

    4) Бэкапим заводскую прошивку:
    avrdude -p m644p -c arduino -P /dev/ttyUSB0 -v -U flash:r:arduino_flash_factory.hex:i # не забываем поменять модель МК. Понять куда подключён программатор можно вызвав dmesg | tail после подключения платы к ПК

    5) Зашиваем новую:
    avrdude -p m644p -c arduino -P /dev/ttyUSB0 -v -U flash:w:1.hex

    Для входа в терминальный режим avrdude (если нужно) используем:
    avrdude -p m644p -c arduino -P /dev/ttyUSB0 -v -t

    6) Читаем man avrdude и http://www.nongnu.org/avr-libc/user-manual/pages.html


    1. GarryC
      15.04.2016 16:46

      А теперь сравните Вашу процедуру со стандартной в среде Ардуино, и поймете, почему народ не стремится «бэкапить прошивки и зашивать новые, а также читать мануалы».
      Я честно не могу понять, почему в -nix не могут сделать нормальные процедуры, ну хотя бы с использованием bash.
      Не то, чтобы я не мог ввести в консоли команду dmesg, но, блин, почему я должен это делать?


      1. evocatus
        15.04.2016 16:57
        +1

        https://sourceforge.net/projects/avrdude-gui/
        http://blog.zakkemble.co.uk/avrdudess-a-gui-for-avrdude/


      1. WebConn
        15.04.2016 22:41
        +1

        Ну так можно найти/написать Makefile, который всё это будет делать за вас, а вам останется только поправить код и сделать make build && make deploy.

        Если есть аллергия на консоль, есть Eclipse, под который давно сделаны нужные плагины для работы с AVR (и, да, там есть отладчик, хоть для Arduino это не актуально). Ну или Atmel Studio.

        Вообще не представляю, как можно писать хоть сколько-нибудь серьёзные проекты в Arduino IDE. А уж тем более их после этого поддерживать.


      1. tsostik
        18.04.2016 10:44

        Непонятно, кто именно не может сделать «нормальные процедуры»?
        Желающие могут поставить себе родную Arduino IDE и наслаждаться всеми ее «прелестями». Желающие могут пойти по красноглазому «только консоль, только хардкор». Желающие — написать Makefile или скрипт и пользоваться «любимым текстовым редактором», «любимой IDE», да хоть преферансом и поэтессами. И да, один раз вытащив все нужные библиотеки можно будет навсегда позабыть про кривое версионирование «от авторов» и большинство остальных проблем, связанных с кривыми руками поставщика.


    1. follow39
      15.04.2016 19:08

      2) Пишем код. Например:

      #include

      main() {
      DDRD |= 1


      1. follow39
        15.04.2016 23:42

        2) Пишем код. Например:

        #include <avr/io.h>

        main() {
        DDRD |= 1<<7; // настраиваем порт D, пин 7 на выход
        PORTD |= 1<<7; // посылаем туда 1
        while();
        }


  1. Sild
    15.04.2016 18:12

    Вы довольно красочно описали то, что было и так ясно: «Что-то поломали в новой версии, надо чинить». Где грязные подробности, что именно поломалось? И в чем поломка?


    1. smart_alex
      15.04.2016 18:33

      Не понял вопроса. Описал механизм формирования дистрибутивов сред разработки Ардуино и дал практические рекомендации, как заставить работать проект, если он не компилируется в новой версии IDE.


  1. svd71
    16.04.2016 09:52

    Если что то изменилось в библиотеке не стоит сходу возвращать старую — сначала нужно понять «Марио», за каким он сделал эти изменения. Изменения нужно вносить у себя в коде. Прричем код нужно разделить директивами прекомпайлера. Сам не фанат Ардурины, поэтому сказать точно не могу, какие дефайны нужно использовать для определения версии IDE, но уверен, что они есть. Иначе, грозит ситуация, когда вы скачиваете с git очередной проект, а он просто не запускается. А вам нужно последовательно шаг за шагом скачать все версии IDE и пытаться поменять библиотеку.

    Если хотите этого избежать — программируйте на C или C++ без использования фреймворка. Для этого ничего делать не нужно: код можно прямо в файле ino прописать. Это я и делаю чаще всего для простого прототипирования.

    Если же вам охота использовать всяческие методы с make-файлами — пожалуйста. В Arduino уже лежит последняя версия avr-gcc и avrdude. Нужно только пути правильно в make-файле прописать.


  1. sav13
    16.04.2016 17:36

    А зачем вообще скакать из версии к версии?
    Есть стабильная 1.6.5. До этого была, например 1.0.7 на которой все работало.
    Ничего принципиально нового без чего нельзя жить в 1.6.7 не появилось.
    Сторонние библиотеки (по крайней мере нормально написанные типа Адафруитовских) довольно толерантны к разным версиям.


    1. smart_alex
      16.04.2016 17:56

      Всё не так просто, например, плата Genuino 101 работает только с версией Arduino IDE 1.6.7 и выше. Без вариантов — хочешь перенести АМС на Genuino 101 — умудрись скомпилировать проект в среде 1.6.7. А там всё изменено по произволу программистов Ардуино на уровне библиотек (что плохо, но терпимо), а также на более глубоком уровне системных файлов среды (с чем бороться вообще невозможно).

      Отсюда и предложенное практическое решение как откомпилировать проект в любой версии IDE, несмотря на любые «закидоны» программистов Ардуино.


  1. Maks_K2
    16.04.2016 23:45

    А возможно сделать сравнительный анализ какие именно библиотеки модифицируются:
    сделать табличку — например базовая 1.5 — версия 1.6.5 изменены следующие библиотеки
    1.-Ethernet
    2.
    3.


    1. smart_alex
      17.04.2016 07:17

      В том то всё и дело, что модификация библиотек и системных файлов носит тотальный и субъективный характер. Пытаться предугадать, что они изменят в следующей версии и пытаться каталогизировать изменения не имеет смысла.

      Разумным решением, на мой взгляд, является понимание их целей и логики их поведения и простое и эффективное противодействие этому — нашли работающую библиотеку, перенесли в проект и модифицировали, если нужно — просто и эффективно.