3

Say I'm working on a library^1 to which I want to add support for SD.h^2 but knowing for a fact that many microcotrollers don't support SD.h (therefore they result in compilation errors [eg. Attiny85]) I don't want to just #include <SD.h> (or even #ifndef __SD_H__ then #include <SD.h>) in Mylibrary.h and make it totally unusable for some microcontrollers. So I was wondering, is it considered ok to just add the functionality like...

// Mylibrary.h

#ifdef __SD_H__
    // Save functionality for those including `SD.h` to their `sketch.ino`
    void Mylibrary::save(String filename){
        SD.open(filename, FILE_WRITE)
        // ...
    }
#endif

...without ever including the SD.h in Mylibrary.h and hence force the user whenever he\she wants to use some SD functionallity, to just include SD.h in his\her sketch.ino? +(it sound exhausting to do something like this for every MCU, as an alternative way)

[1] (in my case this library)
[2] (in my case something related to this)

PS. The reason I'm asking is because I don't remember seeing it anywhere being used that way and I'm slightly confused as to if this is the right or wrong thing to do so

6
  • Chat-GPT says it's reasonable, but I really want to know your thoughts about how would you approach such an issue Commented Nov 5, 2023 at 20:10
  • 9
    Do not trust ChatGPT, always assume it is hallucinating. Commented Nov 6, 2023 at 6:29
  • It is bad and I have seen it :)
    – Carsten S
    Commented Nov 6, 2023 at 10:36
  • 2
    Note that identifiers that start with two underscores (or one underscore and a capital letter) are reserved: "All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use." Commented Nov 6, 2023 at 14:04
  • Since you asked ChatGPT, I asked it as well: "in C++ is it good practice to put all of your code in a .h file?" And the answer was: "No, it is not considered good practice to put all of your code in a .h (header) file in C++. In C++, code is typically organized into header files and source files, and there are specific conventions for what should go in each type of file." So no, putting all your code (declarations and definitions, that is, function prototypes and implementations) is not considered good practice. You can search other parts of the Internet for other opinions on that.
    – Nick Gammon
    Commented Nov 7, 2023 at 10:54

2 Answers 2

7

Yes, it is in general a bad practice to use include guard define to detect if the header file is included. It will work only in a header file in a compilation unit which includes the detected header file.

In Arduino all ino files of the sketch are one compilation unit. But every C or C++ file is a separate compilations unit. They would not 'see' the include guard from an include in the ino file(s).

If you want to use the include guard define, don't relay on it exclusively. Use your own define and set it if you detect the include guard. This way user can set it if theirs SD library has a different name for the include guard.

#ifdef __SD_H__
#define XY_USE_SD_LIB
#endif

#ifdef XY_USE_SD_LIB
    // Save functionality for those including `SD.h` to their `sketch.ino`
    void Mylibrary::save(String filename){
        SD.open(filename, FILE_WRITE)
        // ...
    }
#endif

I use this in my popular ArduinoOTA library here.

There is other way to detect includes and it works across compilation units, but it doesn't work on all Arduino platforms. It is the __has_include 'directive'. I use it here.

3
  • That's so cool! clever one! It's exactly what i was looking for! Thanks! Commented Nov 5, 2023 at 21:00
  • you are fast :-). please read the last paragraph for an alternative
    – Juraj
    Commented Nov 5, 2023 at 21:02
  • That's so interesting I didn't know about __has_include Commented Nov 5, 2023 at 21:05
2

I don't think this will work, however you could try it and see. Just set the board type to something that doesn't support SD.h.

My problem would be that your library is a separate compilation unit (ie. file) that would be compiled against the things you put as header files.

If your library user uses SD.h in the main .ino file, then your library (which is compiled separately) would not know about that. In other words, it wouldn't know whether or not to implement the Mylibrary::save function.

I think a fairly simple solution would be to put a define in the include file for your library, eg.

#define USE_FILE_SAVING false

Then check that in your code. You don't need a whole list of MCUs, just inform the user that if they want file saving implemented to change that one line.


For more information see How the IDE organizes things

10
  • Thanks! it's really interesting though, I also just realised that it depened if it works or not based on which board i select (eg. on arduino uno works, with espressif's ESP32 it doesn't consider that SD.h is already defined) Commented Nov 5, 2023 at 20:52
  • Wait It's so weird, it copiles just fine on both boards but with ESP32 the #ifdef __SD_H__ #pragma message("YES SD.h") #else #pragma message("NO SD.h") #endif says "No ..." Commented Nov 5, 2023 at 20:57
  • 1
    Adding SD.h to your main project is not going to affect how your library compiles. That is a separate compilation unit and does not look at what includes you have in your .ino file. See: arduino.stackexchange.com/a/13182/10794
    – Nick Gammon
    Commented Nov 6, 2023 at 6:14
  • @GiorgosXou This isn't a library, though, right? Of course it affects a compilation unit. You are showing in that GIF that putting the include inside a file in a compilation unit (that is, the file we are looking at) will of course affect how that file is compiled. But if you put that include in file A it won't affect how file B (your library) is compiled.
    – Nick Gammon
    Commented Nov 7, 2023 at 4:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.