Reputation: 560
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?
Upvotes: 1
Views: 1438
Reputation: 7069
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.
Upvotes: 1
Reputation: 4214
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. E.g., 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
.
Upvotes: 1