Переопределение #define в библиотеках

Я создал библиотеку Arduino для устройства, из которых он обычно может быть настроен несколькими способами. Е. Г. использование прерываний или опроса. Из других примеров я создал следующие файлы: foo.h, fooConfig.х и фу.cpp показано ниже для библиотеки. Где fooConfig.h содержит конфигурацию использования экрана. Как с или без прерываний etc...

при этом я хотел бы, чтобы INO-файл основного эскиза мог переопределять настройки по умолчанию, которые были объявлены с использованием #define. В том числе в экземпляре библиотеки. Результаты показывают, что это действительно. По крайней мере, как я это делаю.

приведенный ниже код является упрощенным примером с проблемой:

definetest.Ино!--13-->

#define BAR USE_POLL
#include <foo.h>

foo test;

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.print(F("setup's defined BAR was "));
  Serial.println(BAR);

  Serial.print(F("inside foo.begin defined BAR was "));
  Serial.println(test.begin());
}

void loop() {
}

фу.h

#ifndef FOO_h
#define FOO_h

#include "FOOConfig.h"

class foo {
  public:
    int begin();
};
#endif // FOO_h

FooConfig.h

 #ifndef FOOCONFIG_h
  #define FOOCONFIG_h

  #define USE_INT      1
  #define USE_POLL     2

  #ifndef BAR
    //default to using interrupts
    #define BAR USE_INT
  #endif // BAR

#endif  // FOOCONFIG_h

фу.cpp

#include <foo.h>

int foo::begin() {
#if defined(BAR) && BAR == USE_INT
  Timer1.attachInterrupt( isr );  // error here, because of the define...
  return 1;
#elif defined(BAR) && BAR == USE_POLL
  return 2;
#endif
  return 0;
}

дает следующий серийный вывод:

setup's defined BAR was 2
inside foo.begin defined BAR was 1

где было пожелано иметь адвокатское сословие внутри foo.начните с 2, а не 1. Отмечая, что желательно, чтобы прекомпилятор решил или не опускал attachInterrupt. Не требуется зависимость и потребление ресурсов библиотеки, если она не используется. Просто хочу, чтобы это был расширенный вариант.

Я понимаю, что это лучше всего обрабатывать с файлом make или eclipse, но я пытаюсь опубликовать эту библиотеку для Arduino IDE в настоящее время в 1.0.3.

любая помощь приветствуется.

FYI, реальный и весь код здесь. https://github.com/mpflaga/Sparkfun-MP3-Player-Shield-Arduino-Library/tree/master/SFEMP3Shield

4 ответов


независимо от цепочки инструментов, программа не определяет и не должна определять, как компилируется библиотека. Ключевой концепцией библиотеки является то, что она полностью разработана, скомпилирована и упакована без наличия какой-либо программы. Существует зависимость в одну сторону: программа зависит от библиотеки-Библиотека не зависит ни от какой программы. Ключевой момент, который подчеркивает это, заключается в том, что вам не нужно распространять исходный код для использования библиотеки. Библиотека может использоваться только с заголовками и двоичными файлами (.a) загляните во все библиотеки WinAvr, которые используются.

то, что вы ищете-это как иметь несколько конфигураций вашей библиотеки. В других цепочках инструментов это легко сделать на уровне проекта, где вы можете создать любое количество выходных конфигураций. В вашем случае у вас были бы poll и int, а цепочка инструментов создавала бы две библиотеки, например:
libMySomething_int.а
libMySomething_poll.а

программы выбирают, какая конфигурация из библиотеки, которую они хотели использовать.

Как отмечали другие, Arduino IDE не будет обеспечивать эту форму сложности. Поскольку вы заявили, что намерены оставаться в этой цепочке инструментов, это решения, которые я вижу:

  1. сделайте две копии библиотеки, которые отличаются только одним #define. Это в основном вы предоставляете две конфигурации. Поскольку они отличаются незначительным количеством, будет легко WinMerge между двумя и сохранить кодовые базы синхронизированный.

  2. переосмыслить, нужно ли иметь один интерфейс для двух форм. Вам не обязательно иметь только один begin (), вы можете иметь две формы:

    void beginInt ();
    void beginPoll ();

    void getSomethingInt ();
    void getSomethingPoll ();

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

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


Arduino IDE компилирует библиотеки индивидуально, поэтому вам нужно будет передать параметр define as a-D во время компиляции. Arduino IDE в настоящее время не предоставляет возможности для вас легко сделать это. Arduino 1.5 предоставляет некоторые функциональные возможности через платы.система txt, но это, вероятно, не обеспечит необходимую гибкость.

Итак, как вы говорите, параметры редактируют файлы make в таких продуктах, как Eclipse или путем установки одного из свойств проекта" Defines " (таких как "Defines-Project") в Visual Studio Pro.

или с помощью TEENSYDUINO IDE и добавив свой собственный menu. дефс к доскам.txt


Если ваша библиотека используется только из основного эскиза
И вы можете поместить весь код в .H-файл (т. е. нет .cpp file)
Тогда вы сможете достичь того, чего хотите.

это сомнительная практика кодирования, чтобы сделать это, но это не кажется необычным в мире Arduino.

PS: чтобы быть полностью правильным, на самом деле также можно иметь .cpp-файл, но только если его компиляция полностью не зависит от переопределяемых #define.


Я не специалист по Arduino, но на первый взгляд. Ваш foo:: begin() выводит 1, потому что вы не определили "бар" в foo.cpp, поэтому препроцессоры по умолчанию. Возможно, вы можете добавить метод "конфигурации" в класс "foo". Этот метод получит аргумент с желаемой конфигурацией, поэтому вы сможете передать свой параметр define as из файла INO в экземпляр класса "foo".