I recently posted this as a possible bug in the Arduino forum (https://forum.arduino.cc/index.php?topic=656968), but I suspect they are going to "ho-hum, so what?" it because it goes outside of their standard rules for Arduino library organisation. However, I still want to understand why it is failing and I suspect this is the only place I will get decent and/or definitive answers:
( For the record, an arduino library normally sits in a folder which has a library.properties metadata "manifest" and a src folder containing all the files. Their build system automatically compiles (and links!) all the .cpp files in src - whether they are used or not. Obviously in 99% of cases all of them are used /needed, but for various reasons...)
BEGIN INCLUSION
Version 1.8.10 ESP8266 core 2.6.2
Before we start, I have written several several successful libraries and I am familiar with the "standard" way of doing things. I say this because what follows may be considered "non-standard" although it is syntactically valid and in all but one instance, compiles and runs successfully. I came across it by accident while experimenting to try and get round the restriction of compiling everything in src folder whether you want it or not
In the failing instance, I get a compilation error that I have never seen before,don't understand and makes no sense; but worse: it should not be happening at all as it is a) valid code b) functionally identical to the working cases - and compiles cleanly when not in a separate folder as is the current case...
The fundamental problem then is that the only significant difference between failure or success of this piece of valid C++ code is its physical location in the file system, which baffles me.
First the sketch:
#include <H4P_WiFiX.h>
void f1(){}
void f2(){}
/*
* H4P_WiFi has defaults of [](){}, [](){}
*/
//H4P_WiFi h4wifi(f1,f2); // compiles OK
//H4P_WiFi h4wifi([](){},f2); // compiles OK
//H4P_WiFi h4wifi(f1,[](){}); // compiles OK
//H4P_WiFi h4wifi(f1); // compiles OK
//H4P_WiFi h4wifi([](){},[](){}); // compiles OK
//H4P_WiFi h4wifi([](){}); // compiles OK
H4P_WiFi h4wifi; // using BOTH defaults (and ONLY that case), fails with the "helpful":
/*
C:\Users\phil\AppData\Local\Temp\ccnwDwvr.s: Assembler messages:
C:\Users\phil\AppData\Local\Temp\ccnwDwvr.s:21: Error: symbol `_ZNSt17_Function_handlerIFvvEZN8H4P_WiFiC1ESt8functionIS0_ES3_Ed_NUlvE_EE9_M_invokeERKSt9_Any_data' is already defined
C:\Users\phil\AppData\Local\Temp\ccnwDwvr.s:97: Error: symbol `_ZNSt14_Function_base13_Base_managerIZN8H4P_WiFiC1ESt8functionIFvvEES4_Ed_NUlvE_EE10_M_managerERSt9_Any_dataRKS7_St18_Manager_operation' is already defined
*/
void setup() {}
void loop() {}
Now the bizarre stuff: The "odd" folder structure is:
libraries/H4Pwtf
|--optional
|
|--H4P_WiFi.cpp
|--H4P_WiFi.h
|--H4Plugins.h
!--src
|
|--H4P_WiFiX,h
|--H4Plugins.cpp
library.properties
src/H4P_WiFiX.h
#ifndef H4P_WiFi2_H
#define H4P_WiFi2_H
// Yes, I know, I know! See above - it's valid even though weird
#include"../optional/H4P_WiFi.cpp"
#endif
src/H4Plugins.cpp
#include"../optional/H4Plugins.h"
H4PluginService::H4PluginService(H4P_FN_VOID onConnect,H4P_FN_VOID onDisconnect){}
optional/H4P_Plugins.h
#ifndef H4P_HO
#define H4P_HO
#include<functional>
using H4P_FN_VOID = std::function<void()>;
class H4Plugin {};
class H4PluginService: public H4Plugin {
public:
H4PluginService(H4P_FN_VOID onConnect=[](){},H4P_FN_VOID onDisconnect=[](){});
};
#endif // H4P_HO
optional/H4P_WiFi.h
#ifndef H4P_WiFi_HO
#define H4P_WiFi_HO
#include"H4Plugins.h"
class H4P_WiFi: public H4PluginService{
public:
H4P_WiFi(H4P_FN_VOID onConnect=[](){},H4P_FN_VOID onDisconnect=[](){});
};
#endif // H4P_WiFi_HO
optional/H4P_WiFi.cpp
#include"H4P_WiFi.h"
H4P_WiFi::H4P_WiFi(H4P_FN_VOID onC,H4P_FN_VOID onD): H4PluginService(onC,onD){}
Needless to say, if I move this all to src and edit the "weird" includes back to < > variants instead of " " versions and don't do the bizarre inclusion of .cpp (obvs because it will get compiled anyway by virtue of just "being there") then the line that shouldn't fail doesn't fail and everything compiles and runs 100% as expected.
But that's not the point: It looks to me as if the build system is including something twice when it shouldn't be...and I just cannot fathom that error! Any ideas?
END INCLUSION
So, overflowers: can anyone explain the bug and when it only happens when both defaults are used?
SOLVED thanks to "walnut". A residual issue is that he compiler bug only manifests when the two-identical-lambdas-as-defaults function is defined out-of-class. I moved it back inside, recompiled using my much-derided (but working) non-standard file organisation and: Bingo! Code now running exactly as expected and compiling in only #included modules. I'm a happy bunny. Thanks to others who contributed also. Case closed. +1 to stackoverflow