Arduino library link order

I just stumbled upon a problem with undefined symbol reference errors that typically come from a bad link order of the .a libraries in the avr-gcc command line that is managed by Arduino.

This can easily be checked by building the firmware with

> make VERBOSE=1

At the very end of the output one can find the linker command. Here the relying library must occur before the relied library. Unfortunately, this is not handled automatically.

Does anybody have a hint about how to manually fix this problem?

1 Like

Can you tell us a bit more about what the error was and which libraries it was? What does the linker output look like?

One thing that occurred to me during dinner is that the strange library link order might come from an inappropriate include order of header files.

Arduino has this wannabe smart preprocessor. Appart from the fact that it causes problems with comments in C/C++ macro calls and other dubious non-standard behavior - admittedly another story- it seems to look for include directives and uses this information to decide which libraries to link to the sketch.

Is it possible that Arduino just passes the libraries to the linker command line in the exact order as it encounters associated include directives? Although not yet tested, I remember that I have an include at the very top of the .ino sketch that points to the library whose symbols are not found.

I will test this hypothesis ASAP.

If true this might be important to mention in the Kaleidoscope documentation as it could hit people that generate plugins with relative dependencies. For my part, I have a plugin that relies on an external library that I turned Arduino compatible and intent to link it into the sketch.

1 Like

Now I can confirm by experiment that at least in my case the order of includes in the .ino affects the order of libraries in the linker command line.

The following code snippets hopefully exemplify the problem. Say you have two Kaleidoscope plugins or, more general, two Arduino libraries A and B. Let’s assume B depends on A in a sense that B references symbols (functions/variables) defined in A. Both libraries define header files a_header.h and b_header.h that specify their exported symbols.

The following sketch builds as expected.

// my_sketch.ino
#include "b_header.h"
#include "a_header.h"
...

If the header appear in opposite order the linker will throw undefined symbol errors regarding missing symbols from A.

// my_sketch.ino
#include "a_header.h"
#include "b_header.h"
...

The reason for this somewhat unexpected behavior is that the order of libraries’ occurrence in the linker command line is crucial. The linker must see library B first to determine which symbols it needs to extract from A. If it encounters A first, it completely neglects its symbols as there are no references to it at that point.

To be on the safe side and only if the sketch does not reference symbols from A directly, it is better to include the headers in the following way.

// header_b.h
#include "header_a.h"
...
// my_sketch.ino
// Do not include a_header.h directly. I is already included by a_header.h.
#include "b_header.h"
...

Note: I did no thorough research on how Arduino internally establishes the linker command line, e.g. with respect to a recursive traversal of the include-tree. This means, I am not sure how the link command line order is generated when header files that are included by the main .ino do include other files that provide definitions of library symbols in different orders. There might be additional pitfalls when header includes are more complex given a larger project.

@Jennigma, is there a suitable place in the documentation where this information could be added?

Thank you!

Yes, there is a good place. In the sidebar is “Advanced Topics,” and I would add a link under that section to a new page with more or less what you have written above.

If you feel up to creating a new page on the wiki for this it would be welcomed, otherwise I will get to it as I can. :slight_smile:

I will try to add the page as you suggested. Thank you.

1 Like

Here is the wiki entry.

As non native speaker I would appreaciate if someone could correct my writing where necessary.

2 Likes

@noseglasses: looks good to me. Thanks for explaining the issue.

Needs a tiny correction though:

// Do not include a_header.h directly. I is already included by a_header.h.

should be

“It is already included by b_header.h”

Edit: i took the liberty of changing it.

2 Likes