Including a C++ Library

I’m working on getting my library for modulo ready to use in Particle Build and Particle Dev. I’ve run into a problem, though. It seems that my library only compiles when I include it on the very first line of the .ino file.

If there is anything else (even just whitespace) before the include for my library, then the compile fails with errors indicating that classes from by the library are not defined.

I know there’s a pre-processor for .ino files, so perhaps it’s an issue with that? Is there any way to view the output of the preprocessor? What exactly does the preprocessor do and does it do anything special with the first line?

In particle dev, if I name the file with a .cpp extension it compiles just fine. In particle build if I put all the code in a .cpp file that works too. In build, however, it doesn’t look like it’s possible to rename or remove the .ino file. Is that right?

Thanks in advance!
Erin

The preprocessor mainly adds an #include "application.h" and creates function prototypes if required.

If you can do this yourself, just add #pragma SPARK_NO_PREPROCESSOR as first line and see if your troubles go away.


The symptoms you describe do fit to some similar issues reported by others and usually got sorted with above #pragma :wink:

@ScruffR: thank you for the suggestion.

With the pragma it compiles! I also found another work-around… if I include application.h AFTER including my library (but not before) then that works too.

Of course I’d like to avoid requiring users of the library to resort to pragma hacks or include file ordering, and it bothers me that I still don’t understand what’s causing the problem. Is there any way I can see the pre-processed file? Or can someone point me to the code for the preprocessor?

The thing is, the preprocessor sometimes gets a bit over-excited and since the official :particle: Particle response used to be: "Use #pragma ...", but it does have the taste of a workaround.

Maybe @Dave (who was one of the first to ever suggest this on the forum) or @suda might have some more satisfactory info for you :wink:

1 Like

Hi @modulo

It sounds to me like your header is redefining something already defined in application.h.

@bko: that doesn’t seem consistent with the errors I’m getting. For instance, the errors indicate that certain classes declared in my header are not declared. (i.e., KnobModulo and JoystickModulo). There are also errors about functions like loop() and setup() having conflicting C vs C++ linkage.

Which makes me wonder, does the pre-processor do anything weird with linkage? i.e., including stuff in an extern “C” block or something?

1 Like

PS, if I use the pragma then I can include application.h before my header, after it, or not at all. All three work just fine.

1 Like

The pre-processor is sometimes a bit silly, and gets confused by files that start with large comment blocks. It’s using some expressions to find the start of the include block, and to determine if the standard includes are already there or not. That pragma just tells the preprocessor to chill out and not mess with the file. In general it only looks at the “.ino” files in your project, and it’ll leave the “.h” and “.cpp” files alone.

Thanks!
David

Thank you for the reply, Dave.

Does the preprocessor only insert includes, or does it do other stuff too?
Is the preprocessor open source? If so can you point me to it?
If it’s not open source is there a way for me to look at the pre-processed output?

I’m working on docs for modulo now and want to be sure I can give people reliable instructions for using the library. Would you recommend that I tell them to just always use the pragma?

Thanks,
Erin

Hi @modulo,

Good question! If you’re seeing consistent bad behavior from the pre-processor I’d love to fix that bug and add tests so it doesn’t regress. Any chance you might have a minimal test case?

I believe some work is being done on a dockerized local-build container that includes some of the pre-processor source, but I’m not sure what’s released yet. The pre-processor also looks for function definitions that are missing declarations, and inserts those after the include statements. ( @suda knows more about that )

I like the idea of making that more transparent, I’ll see what we can do about making the processed code available as well, I think that’d be a very helpful debugging tool. :slight_smile:

Thanks!
David

Exactly as Dave mentioned, we’ll release sources for Arduino preprocessor soon :slight_smile: It should definitely give some view into how it works internally.

1 Like

The pre-processor inserts declarations before the includes? Why does it do that? A library include file should, of course, not rely on anything in the application that uses it. So it seems like it should never be necessary to insert declarations before includes.

In fact, that sounds like the problem here. There’s a function in my .ino file which take an argument of a type that’s defined in my library. The function can’t be declared before the include file since the type is not yet declared.

Here’s a simple example. (You’ll need to include the ‘Modulo’ library that I contributed)

// Include the Modulo Library
#include "Modulo/Modulo.h"

void onKnobChanged(KnobModulo &knob) {}

void setup() {}

void loop() {}

This fails to compile with an error that says KnobModulo is not defined. I suspect it’s because of the declarations that the pre-processor is inserting.

I’m curious why it inserts declarations at all. Is that to try and make it so people can call locally defined functions from anywhere in the .ino without having to forward declare their functions?

Thanks,
Erin

I think this is a misunderstanding.

as @Dave mentioned

and as I said in one of my earlier posts

If the preprocessor finds a call to a function befor its actual implementation and is also missing a prototype for such function, it adds the missing prototype(s) after the #include block.

e.g. if you write this in your .INO file

void setup()
{
  doSomeSettingUp();
}

void loop() { }

void doSomeSettingUp(void)
{
  pinMode(D7, OUPUT);
  // whatever else
}

the compiler would complain about not knowing what doSomeSettingUp(); is supposed to be and also pinMode() and D7 would be unknown, but the proprocesser does this

#include "application.h"     // added by preproc

void doSomeSettingUp(void);  // added by preproc

void setup()
{
  doSomeSettingUp();
}

void loop() { }

void doSomeSettingUp(void)
{
  pinMode(D7, OUPUT);
  // whatever else
}

and now the compiler is happy again.

But if the #include block search does not work correctly, the prototype (forward declare - which non-C people tend to forget :wink: ) might well be inserted at a bad spot.

Oh I'm sorry. I misread. Yeah, I wouldn't expect this problem from declarations being inserted after the includes. But as you suggested, maybe it's being inserted in the wrong spot?

2 Likes

Hmm, sorry I think I meant to say after, not before:

It tries to insert after in case the include statements introduce classes or structs that are referenced in the functions, etc. Sorry about any miscommunication there! :slight_smile:

I do think there are some scenarios where it doesn't find the last include properly, and does insert them in the wrong spot. So that's a bug I'd want to fix :slight_smile:

Thanks,
David