简体   繁体   中英

undefined reference to function inside ifdef block

I have the following problem:

I'm writing a collection library for a bunch of sensors to be used with a microcontroller. Meaning I take a lot of libraries for sensors and abstract and simplify them a bit in a unified library for a student project.

I use #define structures to figure out which sensors the students want to use and connected.

Example:

#define IR_SENSOR_USED

In the .h and .cpp files of the library I then use #ifdef - #endif pairs to define and declare the functions for the given sensor as well as include the given libraries.

Example from my Sensors.h file:

#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

and from my Sensors.cpp file:

#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

However, so long as I have the #ifdef in the .cpp file, I get the following error if I try to call the function in the 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

If I comment them out, the code executes fine. Another function ( setup_sensors() ), which is also in the Sensors.h and .cpp files and is not surrounded by an #ifdef works also fine.

This is my Sensors.ino sketch:

#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() {
}

What's the reason for this? (Why) does the preprocessor not execute the directives in the .cpp file properly?

This question might be an instance of an XY problem .

If you would like the users of library to pick the functionality they need it would make more sense to put declarations in separate headers. Eg, IR_sensor.h and then

#define IR_SENSOR_USED
#include "Sensors.h"

becomes just #include "IR_sensor.h" .

  • If the size of the library is or concern, splitting it into separate libraries is an option.

  • The third option is to provide the functionality as a header-only library.

Exact answer:

What's the reason for this? (Why) does the preprocessor not execute the directives in the .cpp file properly?

The most likely reason is that Sensors.cpp is unaware of #define IR_SENSOR_USED . Define is in another file that is not included.

However even if IR_SENSOR_USED would be defined in the Sensors.cpp another problem arises: re-compilation of Sensors.cpp for every possible combination of defines is necessary. Otherwise the ifdefed-code is excluded from compilation and can't be simply enabled on the client side by calling #define .

As the comments and other answer pointed out, any #define directives are only visible in the files that contain them. So having

#define IR_SENSOR_USED

in Sensors.cpp won't affect any code that's not compiled in Sensors.cpp (importantly, it will affect code that's contained in .h files that are included in Sensors.cpp after the #define . But it wouldn't affect anything contained in a different .cpp file.

More sophisticated build environments than Arduino have better and more complicated ways to deal with this problem, but the Arduino world doesn't give you a lot of tools to handle this.

What I do in the Arduino world is simply have a file called config.h which contains all the #define statements that I need project-wide. I #include "config.h" in each file that needs these values.

So in your case, you'd put your all the defines that show which devices are used in config.h and then #include "config.h" at the start of every file that depends on it.

You could even include it at the start of your Sensors.h file. I'd consider keeping the two files separate so that there would be a clear boundary between the stuff that needs to be configured and the stuff that's useful code.

I also keep any sensitive values (wifi credentials, passwords, API keys) in this file, and exclude it from code I publish on Github. In its place I include a "config-example.h" file with all the directives in it but with dummy values, so that others using the code can edit and rename it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM