Linker problem. Ideas?

I am using Eclipse to develop Arduino applications. In general, it is working pretty well for me.

I have always used a static library for the Arduino core (I named it core328p-0022). No problem. And I have successfully used a static library for the Arduino libraries (I named it arduinolib-0022). My problem comes in trying to use a static library containing my own library files (it’s named TC4stdlib).

A simple example (abbreviated):

//blinker.cpp
#include <WProgram.h>
#include <Wire/Wire.h> // Arduino library contained in arduinolib-0022
#include <cLCD/cLCD.h>  // my library contained in TC4stdlib
cLCD lcd;  // create an instance of cLDC with default consrtuctor
void setup() {
  Wire.begin();
  lcd.begin( 16, 2 );
  ....
}
void loop() { // some unrelated code  here to blink the LED, etc. }

As best I can tell, all of the include directories are set up for the compiler and linker in Eclipse (it is not complaining about not finding files). The program compiles OK, no errors.

But I get lots of linker errors like this one:

C:\Documents and Settings\Jim\My Documents\eclipse\workspace\TC4stdlib/Release\TC4stdlib.a(cLCD.o):(.rodata._ZTV4cLCD+0x6): undefined reference to `Print::write(char const*)'

There are these class definitions in my cLCD library:

// base class for LCD objects
class LCDbase : public Print {
.....
};
class cLCD : public LCDbase {
....
};

So it is pretty clear to me that the linker does not know where to grab the code for the Print class.

If I just add cLCD.h and cLCD.cpp sources into my blinker project in Eclipse, and do not link with my TC4stdlib, then everything is fine. But when I remove the cLCD sources from my blinker project and try to link it from the TC4stdlib, I get the linker errors again.

Can someone give me some places to start looking for a solution to this problem? I would really like to be able to link my library files in without recompiling the source every time.

Jim

Bump.

Anyone got an idea?

Jim

I don't know anything about Eclipse, but a fair amount about gcc and linking.

The absence of error messages about files doesn't prove much, it just means the files you specified (whatever they are) have been found. Whether they are the right files is another thing.

It's hard to say more without more details. Did you create a library file? Is it part of the Makefile (or whatever Eclipse uses)? Have you linked things in the right order?

As best I can tell, all of the include directories are set up for the compiler and linker in Eclipse (it is not complaining about not finding files).

Linking errors are nothing to do with include directories. They are more to do with library directories or library files.

Yes, I created 3 static libraries: Arduino core, Arduino libraries (e.g. Wire, etc.), and my own library. I am not writing my own my own Makefile. Instead, Eclipse is handling the build.

Does the order of linking matter?

Thanks for the response.

Jim

This is what I am seeing in the console window in Eclipse:

make all 
Building target: aBourbon.elf
Invoking: AVR C++ Linker

avr-gcc --cref -s -Os -o"aBourbon.elf"  ./aBourbon.o   -lcore328p-0022 -larduinolib-0022 -lTC4stdlib 
-lm -Wl,-Map,aBourbon.map,--cref -Wl,--gc-sections 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\core328p-0022\Release" 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\arduinolib-0022\Release" 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\TC4stdlib\Release" -mmcu=atmega328p

C:\Documents and Settings\Jim\My Documents\eclipse\workspace\TC4stdlib\Release\libTC4stdlib.a(TC4app.o): 
In function `rstCmnd::doCommand(CmndParser*)':
TC4app.cpp:(.text._ZN7rstCmnd9doCommandEP10CmndParser+0x24): undefined reference to `Serial'
TC4app.cpp:(.text._ZN7rstCmnd9doCommandEP10CmndParser+0x26): undefined reference to `Serial'
...many more similar errors....

The final target is aBourbon.hex.

The TC4app.cpp classes are contained in the TC4stdlib library. They depend on both the core328p-0022 classes and the arduinolib-0022 classes. These dependencies seem to be causing the problems, based on the error messages.

If instead of linking with TC4stdlib I just add the source files (e.g. TC4app.cpp) to my Eclipse project, and compile them with the build, everything works fine.

Jim

JimG: Does the order of linking matter?

Yes it matters, or at least it has been known to matter under certain circumstances.

Consider that the linker tries to link in a minimal amount of code, that is it tries to omit things it doesn't think are required. Now moving from left to right it starts with aBourbon.o, which gives it stuff that (presumably) needs to be resolved. You then link in core328p-0022 followed by arduinolib-0022 which would resolve certain dependencies. Finally you link in TC4stdlib last. Now if TC4stdlib requires something in arduinolib-0022 (like Serial) then it's too late. It has already considered that file and won't backtrack.

If you can move -lTC4stdlib to after ./aBourbon.o that may resolve your issue. Failing that, some dummy reference in aBourbon.cpp to Serial may trick the linker into pulling in stuff needed in TC4stdlib although that is a bit of a kludge.

A search for "gcc linker resolve order" reveals various posts including this gem:

You can add: "--start-group / --end-group" options.

You may or may not be able to influence the linking command (if so you could probably just alter the order like I said). But the --start-group and --end-group apparently make the linker reconsider each item inside the group until all dependencies are resolved.

Yahoo! Success.

First, I only reordered the list of libraries, but that didn't help. Then I reordered the libraries and then -L parameters, and the errors disappeared. I guess what I learned from this is that the linker has to be made aware in advance which objects to grab from a static library. I assumed it would pull everything from the library in, and then discard the objects not needed. Not the case.

Here is the link command that ultimately worked:

make all 
Building target: aBourbon.elf
Invoking: AVR C++ Linker
avr-gcc --cref -s -Os -o"aBourbon.elf"  ./aBourbon.o   -lTC4stdlib -larduinolib-0022 -lcore328p-0022 
-lm -Wl,-Map,aBourbon.map,--cref -Wl,--gc-sections 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\TC4stdlib\Release" 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\arduinolib-0022\Release" 
-L"C:\Documents and Settings\Jim\My Documents\eclipse\workspace\core328p-0022\Release" 
-mmcu=atmega328p
Finished building target: aBourbon.elf

I never would have figured out that the order of the linker command parameters would matter. Many thanks!

Jim