Advanced Arduino – Including Multiple Libraries In Your Project

Arduino IDE

The Arduino IDE is a great environment for getting started programming microprocessors. It radically lowers the cost of entry, and greatly simplifies the learning curve. The importance of these properties should not be underestimated. Most of us are capable of advanced microprocessor programming given time, desire and opportunity even without the Arduino environment. The biggest obstacle, however, is getting started. When that first hurdle is at last overcome, we can then soar to greater heights. That is where the Arduino is an incredible blessing. It is so simple that it removes most of the barriers to entry. From scratch, we can get started in microprocessors and build our confidence and knowledge at an easy pace. Once that is done, then we can advance to more complex projects and techniques.

That easy means of entry, however, can also become a limitation. Because the Arduino IDE makes the cost of getting started very low, that same simplicity can also prevent us from advancing to more complex projects. A good example is when you want to create new libraries that make use of existing libraries. When you try to do so in the usual fashion of including libraries, you are confronted with compiler errors. This article will examine the problem in combining various libraries within the IDE and how to work around them. It will also address some more advanced C++ practices that help when dealing with multiple libraries and larger projects.

Including Libraries within Another Library

The Arduino IDE has an easy way to include libraries in your sketch. Just use the Import Library command, and an include directive appears in your sketch. From there, not only is the header file (ending in .h) included in your sketch, but the code file (ending .cpp) is also compiled behind the scenes.

Now, say we are developing a more complex project that will use a library of our own. That library will itself build on other libraries. When we try to include one of those existing libraries in our new custom library, this automatic mechanism fails. In fact, it doesn’t even exist.  To see what I mean, let’s look at an example:

MyLibrary.h:
class Bounce;

class MyLibrary {
protected:
  Bounce* btn;

public:
  MyLibrary(int btnPin);
};

MyLibrary.cpp:
#include "Bounce.h"

MyLibrary::MyLibrary(int btnPin) {
btn = new Bounce(btnPin, 5);
}

In this example, in my header file, I’ll provide a forward declaration to the class Bounce, and then in my code file, I’ll include the Bounce library. If I did this include in a sketch file, I would have no problem. When I try it in a library file, it fails.

Getting Your Library to Compile while including a Library

When you try to compile this code, the first error you get indicates that the Bounce.h file can not be found. The reason is the Arduino IDE searches for library includes, so the user is not hassled with specifying their exact location. It is setup to search the library directory from sketches only, not from within the library directory itself. When including files from within the library, if the include file is not in the same directory as the file doing the including, it won’t be found.

The remedy is simple – provide a directory specification to the file to include. In this example, to include the “Bounce.h” file, we specify the relative file path this way:

#include "../Bounce/Bounce.h"

That is the relative path in Linux. In Windows, you may need to use backslashes (‘\’) instead. The ‘../’ indicates the parent directory of the current one which is “MyLibrary”. If we followed the path specifier, we go up one directory, which puts us in the library directory, and then down into the Bounce directory. Lastly, we then specify the filename to include.

Now when you try to compile, the compiler will find the Bounce header code and compile with no problem. That was simple wasn’t it? Not so fast. We now run into our next problem. As part of keeping things simple for the new user, the Arduino IDE makes no distinction between compiling and linking. These are two distinct operations and the linking operation comes after the compile operation. What is linking you may be asking? Read on.

Linking versus Compiling

What the compile operation does is check the source files for syntax errors, and then if all is well, it converts them to machine code. Next comes the linking part. In this step, the linker scours all the source files (generally ending in .cpp) given it and connects or “links” the functions being called with their actual code, with result being one large file (called a hex file), which is then uploaded to your Arduino. If a needed file is not given to the linker, the link step will fail. Most development environments separate the two processes, so it is easy to track down the cause of the error. In the Arduino IDE, this separation is not made. That being the case, one way to detect a link error from a compile error is to simply to watch the compile error window. Compile errors show up quickly. If you have to wait a while before you get errors, the errors are likely coming from the linker.

Getting Your Library to Link to another Library

When you try to compile and link our changed example, you will now get errors complaining that various functions being called in the Bounce library cannot be found:

MyLibrary/MyLibrary.cpp.o: In function `MyLibrary::MyLibrary(...)': /home/scott/Arduino Sketches/libraries/MyLibrary/MyLibrary.cpp:28: undefined reference to `Bounce::read()'

That is because the Bounce library is not being sent to the linker. The Arduino IDE magic has again failed. The fix is unfortunately somewhat of a hack. Being a hack, it must be applied every time it is needed, and it isn’t real pretty. Having said all that, it is relatively easy.

The Arduino IDE sends any files included in the sketch to the linker, so the fix is to simply include the missing files in the sketch itself. In our example, in our sketch we put:

#include "Bounce.h"

You should understand that the linker really is looking for the source code file “Bounce.cpp”. Since we have no way in the IDE to specify which source files to include in the linking process, the only way to specify to the Arduino IDE to link to this file is to include the header file in the sketch itself. That signals the IDE to send the corresponding .cpp file to the linker. You will need to repeat this step for every library used in your project. In the end, your sketch file will have one include for every library used in the entire project.

With this simple include statement in our sketch, the example will not only compile, it will also link. Problem solved.

Good Include Practices

While we are on the arcane subject of file includes, I thought it would be useful provide some good programming practices and clear up some confusion that may exist on the subject.

Forward Class Declaration vs Includes

In my simple example’s header file, you may have noticed that I did not try to include the Bounce.h file, but instead simply wrote what is known as a forward declaration to it:
class Bounce;
I did so because it is good programming practice. You should only include header files when necessary, especially within header files, since they in turn are included in other files. It speeds compile time and prevents possible trouble down the road. When you need to make use of another class within your header file, instead of including that class’s header file, you only need to provide a forward declaration to it. Then in your source code file, you actually include the class header so you can use the class. If you are confused, just look at my example header and source code file again.

Using Brackets vs Quotation Marks for Includes

You may have noticed when looking at other people’s code, that sometimes files are included using brackets (<>), and sometimes using quotes (“”). What is the reason for these two ways and which one should be used? I haven’t found documentation for any particular rules in the Arduino IDE. From my experience, it appears both can be used interchangeably. Normally though, C++ does make a distinction. The brackets should be used for built-in language library files, and quotes for your own files as well as third party libraries. In the Arduino’s case, if including a file in the Arduino IDE directory, you should use brackets. For example:

#include <WConstants.h>

For anything in your sketch directory, including libraries, use quotes:
#include "Bounce.h"
Like I said, the Arduino IDE doesn’t enforce this distinction, but other IDEs may. It is good practice to make your code conform to the rules of C++. Good practices in the beginning will avoid countless headaches down the road.

Conclusion

Because of the inherent limitations in the Arduino IDE, many people migrate to more powerful development tools such as Eclipse as they begin to tackle larger projects. Interestingly, the Arduino website has a tutorial on converting over to Eclipse. Unfortunately, Eclipse has a bit of learning curve itself. If you are not ready to make that plunge, the technique provided in this tutorial will serve you until you take that next step.

In summary, we have examined some of the limitations of the Arduino IDE in regards to including files and provided a workaround. We examined good coding practices that may save trouble later on. At some point you may outgrow the IDE and migrate to Eclipse or some other IDE. Until that day, this article will make you better equipped to work within its limitations.

In researching solutions to this library include problem, as well as correct include syntax, I couldn’t find any relevant documentation on the subject. Therefore, the recommendations given are drawn from my own experience. As such, these techniques and practices may be flawed or there may be better ones available.  If you have any advice to the contrary, please post them in the comments section. Anything valid and pertinent will be added to this article.

Happy Arduino-ing!

Advanced Arduino – Including Multiple Libraries In Your Project by Provide Your Own is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

This entry was posted in Tech and tagged . Section: . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

12 Comments