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

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

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

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

definetest.ino

#define BAR USE_POLL
#include <foo.h>
foo test;
void setup() {
 Serial.begin(115200);
 delay(1000);
 Serial.print(F("setup defined BAR was "));
 Serial.println(BAR);
 Serial.print(F("inside foo.begin defined BAR was "));
 Serial.println(test.begin());
}
void loop() {
}
</foo.h>

foo.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

foo.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;
}
</foo.h>

Устанавливает следующий последовательный выход:

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

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

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

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

FYI, настоящий и весь код здесь. https://github.com/mpflaga/Sparkfun-MP3-Player-Shield-*******-Library/tree/master/SFEMP3Shield

4 ответа

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

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

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

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

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

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

    void beginInt(); void beginPoll();

    void getSomethingInt(); void getSomethingPoll();

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

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


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

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

Или с помощью IDE TeensyDuino и добавления собственных menu. defs в board.txt


Если ваша библиотека используется ТОЛЬКО из основного эскиза И вы можете жить с помещением всего вашего кода в файл .h(т.е. Файл .cpp) ТОГДА вы можете достичь того, чего хотите.

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

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


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

licensed under cc by-sa 3.0 with attribution.