Conditional library inclusion

My question is somewhat related to this previous question.
I am writing a library that contains some #include lines. I want to make these include lines conditional on the type of sketch. My goal is to use the same library with two SoftwareSerial "flavors".

In lib.h, I have

#include "SoftwareSerial.h" // notice this is a local file in the same folder as "lib.h", "lib.cpp"
SoftwareSerial serial = SoftwareSerial(A0);
void writeDataString(char* s, DateTime now);
long serialSpeed = 57600;
bool serialOn = false;
void setSerial(bool b);

In lib.cpp, I then make use of SoftwareSerial to send messages.

If possible, I would like to have the option of using version_a.h and version_b.h of the library (different small tweaks to both .h and .cpp SoftwareSerial files) without modifying the lib.h or having duplicate files.

Is it possible to pass a flag of any kind to my library from the .ino? If so, how could it be implemented and where should the version_a.h, version_b.h live?
Right now, we are copying the different flavors of the lib (let's say lib_a.h and lib_b.h) and having the proper SoftwareSerial in the same folder as the lib, and the .ino.
That means we are including the "local" lib each time, it's not the best for reproducibility or tractability.
Ideally, I would like to have the lib.h and lib.cpp unified and able to handle the slightly different definitions of the two SoftwareSerial flavors.

A #include tells the compiler to put the text of that file right there. That is before the compiler starts compiling. Anything you do before the #include can be used.

Another thing at text level (before compiling) is the #ifdef directives : Conditional inclusion - cppreference.com

There are two ways:

  1. Make a define or not. You can test if the define exists with #ifdef MYSERIALPORT
  2. Give a define a number. Test what number the define has #if MYSERIALPORT == 1

A common way of doing this would be to #define something (or not) in your .ino file before including your .h file
.ino

#define USE_VERSION_B
#include "lib.h"
...
void setup() {
...

and then in lib.h

#ifdef USE_VERSION_B
// define everything you need to
#else
// define regular stuff here
#endif

Note: This #define does not carry over to your .cpp file. That file is compiled separately from your .ino file and then they are linked together. If this creates a problem for your library, you can either insert all your code into the .h file (some libraries do this) or have some sort of library .begin() function where you would pass an argument to do option A or B.

This is kind of the general idea I have, but could we please clarify a few things?
Desired sketches would use the installed version of the library.

#include <lib.h>
// instead of #include "lib.h"

I guess the proposed fix for lib.h will make it work with <lib.h> and not the local file in the .ino folder, right?

Using the #define USE_VERSION_B sound easy enough, using the #ifdef is the part that confuses me a bit.

In lib.h:

#ifdef USE_VERSION_B
// how to load SoftwareSerial_version_b.h ?
// like this? if so, what should be the location of "SoftwareSerial_version_b.h" and "SoftwareSerial_version_a.h" 
#include "SoftwareSerial_version_b.h"  
...
#else
#endif

What is confusing about that statement? It is a compile time if/then/else...

#ifdef USE_SOFTWARE_SERIAL
#include "SoftwareSerial.h"
SoftwareSerial serial = SoftwareSerial(A0);
#define myLibSerial serial
#else
#define myLibSerial Serial
#endif

void writeDataString( char* s, DateTime now) {
  myLibSerial.print(s);
  myLibSerial.println(now);
}

Maybe I didn't express properly, I'm not confused about the code.
I am confused about where files are located.

Because it's not the same to do

#include "SoftwareSerial.h"

Than

#include <SoftwareSerial.h>

My question is, where should I keep my SoftwareSerial files and whether it's possible to avoid using them locally like I have been doing. I would much prefer having just one copy of each flavor that installs with my lib.h lib.cpp files. Right now, the only way to get the desired behavior is by having a folder that looks like

version a

whatever_a.ino
lib.cpp
lib.h
SoftwareSerial.h // mind this is different from <SoftwareSerial.h>
SoftwareSerial.cpp // mind this is different from <SoftwareSerial.cpp>

version b

whatever_b.ino
lib.cpp
lib.h
SoftwareSerial.h // mind this is different from version a
SoftwareSerial.cpp //mind this is different from version a

I would rather have a folder that looks

whatever_a.ino

With

#define USE_VERSION_A
#include <lib.h>

Let's take a step back... why different versions of SoftwareSerial.h and SoftwareSerial.cpp, each unique to the sketch?

lib.h and lib.cpp is the library we use to control devices we use for scientific research. Each device has a featherboard that will be running the library. Different groups are extending their use to be able to communicate to other boards via serial using A0 because that's the only pin available to do so (e.g., we developed integration with a raspberry pi).
Different groups have their solutions working quite nicely for our intended standards, but we had to tweak SoftwareSerial a bit, which is also not included in lib. The differences for different device communication purposes are not large enough that merit splitting into two libraries (we would like to stay as one, keep the code base unified as it has been so far). However, we now have different flavors of SoftwareSerial.h and SoftwareSerial.cpp to communicate with different boards.
This happened because development was done in parallel and trying to make it work independently might have created this issue.
We could try to make a unified version that handles both use cases, although there are conflicts and it would be developing again (when we have functional "independent" products).
If possible, we would like to push an update to the library that just asks users to modify minimal things in their sketches. Telling them "put these 4 files in all the folders with your .ino and forget about using the <lib.h> that you actually installed" is not what we are aiming for.

sounds like a familiar problem :slight_smile:

If the SoftwareSerial library is outside your lib, why not let others control their own version? And you just control lib? You could add a function to your library that passes in a reference or pointer to a Stream object and the library just uses that. Others who use the library must declare SoftwareSerial (of any flavor) or a hardware serial port and pass that in within setup()?

#include "SoftwareSerial.h"  // local, modified copy for project X
SoftwareSerial serial = SoftwareSerial(A0);
#include <lib.h>
...
void setup() {
  libSetSerial( &serial );
  ...
}

Then, inside your library, you have a global

Stream *libSerial;
...
void libSetSerial( Stream *s) {
  libSerial = s;
}

void writeDataString ( char* s, DateTime now) {
  if ( libSerial ) {
    libSerial->print(s);
    libSerial->println(now);
  }
}

Sounds like something we can explore. Thank you.