__has_include(<SD.h>) how is it supposed to work?

KurtE

Senior Member+
I am playing around with some MTP stuff and trying to detect if the Sketch is using SD library or not... So __has_include...

But I am getting strange results.... Or at least the feel strange to me... Short version.

Suppose: For lack of anything I have a header file "XYZ.h"
That just has:
Code:
#ifndef _XYZ_H_
#define MTP_Storage_H
#if defined(__has_include) && __has_include(<SD.h>)
#pragma message " __has_include(<SD.h>"
#include <SD.h>
#endif
#else
#pragma message " NOT __has_include(<SD.h>"
#endif

Now suppose I have sketch (or library)... That has like:
Code:
#include "XYZ.h"

void setup() {
  // put your setup code here, to run once:
  while(!Serial) ;
  Serial.begin(115200);
  delay(500);
  Serial.println("Test for include file");
  #ifdef BUILTIN_SDCARD
  Serial.printf("BUILTIN_SDCARD defined %u\n", BUILTIN_SDCARD);
  #else
  Serial.println("BUILTIN_SDCARD NOT defined");
  #endif

}

void loop() {
  // put your main code here, to run repeatedly:

}
As expected on the T4.1, it
Prints out that is not defined...

However if you instead do:
Code:
#include "XYZ.h"
#include <SD.h>

void setup() {
  // put your setup code here, to run once:
  while(!Serial) ;
  Serial.begin(115200);
  delay(500);
  Serial.println("Test for include file");
  #ifdef BUILTIN_SDCARD
  Serial.printf("BUILTIN_SDCARD defined %u\n", BUILTIN_SDCARD);
  #else
  Serial.println("BUILTIN_SDCARD NOT defined");
  #endif

}

void loop() {
  // put your main code here, to run repeatedly:

}
It still prints "BUILTIN_SDCARD NOT defined"
I am confused.

However if instead you do:
Code:
#include <SD.h>
#include "XYZ.h"

void setup() {
  // put your setup code here, to run once:
  while(!Serial) ;
  Serial.begin(115200);
  delay(500);
  Serial.println("Test for include file");
  #ifdef BUILTIN_SDCARD
  Serial.printf("BUILTIN_SDCARD defined %u\n", BUILTIN_SDCARD);
  #else
  Serial.println("BUILTIN_SDCARD NOT defined");
  #endif

}

void loop() {
  // put your main code here, to run repeatedly:

}
It works as expected

So what is going on in the second case?
 
is the "__has_include("file.h") not testing if "file.h" CAN be included and not if it is included by the sketch?

gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html :
"The special operator __has_include (operand) may be used in ‘#if’ and ‘#elif’ expressions to test whether the header referenced by its operand can be included using the ‘#include’ directive. "
 
Your xyz.h looks broken.
Code:
#ifndef _XYZ_H_
#    define MTP_Storage_H
#    if defined(__has_include) && __has_include(<SD.h>)
#        pragma message " __has_include(<SD.h>"
#        include <SD.h>
#    endif
#else
#    pragma message " NOT __has_include(<SD.h>"
#endif
Maybe you meant something like
Code:
#ifndef _XYZ_H_
#    define MTP_Storage_H
#    if defined(__has_include) && __has_include(<SD.h>)
#        pragma message " __has_include(<SD.h>"
#    else
#        pragma message " NOT __has_include(<SD.h>"
#        include <SD.h>
#    endif
#endif

Anyway, this does not fix your issue.

To me it looks like the Arduino "library finder" (don't know the official name for the thing) only identifies <sd.h> as a library when #include <sd.h> appears before any other use of <sd.h>. Otherwise it interprets sd.h as just another header to include. This code shows the effect more directly:
Code:
#if defined(__has_include) && __has_include(<SD.h>)
#endif

#include <SD.h>

void setup() {
  // put your setup code here, to run once:
  while(!Serial) ;
  Serial.begin(115200);
  delay(500);
  Serial.println("Test for include file");
  #ifdef BUILTIN_SDCARD
  Serial.printf("BUILTIN_SDCARD defined %u\n", BUILTIN_SDCARD);
  #else
  Serial.println("BUILTIN_SDCARD NOT defined");
  #endif

}

void loop() {
  // put your main code here, to run repeatedly:
}

If you comment/uncomment the first two lines and look at the compile output you see that it identifies/not identifies SD.h as library. It looks like in the second case it even ignores the #include <SD.h> completely. Because, without setting up the library paths, the compiler shouldn't even find sd.h? I suspect that this is a bug in the library detection/ preparsing stuff of the IDE.

Edit: I tried this now with VisualTeensy which does not do any automatic library detection. Looks the has_include(<SD.h>) makes the compiler ignore the next #include of the same header completely.

This compiles (but doesn't include SD.h)
Code:
#if defined __has_include
#    if __has_include(<SD.h>)
#        include <SD.h>
#    endif
#endif

#include <SD.h>
....

This generates a "sd.h not found" compiler error as expected (note the changed capitalization of sd.h (Windows files are not case sensitive))
Code:
#if defined __has_include
#    if __has_include(<SD.h>)
#        include <SD.h>
#    endif
#endif

#include <sd.h>
....

Maybe that's a feature? If one checked for the existence of sd.h and if it doesn't exist the compiler ignores trying to #include the same file? Weird indeed ...
This also explains why the Arduino IDE doesn't interpret SD.h as library of course...
 
Last edited:
@luni I started a reply like yours ... if not there then #else bring it in, but did a refresh and saw the @WMXZ note that the has_include doesn't seem to perform the desired test?
 
my reply was triggered by
trying to detect if the Sketch is using SD library or not... So __has_include...
(emphasis my me)
but may KurtE was intending something different
 
Question is what does "is using SD library" actually mean? IMHO, the only thing you can detect with __has_include is, if the build sytem added the corresponding -Ipath/to/the/lib directives to the compiler call? Maybe Kurt can expand on the actual use case?
 
Sorry, I think my example may be too convoluted. let me get to the real one.

I am trying to make MTP_Teensy, automatically add support to detect if an SD card was inserted or removed from the slot...
So Suppose, in MTP_Storage.h I add:
Code:
#if defined(__has_include) && __has_include(<SD.h>)
#include <SD.h>
#endif
Which is included by MTP_Teensy.h

Now suppose in MTP_Teensy.h I have:
Code:
#if defined(__SD_H__)
  uint32_t addFilesystem(SDClass &disk, const char *diskname);
  #endif
  uint32_t addFilesystem(FS &disk, const char *diskname);

Now suppose I had a really simple SD example for MTP... I removed stuff from the current simple example 3 down to basics:
Code:
#include <SD.h>
#include <MTP_Teensy.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
//#define CS_SD 10  // Works on SPI with this CS pin
void setup()
{
  // mandatory to begin the MTP session.
  MTP.begin();

  // Add SD Card
  SD.begin(CS_SD);
  MTP.addFilesystem(SD, "SD Card");
}

void loop() {
  MTP.loop();  //This is mandatory to be placed in the loop code.
}
This builds and runs.
However this one fails to build:
Code:
#include <MTP_Teensy.h>
#include <SD.h>

#define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
//#define CS_SD 10  // Works on SPI with this CS pin
void setup()
{
  // mandatory to begin the MTP session.
  MTP.begin();

  // Add SD Card
  SD.begin(CS_SD);
  MTP.addFilesystem(SD, "SD Card");
}

void loop() {
  MTP.loop();  //This is mandatory to be placed in the loop code.
}
Code:
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino: In function 'void setup()':
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:12:3: error: 'SD' was not declared in this scope
   SD.begin(CS_SD);
   ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:4:15: error: 'BUILTIN_SDCARD' was not declared in this scope
 #define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
               ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:12:12: note: in expansion of macro 'CS_SD'
   SD.begin(CS_SD);
            ^
Using library MTP_Teensy at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy 
exit status 1
 
Kurt,
Do I understand it correctly, you wanted to detect at compile time if the user inserts/removes a uSD card?
I am trying to make MTP_Teensy, automatically add support to detect if an SD card was inserted or removed from the slot...
 
OK, I think I know what is going on...

It is Arduino's fault! (I think)

A few hints on it, with the build that works, the build output looks like:
Code:
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-tools\\1.56.53/precompile_helper" "C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53/cores/teensy4" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino" "C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -x c++-header -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53/cores/teensy4" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch/Arduino.h" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch/Arduino.h.gch"
Using previously compiled file: C:\Users\kurte\AppData\Local\Temp\arduino_build_Example_3_simple_SD.ino\pch\Arduino.h.gch
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\SD\\src" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\SdFat\\src" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\libraries\\SPI" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp.o"

...
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:84868, data:11252, headers:8324   free for files:8022020
teensy_size:    RAM1: variables:13760, code:82184, padding:16120   free for local variables:412224
teensy_size:    RAM2: variables:17504  free for malloc/new:506784
Multiple libraries were found for "SdFat.h"
 Used: C:\Users\kurte\Documents\Arduino\libraries\SdFat
 Not used: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53\libraries\SdFat
Multiple libraries were found for "SD.h"
 Used: C:\Users\kurte\Documents\Arduino\libraries\SD
 Not used: C:\arduino-1.8.19\libraries\SD
 Not used: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53\libraries\SD
Using library SD at version 2.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\SD 
Using library SdFat at version 2.1.2 in folder: C:\Users\kurte\Documents\Arduino\libraries\SdFat 
Using library SPI at version 1.0 in folder: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53\libraries\SPI 
Using library MTP_Teensy at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy 
       upload@7819620-Teensy  Uploading to board '7819620-Teensy' (Teensy 4.1)
       upload@7819620-Teensy  Triggering board reboot
       upload@7819620-Teensy  Waiting for Teensy Loader
[Finished in 24.0s]

A couple of interesting points:
1) The Using library... code says:
Code:
Using library SD at version 2.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\SD 
Using library SdFat at version 2.1.2 in folder: C:\Users\kurte\Documents\Arduino\libraries\SdFat 
Using library SPI at version 1.0 in folder: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53\libraries\SPI 
Using library MTP_Teensy at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy

2) Look at the -I in the build.
Code:
"-IC:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch"
"-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4"
"-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\SD\\src" 
"-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\SdFat\\src" 
"-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\libraries\\SPI"
"-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src"

Now look at the build that failed:
Code:
Building Sketch: ".\Example_3_simple_SD.ino"
Using board 'teensy41' from platform in folder: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53
Using core 'teensy4' from platform in folder: C:\Users\kurte\AppData\Local\Arduino15\packages\teensy\hardware\avr\1.56.53
Detecting libraries used...
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp" -o nul
Alternatives for MTP_Teensy.h: [MTP_Teensy@1.0.0]
ResolveLibrary(MTP_Teensy.h)
  -> candidates: [MTP_Teensy@1.0.0]
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp" -o nul
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src\\MTP_SD_Callbacks.cpp" -o nul
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src\\MTP_Storage.cpp" -o nul
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src\\MTP_Teensy.cpp" -o nul
Generating function prototypes...
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -E -CC -x c++ -w -g -Wall -ffunction-sections -fdata-sections -nostdlib -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\preproc\\ctags_target_for_gcc_minus_e.cpp"
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\builtin\\tools\\ctags\\5.8-arduino11/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\preproc\\ctags_target_for_gcc_minus_e.cpp"
Compiling sketch...
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-tools\\1.56.53/precompile_helper" "C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53/cores/teensy4" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino" "C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -x c++-header -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53/cores/teensy4" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch/Arduino.h" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch/Arduino.h.gch"
Using previously compiled file: C:\Users\kurte\AppData\Local\Temp\arduino_build_Example_3_simple_SD.ino\pch\Arduino.h.gch
"C:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\tools\\teensy-compile\\1.56.1/arm/bin/arm-none-eabi-g++" -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -std=gnu++14 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -D__IMXRT1062__ -DTEENSYDUINO=157 -DARDUINO=10600 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_MTPDISK -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino/pch" "-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_Example_3_simple_SD.ino\\sketch\\Example_3_simple_SD.ino.cpp.o"
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino: In function 'void setup()':
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:12:3: error: 'SD' was not declared in this scope
   SD.begin(CS_SD);
   ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:4:15: error: 'BUILTIN_SDCARD' was not declared in this scope
 #define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
               ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:12:12: note: in expansion of macro 'CS_SD'
   SD.begin(CS_SD);
            ^
Using library MTP_Teensy at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy 
exit status 1
[Finished in 11.5s]
Again hints:
1) Notice it only mentions MTP at end, it does not mention SD or SDFat
Code:
   SD.begin(CS_SD);
   ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:4:15: error: 'BUILTIN_SDCARD' was not declared in this scope
 #define CS_SD BUILTIN_SDCARD  // Works on T_3.6 and T_4.1
               ^
C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy\examples\Simplified Examples\Example_3_simple_SD\Example_3_simple_SD.ino:12:12: note: in expansion of macro 'CS_SD'
   SD.begin(CS_SD);
            ^
Using library MTP_Teensy at version 1.0.0 in folder: C:\Users\kurte\Documents\Arduino\libraries\MTP_Teensy 
exit status 1
[Finished in 11.5s]

2) command lines -Is
Code:
"-IC:\\Users\\kurte\\AppData\\Local\\Arduino15\\packages\\teensy\\hardware\\avr\\1.56.53\\cores\\teensy4" 
"-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\MTP_Teensy\\src"
So sure enough it does not find SD.h
 
Been experimenting after and during Kurt's post. The issue is definitely in MTP_Storage.h and use of the has_include. For instance (after some trial and error) I just did this:
Code:
//#if defined(__has_include) && !(__has_include(<SD.h>)
#include <SD.h>
//#endif

It compiles and runs as it should and identifies when the cards are removed.

Test 2. If I remove the specifying to use SD.h and wrap the appropriate functions in
Code:
#if defined(__SD_H__)

It compiles and runs but those functions are not visible.

Wondering to self is since MTP_Storage is (pardon my terminology here) third level its not seeing whats in the sketch only MTP_Teensy is, my thought:
Sketch ->MTP_Teensy -> MTP_Storage

Dont know - does this make sense?
 
It might work... as long as the implementation for it is within the .h file... Although maybe would still work
if the __has_include_ is not in the .h file but in the couple of .cpp files that rely on it.

Might try that.
In the mean time, I thought I would mention it to Arduino, so:
https://github.com/arduino/arduino-cli/issues/1782

Edit: I think it would build... But it would not get the functionality... I could be wrong:
That is if MTP.h was included first, then the #if defined(__SD_H__)
will be false, so then it will simply fall through and use the generic FS* version
(I think)
 
@Kurt, I don't know if you read #4.
I also thought that this is an Arduino issue first, but it turned out (see Edit in #4) that GCC is simply ignoring the #include after the __has_include. Thus Arduino never sees the #include <sd.h> which leads to not detecting the lib. At least this is how I interpreted the weird results
 
Last edited:
@Kurt, I don't know if you read #4.
I also thought that this is an Arduino issue first, but it turned out (see Edit in #4) that GCC is simply ignoring the #include after the __has_include. Thus Arduino never sees the #include <sd.h> which leads to detect the lib. At least this is how I interpreted the weird results

I read it... But it did not fully register... :eek:

On the Issue, I created on CLI... matthijskooijman commented 24 minutes ago
This is unfortunately a gcc bug, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80753

The Arduino build relies on error messages for missing includes to autodetect the libraries that are used. However, the gcc bug means that if you use _has_include() on a header that is not available (like SD.h in your breaking example), then gcc will not emit an error message when the file is later included unconditionally, so arduino-cli never finds out that SD.h is needed.

The only workaround I know about is what you already showed: Make sure SD.h is included before the _has_include(). A proper fix must be done in gcc, but there's no real movement there, unfortunately.

So I don't think this approach will work as transparent as I was hoping for.
 
Yes, __has_include works nicely for the standard use case (I'm using it for the TeensyTimerTool)

Code:
#if defined __has_include
#    if __has_include("optional.h")
#        include "optional.h"
#    else
#        include "default.h"
#endif

but not for more exotic uses
 
Back
Top