Arduino0015+Eclipse problems

I've been fighting with this for some days now. Alas, with no prior C/C++ experience I feel kind of lost.

If anyone is willing to try this out, here's an archive of the Eclipse project:

http://1024.cjb.net/ABox.tar.gz

There is a Debug folder inside it, with automatically generated make files.

ABox/Debug $ make ABox.elf

should replicate the build process of Eclipse. Please try this out in your environment and let me know if you experience the same error.

Mellis, the build works if you replace the arduino folder with r577 from the google code svn repo. r578 introduces the virtual functions in Print.cpp, but I am wondering why does this work from the Arduino IDE, but not with this build process?!?

Thanks to everyone who took the time to read through this :slight_smile:

I have not seen the files on the svn but as of 0015 Print::write(char const*) should be Print::write(uint8_t)

Actually, from Print.h

  public:
    virtual void write(uint8_t) = 0;
    virtual void write(const char *str);
    virtual void write(const uint8_t *buffer, size_t size);

The compile error is in Print.cpp, for this function:

/* default implementation: may be overridden */
void Print::write(const char *str)
{
  while (*str)
    write(*str++);
}

I found a few threads that suggest declaring&defining __cxa_pure_virtual() for pure virtuals to work. The big question for me now is why does the arduino library compile with the Arduino IDE, but not with the Eclipse build?

So they've added two write's then. Hmmm. For the ethernet maybe? [Or bufring generally?]

Just me guessing again:

/* default implementation: may be overridden */
void Print::write(const char *str)
{
  while (*str)
    this->write(*str++);
}

But it is very strange that it compiles with Arduino IDE and not eclipse.

Nope, that didn't work either.

I am now able to compile the sketch with Eclipse if I add

extern "C" void __cxa_pure_virtual(void);
void __cxa_pure_virtual(void) {}

in any .cpp file. Without it, it always complains with

./arduino/Print.o: In function `Print::write(char const*)':
../arduino/Print.cpp:32: undefined reference to `__cxa_pure_virtual'

Can you guys download the code and try running the build?

Also, does anyone know where to get a full list of avr-gcc options and their meanings? I can't find a man page, avr-gcc -v --help doesn't seem to list everything ...

This FAQ has an explanation: http://ccgi.rowley.co.uk/support/faq.php?do=article&articleid=127

Indeed. However, it seems to me the problem is with the Arduino library, and the question is why does your build work.

Someone at AVRFreaks has written a tutorial on coding C++ for the AVR. Part of what needs to be done is definition and implementation of a void __cxa_pure_virtual(void) function. There is no such function in the Arduino library, hence the build error.

However, when building the project with an object archive (not sure about the terminology here), it magically works! The Arduino IDE copies all C and C++ compiled object files into core.a, and then links the main object file against it (and any other libraries outside the core). This I cannot explain.

Can someone shed some light on this?

One thing looks suspicious. I think this is the link step...

avr-gcc --cref -s -Os -o"ABox.elf"  
./blink.o 
./main.o  
./arduino/HardwareSerial.o 
./arduino/Print.o 
./arduino/WInterrupts.o 
./arduino/WMath.o 
./arduino/pins_arduino.o 
./arduino/wiring.o 
./arduino/wiring_analog.o 
./arduino/wiring_digital.o 
./arduino/wiring_pulse.o 
./arduino/wiring_serial.o 
./arduino/wiring_shift.o    
-lm -Wl,-Map,ABox.map,--cref -mmcu=atmega328p

I think one or more crt*.o files need to be included in that step. That may be where the elusive __cxa_pure_virtual has gone.

Good luck,
Brian

Hmm. Where are these crt*.o files supposed to come from? The official IDE does not use any ...

I am still digging into this out of pure curiosity. I want to know why the Arduino IDE build works, while it shouldn't?!

Hmm. Where are these crt*.o files supposed to come from?

My Arduino directory tree is filled with them (137 files).

  • Brian
kiril@kiril:~/local/arduino-0013$ find . -name crt\*.o
kiril@kiril:~/local/arduino-0013$
# this is the svn version from today
kiril@kiril:~/local/arduino-build$ find . -name crt\*.o
kiril@kiril:~/local/arduino-build$

:-?

That is strange.

What's in your...

arduino-0013\hardware\tools\avr\avr\lib

...directory?

  • Brian

That question helped :slight_smile: I use Linux, gcc-avr, avr-libc and avrdude come from the distro. So here is where the crt*.o files are:

kiril@kiril:/usr/lib/avr/lib$ avr-gcc --print-search-dirs
install: /usr/lib/gcc/avr/4.3.2/
programs: =/usr/lib/gcc/avr/4.3.2/:/usr/lib/gcc/avr/4.3.2/:/usr/lib/gcc/avr/:/usr/lib/gcc/avr/4.3.2/:/usr/lib/gcc/avr/:/usr/lib/gcc/avr/4.3.2/../../../avr/bin/avr/4.3.2/:/usr/lib/gcc/avr/4.3.2/../../../avr/bin/
libraries: =/usr/lib/gcc/avr/4.3.2/:/usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr/4.3.2/:/usr/lib/gcc/avr/4.3.2/../../../avr/lib/

I went on playing with this, and found even more curious things. For instance, Eclipse's binaries are much larger than the one generated by the IDE, sometimes by a 3-fold. However, the .o files by the IDE are (on average) 5% larger than those of Eclipse ... I wish I had studied compiler design and theory back in the university ...

That question helped

I'm glad to hear!

Eclipse's binaries are much larger than the one generated by the IDE

That could be the results of...

  • The various build switches. Often there are "optimize for size" and "optimize for speed" options.
  • Building with debug versions of the CRT files. C(++) compilers generally include "release" and "debug" versions of libraries. Usually debug versions are considerably larger.
  • Including the wrong CRT files.
  • Bug(s) in the development tools.

the .o files by the IDE are (on average) 5% larger than those of Eclipse

That only indicates they were built differently. The size of the .o files isn't necessarily going to be related to the size of the final product.

Good luck,
Brian

The makefile seems to be very out-of-date compared to the compile methods used by the IDE.
For example:

  1. The ardunio core libraries are now assembled into a searchable .a library instead of being included explicitly in the link line.
  2. The ide is now using "-ffunction-sections -fdata-sections" to suppress inclusion of extra code.

Here's a log of compiling a sketch with the most recent IDE:

hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/pins_arduino.c -o/tmp/build56301.tmp/pins_arduino.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/WInterrupts.c -o/tmp/build56301.tmp/WInterrupts.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring.c -o/tmp/build56301.tmp/wiring.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring_analog.c -o/tmp/build56301.tmp/wiring_analog.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring_digital.c -o/tmp/build56301.tmp/wiring_digital.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring_pulse.c -o/tmp/build56301.tmp/wiring_pulse.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring_serial.c -o/tmp/build56301.tmp/wiring_serial.c.o 
hardware/tools/avr/bin/avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/wiring_shift.c -o/tmp/build56301.tmp/wiring_shift.c.o 
hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /tmp/build56301.tmp/Temporary_788_9042.cpp -o/tmp/build56301.tmp/Temporary_788_9042.cpp.o 
hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/HardwareSerial.cpp -o/tmp/build56301.tmp/HardwareSerial.cpp.o 
hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/Print.cpp -o/tmp/build56301.tmp/Print.cpp.o 
hardware/tools/avr/bin/avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega168 -DF_CPU=16000000L -I/Applications/arduino/arduino-0015/hardware/cores/arduino /Applications/arduino/arduino-0015/hardware/cores/arduino/WMath.cpp -o/tmp/build56301.tmp/WMath.cpp.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/HardwareSerial.cpp.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/pins_arduino.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/Print.cpp.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/WInterrupts.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring_analog.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring_digital.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring_pulse.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring_serial.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/wiring_shift.c.o 
hardware/tools/avr/bin/avr-ar rcs /tmp/build56301.tmp/core.a /tmp/build56301.tmp/WMath.cpp.o 
hardware/tools/avr/bin/avr-gcc -Os -Wl,--gc-sections -mmcu=atmega168 -o /tmp/build56301.tmp/Blink_double.elf /tmp/build56301.tmp/Temporary_788_9042.cpp.o /tmp/build56301.tmp/core.a -L/tmp build56301.tmp -lm 
hardware/tools/avr/bin/avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 /tmp/build56301.tmp/Blink_double.elf /tmp/build56301.tmp/Blink_double.eep 
hardware/tools/avr/bin/avr-objcopy -O ihex -R .eeprom /tmp/build56301.tmp/Blink_double.elf /tmp/build56301.tmp/Blink_double.hex

Patches welcome.

Well, the differences between the Makefile in hardware/cores/arduino and the build process done by the IDE was not my problem, but I'm glad people have noticed. Hopefully it'll be fixed soon.

Anyway, I finally know what is going on here! Thanks westfw for the hint! Probably most of you already knew all about it, but still, here it comes ...

The difference in binary size, as well as the original problem that prevented me from compiling code (see first post) are related to the same thing -- the -ffunction-sections -fdata-sections options passed to the compiler and the -Wl,-gc-sections option passed to the linker. This post has it all. Having unused code stripped out of the final binary makes it way smaller. It also eliminates the need for void __cxa_pure_virtual(void), since it's not called anywhere. Applying some of the other options/tips there, I managed to get a build by Eclipse even smaller than the one build with the Arduino IDE.

The additional step of combining libraries into core.a and then linking against it is just a hack that allows the linker to garbage-collect even more unneeded code, especially in .data

I'll try to come up with an updated Arduino+Eclipse guide.

I don't know if anyone is interested at all -- it seems not too many people use Eclipse to write for Arduino. Nevertheless, I managed to write a Makefile (oh, the pain!) that replicates the build process of the official ide and even adds some additional improvements.

Here's a quick writeup:

http://lz3060.wordpress.com/2009/05/21/avr-makefile-first-attempt/

The advantages of my setup (vs. the one described in the Playground) are that you can modify core libraries and have them automatically recompiled with the next build. It also adds all .o files to the object archive, allowing the linker to do it's magical garbage collecting everywhere. I am getting even smaller builds with this than with the official IDE!

LMK if you find it useful or need more details on how it works.

I don't know if anyone is interested at all

I am. The Arduino editor is getting on my nerves and I've been fixin' to try Eclipse for months.

Thanks for the write-up.

  • Brian

Kiril: it looks like you changed quite a lot. Is it possible to fold your improvements into the existing Makefile? For example, I'd like to keep the automatic generation of the #include "WProgram.h" and the main() function by the Makefile. If you can send a patch to the developers mailing list, I'll try to integrate it.