use #if __has_include - for something like user_defs.h in Arduino sketch?

Status
Not open for further replies.

KurtE

Senior Member+
Sorry for separate thread for this, have eluded to it in a few threads.

As I have mentioned in the ILI9488_t3 thread, would like to allow the library to compile a couple of different ways, especially for the T4.1

Right now it can compile differently if you uncomment the line: //#define ENABLE_EXT_DMA_UPDATES // This is only valid for those T4.1 which have external memory.
in the header file. In which case the frame buffer compiles for 32 bits per pixel in extended memory.

BUT I can imagine you may not want this for all of your T4.1s.

So I was thinking about maybe trying to set up a sketch specific include that says, I want that option and hopefully have the library compile see that file was defined and load it and have whatever specific options the user wants for that sketch.

So I thought I would try: #if __has_include

First attempt was to define a file as part of the sketch: like user_options.h
I do a #include of it as part of my sketch and it does not find or use it...

Code:
#if __has_include(<user_options.h>)
#  include <user_options.h>
#pragma message "ILI9488_t3h - included user_options.h"
#endif
Probably because the file gets copied to some other location.

So then thought maybe add a new header file to the library like:
Code:
#if __has_include(<ILI9488_enable_extmem.h>)
#  include <ILI9488_enable_extmem.h>
#pragma message "ILI9488_t3h - included ILI9488_enable_extmem.h"
#endif
And it always finds it.

One option that appears to work, is a create a new bogus library with this header file in it.
In my case I created a directory in the <sketch directory>/libraries/ILI9488_options
And create the file: ILI9488_enable_extmem.h

And then in my sketch I added that:
Code:
#include "SPI.h"
#  include <ILI9488_enable_extmem.h>
#include "ILI9488_t3.h"

And the compile appears to work with it:
Code:
"C:\\arduino-1.8.12\\hardware\\teensy/../tools/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=152 -DARDUINO=10812 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IC:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_4969/pch" "-IC:\\arduino-1.8.12\\hardware\\teensy\\avr\\cores\\teensy4" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\SPI" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\ILI9488_options" "-IC:\\Users\\kurte\\Documents\\Arduino\\libraries\\ILI9488_t3\\src" "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_4969\\sketch\\Configure_test_graphicstest9488.ino.cpp" -o "C:\\Users\\kurte\\AppData\\Local\\Temp\\arduino_build_4969\\sketch\\Configure_test_graphicstest9488.ino.cpp.o"
In file included from C:\Users\kurte\Documents\Arduino\Teensy Tests\Configure_test_graphicstest9488\Configure_test_graphicstest9488.ino:17:0:

C:\Users\kurte\Documents\Arduino\libraries\ILI9488_t3\src/ILI9488_t3.h:53:17: note: #pragma message: ILI9488_t3h - included user_options.h

 #pragma message "ILI9488_t3h - included user_options.h"

                 ^
But was sort of wondering if there is a cleaner way?
 
But was sort of wondering if there is a cleaner way?

In the TeensyTimerTool I'm using this config.h

config.h:
Code:
#pragma once

#if __has_include("userConfig.h")
    #include "userConfig.h"
#else
    #include "defaultConfig.h"
#endif

If the user wants to override settings he copies the defaultConfig.h into the sketch folder and changes settings as he needs. All library code only includes config.h but depending on file presence it actually gets the information from the default- or the user config.

Please note: Of course, the sources of already compiled files are not "touched" by generating a userConfig.h. Thus, the build system has no chance to recompile them automatically -> You need to do a clean build once after copying the defaultConfig.h into your sketch directory. After that one-time clean recompile you can change settings in your userConfig as usual. Not a big deal but needs to be explained to your users.
 
Last edited:
@luni - This doesn't seem to work with IDE build - it doesn't seem to include sketch directory in search path - is that part of the build as done there?

Code:
T:\arduino-1.8.12\arduino-builder -dump-prefs -logger=machine -hardware T:\arduino-1.8.12\hardware -hardware C:\Users\Tim\AppData\Local\Arduino15\packages -hardware T:\tCode\hardware -tools T:\arduino-1.8.12\tools-builder -tools T:\arduino-1.8.12\hardware\tools\avr -tools C:\Users\Tim\AppData\Local\Arduino15\packages -built-in-libraries T:\arduino-1.8.12\libraries -libraries T:\tCode\libraries -fqbn=teensy:avr:teensy41:usb=serial,speed=600,opt=o2std,keys=en-us -ide-version=10812 -build-path T:\TEMP\arduino_build_769121 -warnings=more -build-cache T:\TEMP\arduino_cache_750735 -verbose T:\tCode\libraries\TeensyTimerTool\examples\HelloOneShot\HelloOneShot.ino
T:\arduino-1.8.12\arduino-builder -compile -logger=machine -hardware T:\arduino-1.8.12\hardware -hardware C:\Users\Tim\AppData\Local\Arduino15\packages -hardware T:\tCode\hardware -tools T:\arduino-1.8.12\tools-builder -tools T:\arduino-1.8.12\hardware\tools\avr -tools C:\Users\Tim\AppData\Local\Arduino15\packages -built-in-libraries T:\arduino-1.8.12\libraries -libraries T:\tCode\libraries -fqbn=teensy:avr:teensy41:usb=serial,speed=600,opt=o2std,keys=en-us -ide-version=10812 -build-path T:\TEMP\arduino_build_769121 -warnings=more -build-cache T:\TEMP\arduino_cache_750735 -verbose T:\tCode\libraries\TeensyTimerTool\examples\HelloOneShot\HelloOneShot.ino
Using board 'teensy41' from platform in folder: T:\arduino-1.8.12\hardware\teensy\avr
Using core 'teensy4' from platform in folder: T:\arduino-1.8.12\hardware\teensy\avr
Detecting libraries used...
"T:\\arduino-1.8.12\\hardware\\teensy/../tools/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=152 -DARDUINO=10812 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IT:\\arduino-1.8.12\\hardware\\teensy\\avr\\cores\\teensy4" "T:\\TEMP\\arduino_build_769121\\sketch\\HelloOneShot.ino.cpp" -o nul
Alternatives for TeensyTimerTool.h: [TeensyTimerTool@0.1.8]
ResolveLibrary(TeensyTimerTool.h)
  -> candidates: [TeensyTimerTool@0.1.8]
"T:\\arduino-1.8.12\\hardware\\teensy/../tools/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=152 -DARDUINO=10812 -DARDUINO_TEENSY41 -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-IT:\\arduino-1.8.12\\hardware\\teensy\\avr\\cores\\teensy4" "-IT:\\tCode\\libraries\\TeensyTimerTool\\src" "T:\\TEMP\\arduino_build_769121\\sketch\\HelloOneShot.ino.cpp" -o nul
Alternatives for defaultConfig.h: []
ResolveLibrary(defaultConfig.h)
  -> candidates: []
[B][COLOR="#FF0000"]In file included from T:\tCode\libraries\TeensyTimerTool\src/TeensyTimerTool.h:3:0,

                 from T:\tCode\libraries\TeensyTimerTool\examples\HelloOneShot\HelloOneShot.ino:2:

T:\tCode\libraries\TeensyTimerTool\src/config.h:6:31: fatal error: defaultConfig.h: No such file or directory[/COLOR][/B]

compilation terminated.

Using library TeensyTimerTool at version 0.1.8 in folder: T:\tCode\libraries\TeensyTimerTool 
Error compiling for board Teensy 4.1.
 
The errors you get are strange, did you remove the defaultConfig.h? If so, the idea is to copy it, not to move it. (BTW: still need to adjust some defines for the T4.1)

However, you are right, the Arduino Builder does not include the sketch folder to the search path which renders the pattern useless. When I originally tested the pattern I didn't use if from within a library, then it works of course... What a pitty!
 
Since it won't work either way … pretend I did the right thing :)

Actually 'reading' now I see that was not what I did - but I was expecting it to fail … so it worked as expected :)
 
I know that doesn't help but: the pattern works perfectly with PlatformIO and of course with VisualTeensy. I try to log an issue to ArduinoBuilder maybe they fix that (doubt it...)
 
Last edited:
That would be a cool feature - but since I keep the IDE active to play along with Paul - and then use my editor of choice and TSET to trigger CMDline build with TyComm I find it works for me seamlessly between the two without juggling another thing to learn and maintain for how it is working.
 
Interesting to see if they have a way. It seems I found a simple way ... though looking at boards.txt and platform.txt no other copies or ways to move the file in the same way are apparent.

For testing I am using : T:\tCode\libraries\TeensyTimerTool\examples\HelloOneShot\HelloOneShot.ino

{ @FrankB , @mjs513, @KurtE, @others? } :: Though TSET has to be used without TyComm for uploading to T_4.1 until it gets a working update - I've been using default IDE and Teensy.exe - it gets the HEX name then requires a button or Ctrl+B in TyComm to cause the upload when it owns the USB_Serial port.

I added two bold lines ( after green lines ) to my TSET batch file [TSet.cmd2] to copy { to precompile Header where Arduino.h seems to reside } userConfig.h to that folder:
Code:
[I][COLOR="#00FF00"]if not exist %temp1% mkdir %temp1%
if not exist %temp2% mkdir %temp2%[/COLOR]
[/I]
[B]if not exist %temp1%\pch mkdir %temp1%\pch
if exist userConfig.h copy userConfig.h %temp1%\pch[/B]

Then before with this in defaultConfig.h:
Code:
#pragma once

#include "boardDef.h"
namespace TeensyTimerTool
{
[B][COLOR="#FF0000"]xx[/COLOR][/B]

//…

I got an error on the "xx" as expected:
Code:
In file included from T:\tCode\libraries\TeensyTimerTool\src/config.h:6:0,
                 from T:\tCode\libraries\TeensyTimerTool\src/TeensyTimerTool.h:3,
                 from T:\tCode\libraries\TeensyTimerTool\examples\HelloOneShot\HelloOneShot.ino:2:

defaultConfig.h:6: error: '[B][COLOR="#FF0000"]xx[/COLOR][/B]' does not name a type
 [B][COLOR="#FF0000"]xx[/COLOR][/B]

With the above edit to Compile.cmd used to build, there was no error. It found and used the PCH\userConfig.h as needed when building the "libraries\TeensyTimerTool" !!!!!

When I go to the IDE and 'Upload' build it faults still with the above error. Then in the sketch folder if I rename userConfig.h to XuserConfig.h - the error returns as expected.

So on Windows using TSET this pattern seems to work with a simple edit to TSET building the Compile.cmd file:
Code:
#pragma once

#if __has_include("userConfig.h")
    #include "userConfig.h"
#else
    #include "defaultConfig.h"
#endif
 
Last edited:
This sort of user config header has been proposed many times over Arduino's long history. They've consistently rejected it. Maybe this time will be different, but I doubt it.

Arduino specifically designed their system to not support this sort of external header file config of the libraries. It's not merely an artifact of how they created the include paths. It's a explicit choice towards their design goal of API simplicity.

FWIW, the other consistent theme is everyone who has proposed this and been rejected hasn't accepted Arduino's rationale behind these decisions. They're used to hearing arguments & rants. It never works. Don't recommend going there when they reject this proposal.
 
Just did a quick prove of principle experiment by adding the path to the build folder
Code:
-IC:\\Users\\lutz\\AppData\\Local\\Temp\\arduino_build_422957\\sketch
to build.flags.common in boards.txt which fixes it for the Arduino IDE (and probably all IDEs relying on the builder -> TSET). Maybe there is a variable for the build path which can be used instead?
 
I could see it as being 'Magic Sauce' - one more file name to learn and use or avoid for the user that doesn't know/want to do prototypes... etc.

Speaking of Magic - how is the Arduino PRO IDE coming along? Is that a FREE tool also? When I looked at Beta web notes for it I was not sure it wasn't going to be a fee required option?

As shown above - with FrankB's trigger of the IDE from CMDLine on Windows creation - that creates the TEMP dirs and starts the IDE building - All that was required was make sure %temp%\pch exists and then put the userConfig.h there where I found Arduino.h and it was picked up as needed building the @LUNI LIBRARY.
 
@LUNI - CROSSPOST -

I SAW (caps lock) this in platform.txt:
{build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} "-I{runtime.platform.path}/cores/{build.core}" "{build.path}/pch/Arduino.h" -o "{build.path}/pch/Arduino.h.gch"

That showed Arduino.h in :: {build.path}/pch

But that is moved around 'behind the scenes' with the build tools?
 
That showed Arduino.h in :: {build.path}/pch

Yay... adding "-I{build.path}/sketch" before {includes} in platform.txt works.

Code:
## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{build.toolchain}{build.command.g++}" -c {build.flags.optimize} {build.flags.common} {build.flags.dep} {build.flags.cpp} {build.flags.cpu} {build.flags.defs} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DF_CPU={build.fcpu} -D{build.usbtype} -DLAYOUT_{build.keylayout} "-I{build.path}/pch" "-I{build.path}/sketch" {includes} "{source_file}" -o "{object_file}"


@Paul: any chance you change platform.txt? :)
 
...if that gets added, the "defs.h" could be added, too... :confused:

But I don't see a realistic chance - it would be against Arduino compatibility.
..But: Do we need compatibility in this case?
 
@Paul: any chance you change platform.txt? :)

For 1.52, we're much too close to release to make this sort of build system change which could have unintended consequence.

Farther in the future, maybe.

First let's see what Arduino says on that issue. If (when) Arduino rejects it, that's not necessarily the end of story here. But it certainly is something to consider.
 
Thought so.

I'll leave it in for the time being and see if something strange happens during normal work.
 
@defragster = This is what I get for sleeping and not checking earlier I missed al the fun with this discussion.
 
As I mentioned yesterday, in the first post, I did get it to sort of work, by creating a new logical library, and put the header file __has_include is looking for into that library and then have the sketch include that header file. This will have the Arduino builder find the file and add that directory to the includes list and it worked.

But wondered if there as a cleaner approach. And yes I know use a different build system ;)
 
@KurtE - not sure there is really a cleaner way to be honest. The has include is the cleanest I think but the IDE seems to be blocking that from what I am reading in the thread without a change to a compile option. As I am typing this I did have a thought - not sure if it would work, but what if in the config.h file in the sketch you have a define for use_config_file that the Lib can see and if its defined then then the config.h can be used or maybe pass it in the begin - just thoughts out loud.
 
IDE seems to be blocking that
I wouldn't say its blocking it, the builder simply doesn't search in the sketch folder for header files. Therefore, if your library is compiled it doesn't see any user config header located in the sketch so the __has_include will never be true...

@Kurt: I don't quite understand your pattern. If I want to change some option in your user config I need to do the change in your bogus library right? So what is the advantage over doing the change in the original library in the first place? Or is this meant for exactly one option which I can activate by including the lib or not?
 
@mjs513 - Good Morning,

I believe Library files unfortunately, do not see anything the sketch defines, so I am not sure it would work...

For my specific first case I think I may try to leave in the option I added, but also for now add in another __has_include that you mentioned in other thread...
That of course may not work long term if the extram stuff gets moved into core...

But I currently have at the start of ILI9488_t3.h file:
Code:
#ifndef _ILI9488_t3H_
#define _ILI9488_t3H_
#if defined __has_include
#if __has_include(<extRAM_t4.h>) && defined(ARDUINO_TEENSY41)
//#include <extRAM_t4.h>
#define ENABLE_EXT_DMA_UPDATES  // This is only valid for those T4.1 which have external memory. 
#pragma message "ILI9488_t3h -  extRAM_T4 enabled EXT DMA frame buffer"
#endif

#if __has_include(<ILI9488_sketch_options.h>)
#  include <ILI9488_sketch_options.h>
#pragma message "ILI9488_t3h - included ILI9488_sketch_options.h"
#endif
#endif
And verified that with the sketch that I have the moved the ILI9488_t3 buffer to extended memory the message was printed that told me the option was configured in.

Without the includes neither of the messages printed. I may issue a PR (minus the messages), as I don't think it will hurt anything and does add the option in that for T4 you could define an external library directory and setup configuration to use 8 bit frame buffer instead of 16 for a specific sketch...
 
@luni - Two things
a) Wondered if it would work and it did :D

b) Original issue - I hate users needing to edit some library for some specific configuration needed for some specific sketch/hardware and then get screwed as it impacted their other projects as well.

The main thing I was wanting to fix here is for the library I mentioned in previous post and currently can fix the issue by simply detecting if external memory was configured into the sketch or not.

Thanks
 
Status
Not open for further replies.
Back
Top