неопределенная ссылка на функцию внутри блока ifdef - PullRequest
0 голосов
/ 06 марта 2019

У меня следующая проблема:

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

Я использую #define структуры, чтобы выяснить, какие датчики студенты хотят использовать и подключить.

Пример:

#define IR_SENSOR_USED

В файлах библиотеки .h и .cpp я затем использую пары #ifdef - #endif для определения и объявления функций для данного датчика, а также для включения указанных библиотек.

Пример из моего Sensors.h файла:

#ifdef IR_SENSOR_USED
  #include "SparkFun_GridEYE_AMG88/src/SparkFun_GridEYE_Arduino_Library.h"
  extern GridEYE grideye;
  void setup_ir_sensor();
  void read_ir_sensor();
  void enable_ir_interrupt(float lower, float upper, float hysteresis);
  void disable_ir_interrupt();
#endif

и из моего Sensors.cpp файла:

#ifdef IR_SENSOR_USED
void setup_ir_sensor() {
  Wire.begin(16, 17, 0x69);
  grideye.begin(0x69, Wire);
}

void read_ir_sensor() {
  for (int i = 0; i <= 64; i++) {
    sensor_values.ir_pixel_temp[i] = grideye.getPixelTemperature(i);
  }
  sensor_values.ir_device_temp = grideye.getDeviceTemperature();
}

void enable_ir_interrupt(float lower, float upper, float hysteresis) {...}

void disable_ir_interrupt() {...}
#endif

Однако, пока у меня есть #ifdef в файле .cpp, я получаю следующую ошибку, если пытаюсь вызвать функцию в setup():

sketch/Sensors.ino.cpp.o:(.literal._Z5setupv+0xc): undefined reference to `read_ir_sensor()'
sketch/Sensors.ino.cpp.o: In function `setup()':
.../Sensors/Sensors.ino:112: undefined reference to `read_ir_sensor()'
collect2: error: ld returned 1 exit status
exit status 1

Если я их закомментирую, код выполняется нормально. Другая функция (setup_sensors()), которая также находится в файлах Sensors.h и .cpp и не окружена #ifdef, также работает нормально.

Это мой Sensors.ino набросок:

#define IR_SENSOR_USED
//#define COLOR_SENSOR_USED
//#define ENV_SENSOR_USED
//#define TEMP_SENSOR_USED

#include "Sensors.h"

void setup() {
  sensor_setup();

  read_ir_sensor();
}

void loop() {
}

В чем причина? (Почему) препроцессор не выполняет директивы в файле .cpp должным образом?

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Как отмечалось в комментариях и других ответах, любые директивы #define видны только в тех файлах, которые их содержат.Таким образом, наличие

#define IR_SENSOR_USED

в Sensors.cpp не повлияет на код, не скомпилированный в Sensors.cpp (важно, что это повлияет на код, содержащийся в .h файлах, включенных в Sensors.cpp после#define. Но это не повлияет ни на что, содержащееся в другом файле .cpp.

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

В мире Arduino я просто делаю файл с именем config.h, который содержит все операторы #define, которые мне нужны для всего проекта.#include "config.h" в каждом файле, для которого нужны эти значения.

Таким образом, в вашем случае вы должны указать все определения, которые показывают, какие устройства используются в config.h, а затем #include "config.h" в начале каждогофайл, который зависит от него.

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

Я также сохраняю в этом файле любые конфиденциальные значения (учетные данные Wi-Fi, пароли, ключи API) и исключаю его из кода, публикуемого на Github.Вместо этого я включаю файл «config-example.h» со всеми директивами в нем, но с фиктивными значениями, чтобы другие, использующие код, могли редактировать и переименовывать его.

1 голос
/ 06 марта 2019

Этот вопрос может быть примером проблемы XY .

Если вы хотите, чтобы пользователи библиотеки выбирали необходимую им функциональность, было бы разумнее помещать объявления в отдельные заголовки. Например, IR_sensor.h, а затем

#define IR_SENSOR_USED
#include "Sensors.h"

становится просто #include "IR_sensor.h".

  • Если размер библиотеки имеет значение или имеет значение, можно разделить ее на отдельные библиотеки.

  • Третий вариант - предоставить функциональность в виде библиотеки только для заголовков .

Точный ответ:

В чем причина этого? (Почему) препроцессор не выполняется директивы в файле .cpp правильно?

Наиболее вероятная причина в том, что Sensors.cpp не знает #define IR_SENSOR_USED. Определить в другом файле, который не включен.

Однако, даже если IR_SENSOR_USED будет определено в Sensors.cpp, возникает другая проблема: необходима перекомпиляция Sensors.cpp для каждой возможной комбинации определений. В противном случае код ifdefed исключается из компиляции и не может быть просто включен на стороне клиента путем вызова #define.

...