User defined #defines in to a library

I am working on "libraryising" some code I've written. The idea is to create a library which can then be used wherever required, in a wide variety of projects. I plan to share the library at some point too.

However I need a way to get user-supplied (meaning from the ino file, the idea being that a user should have no need to edit the hfile or cpp file when in use) #defines. I need #defined values to pass from the top of the ino file, in to the library code.

This would work with a h file library, but I don't want that, I want to have the library in its own cpp file as a separate compilation unti from the main ino code.

I must use #defines, NOT, passing of variables as arguments, because for the functions I've written in the library to run at their proper speed certain variables (pin numbers used in port manipulation operations for example) must be constants. I have verified this on an oscilloscope, the code runs something like 5 times faster when #define or const uint8_t is used for certain variable names, compared to the slow case where a variable is used and the code has to perform certain if loops and switch cases on variable value at run time.

These #defines are constant for any given arduino system built, but the values may vary for different applications, so while they don't need to be actual variables (they will never vary during operation) (and must not be for speed reasons), they also can't be #defines contained in the library's h file or cpp file, as when the library is used for different projects different values will be needed.

But when different compilation units are used, a #define in the ino file doesn't seem to be accessible by the cpp file, I get compiler errors.

I would also like to have the library generate a compiler error with a custom message if these #defines are undefined or if they meet certain properties. For example, refusing to compile and giving a message "ERROR, pins PinAlpha, PinBeta, PinGamma and PinDelta must all be defined, and PinAlpha...PinDelta MUST all be different values" if one of those names isn't defined in the ino file, or if PinBeta and PinGamma were equal values. With other error messages available like "ERROR, defined value Epsilon must be between 2 and 25" if the ino file contained something such as #define Epsilon 30 .

I would be ok with a requirement that in the ino file the #defines must be writen above where the #include command sits.

What is the best way to proceed?

Thank you

This is not possible. And even if you could (e.g. by creating a header-only library), it would be a terrible idea and an ODR nightmare to have macros in user code affect your library.

What you can do is pass all the constants as template parameters to the respective functions and classes of your library.
It would either need to be a header-only library, or you'll have to instantiate all necessary parameter combinations in your .cpp file.

Why?

The requirements that you've outlined are impossible to achieve.

PieterP Why?
Because whilst I'd like these compile time #defines to be passed in by the user, I'd also like the library to be able to contain internal static variables kept safe from being changed by the user code in the ino function butable to be changed by the library's own functions.

That's the important why. It's a separate compilation unit. It can't know anything about #defines from a completely different compilation unit.

This is a problem that has been solved. You just can't do it the way you want to. @PieterP has described a good one.

One option would be to have the user pass the defines as compiler flags. But this would involve mucking around in the platform.txt or boards.txt files and if you don't want users having to modify the library then I would assume asking them to modify their core is even worse.

That is PieterP's "good one"?

How does this ensure that in the library the passed info is seen as #defined type values, constants, and not interpreted as variables? Because it is crucial in my use case that these values are fixed at compile time so that during compilation various if loops and switch cases in the library code get collapsed down by use of "#defin es"/"const uint8_t s"?

If it manages this, then please give me a link to some examples of this being done.

Thank you

Templates are completely resolved at compile time.

Manages what? You've given a vague description that appears to lack a clear understanding of a few crucial points.

Perhaps an example of what you want to try to do would be more appropriate.

It's about as good as you're going to get without having to have people either modify the library code or the core files. Or have them compile with make and put the defines in the makefile.

There are ways, but none that are as simple as #define. I'm sorry, but it just can't happen. You're not the first to want it and you won't be the last to eventually understand why you can't have it.

pass a constant on object creation or use templates.

Ok, thank you. Can you point me to some examples of:

using templates and parameters
and
passing a constant on object creation

So I can have a go with them, and see if they let the code run as fast as #defines do.
Thank you

either search for "c++ initializer list" or make a short sketch with a class and a #define like you do today and some can change it accordingly ..

Post an example of the code you're talking about. Your description of what you want is far too vague to provide useful guidance.

2 Likes

You're still not understanding. It will have nothing to do with the speed of the code. It's just about how it gets compiled.

Google "C++ template class"

Google "C++ class" and learn about what a constructor does. Then pass your constant as an argument to a class constructor. There's nothing special about it being a constant.

No, initialize constant class member doing a different way than variable one.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.