Possible to make libraries dynamically dependent on included libraries?

Hi all,

I’m working on a library for working with servos in particular ways that I’d like to write to be able to use Servo.h, or the Adafruit PWM servo driver (for their boards), or both, depending on which ones are included in the build. Along those lines, I’ve been trying to do something like this in the library:

#ifndef _ADAFRUIT_PWMServoDriver_H
#ifndef Servo_h
#error You must include either the standard Servo library or the Adafruit PWM servo driver to use the ServoDriver library.
#endif
#endif

... snip ...

#ifdef _ADAFRUIT_PWMServoDriver_H
	ServoDriver(Adafruit_PWMServoDriver driver, uint8_t oePin);
#endif
#ifdef Servo_h
	ServoDriver(Servo* servos, bool activeLow = false, uint8_t oePin = 255);
#endif

The code I have using it looks like:

#include <Servo.h>
#include <ServoDriver.h>

Servo servo1;
Servo servo2;
Servo servos[] = {servo1, servo2};
ServoDriver servoDriver1(servos);

However, it seems to randomly decide to fail with one of two errors:

error: #error You must include either the standard Servo library or the Adafruit PWM servo driver to use the ServoDriver library.

or

undefined reference to `ServoDriver::ServoDriver(Servo*, bool, unsigned char)'

The 2nd one I can probably figure out, but the first one… sometimes it decides to include my library before Servo.h, and it doesn’t seem to matter at all what order I put them in the sketch.

So… is there any way to do this? I don’t want to just include Servo.h (and the Adafruit one) from my library because:
a) that would increase the binary size of sketches using my library, regardless of whether they’re using both servo libraries or not.
b) my library would require the Adafruit library, even if it’s not actually used.

Any thoughts?

So it looks like it’s

The way libraries work is they are each compiled and then later linked together with your sketch, so that their .h files are included in two different contexts, one while compiling the library's .cpp file, the other while compiling your sketch (so it can see the library declarations).

Your #error must only be seen when compiling your sketch, so it can't be in the library's .h file, either put it in your sketch or in a ,h file in the sketch's directory.

The Arduino environment happens to recompile all the libraries you use when the sketch is compiled, but that's not the normal C / C++ model (perhaps you could fiddle with the Arduino build strategy to do what you are wanting, but it doesn't feel a good solution).

Have you considered creating a compatibility shim/wrapper class to make one of the libraries look like the other? Then you don't need to add conditional code in the sketch other than for the top level #includes.

Yeah, I realize "normal" C/C++ environments compile the libraries separately and link them in. I also knew the Arduino IDE seemed to be recompiling them when I changed the sketch... but I guess what I'm trying to do isn't possible. :/

I'm not sure the best way to do the shim/wrapper you're talking about, given the design of what I'm trying to do.

What I was trying to do was create two classes, ServoDriver and ServoChannel. ServoChannel would control an individual servo, with variable speed movement, acceleration/decelleration control, etc, using an instance of ServoDriver to actually move the servo. ServoDriver itself would either use Servo, or the Adafruit servo driver, depending which constructor was called.

// Example setup using Adafruit driver
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
ServoDriver driver(pwm);

// Example setup using Servo.h
Servo servo1;
Servo servo2;
// usual servo attachment stuff goes here
Servo servos[] = {servo1, servo2};
ServoDriver driver(servos);

// Example usage (regardless of driver)
ServoChannel leftServo = ServoChannel(driver, 0);
ServoChannel rightServo = ServoChannel(driver, 1);
leftmoveServo(100, 10); // position, speed

Various optional constructor params would define min/max pulse lengths, initial position, allow for safely resetting (move servos back to initial position, slowly)

I was trying to use ifdefs to exclude code that depended on one or the other if it wasn't being used.

I can see 2 ways of doing more or less what I was trying to do: 1) Make the conditional compiliation dependent on defines in the library itself instead. This which means users of the library will have to edit it depending on what hardware they're using.

2) Use polymorphism, and write 3 ServoDriver classes: a base class, and two instances which extend it. ServoChannel would then be calling virtual methods on ServoDriver, so would be invoking them from whichever subclass it was given.

2 is certainly the solution I'd go for outside of the microcontroller world, I'm not sure how appropriate it is here. I don't know what kind of overhead it would add.