[llvm-dev] Build Clang/LLVM for AVR

716 views
Skip to first unread message

Alexander Entinger via llvm-dev

unread,
Mar 25, 2020, 8:01:53 AM3/25/20
to llvm...@lists.llvm.org
Hi everyone,

I've been wondering how to correctly build clang/LLVM for the AVR target architecture. Unfortunately documentation is very scarce (or outdated or I didn't find it) and while I've been able to build clang/LLVM for AVR I'm still falling short of compiling an actual binary for the MCU. Here are the steps I've undertaken so far:

git clone https://github.com/llvm/llvm-project
cd llvm-project
mkdir build && cd build

cmake -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS="clang;libcxx;libcxxabi" -DLLVM_TARGETS_TO_BUILD="AVR" -DCMAKE_BUILD_TYPE=Release ../llvm
make -j8
sudo make install

Next I created a pretty empty main.cpp and tried to compile that:

#include <stdint.h>
int main()
{
for(;;) { }
return 0;
}

Here's the result of attempting the compilation ...

$ clang++ --target=avr -mmcu=atmega328p -c main.cpp -o main.o -v
clang version 11.0.0 (https://github.com/llvm/llvm-project 177dd63c8d742250dac6ea365e7c30f0fbab3257)
Target: avr
Thread model: posix
InstalledDir: /usr/local/bin
Found candidate GCC installation: /usr/lib/gcc/avr/5.4.0
Selected GCC installation: /usr/lib/gcc/avr/5.4.0
(in-process)
"/usr/local/bin/clang-11" -cc1 -triple avr -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model static -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -target-cpu atmega328p -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -v -resource-dir /usr/local/lib/clang/11.0.0 -fdeprecated-macro -fdebug-compilation-dir /home/alex/tmp/clang-avr -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -faddrsig -o main.o -x c++ main.cpp
clang -cc1 version 11.0.0 based upon LLVM 11.0.0git default target x86_64-unknown-linux-gnu
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/local/lib/clang/11.0.0/include
/usr/include
End of search list.
In file included from main.cpp:1:
In file included from /usr/local/lib/clang/11.0.0/include/stdint.h:52:
/usr/include/stdint.h:26:10: fatal error: 'bits/libc-header-start.h' file not found
#include <bits/libc-header-start.h>
^~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Looking for that file I can find it in the system

$ find /usr -iname libc-header-start.h
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h

But adding it to the clang call via -isystem or -I does not help either.

$ clang --target=avr -mmcu=atmega328p -c main.cpp -o main.o -v -I/usr/include/x86_64-linux-gnu
clang version 11.0.0 (https://github.com/llvm/llvm-project 177dd63c8d742250dac6ea365e7c30f0fbab3257)
Target: avr
Thread model: posix
InstalledDir: /usr/local/bin
(in-process)
"/usr/local/bin/clang-11" -cc1 -triple avr -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model static -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor aliases -target-cpu atmega328p -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -v -resource-dir /usr/local/lib/clang/11.0.0 -I /usr/include/x86_64-linux-gnu -fdeprecated-macro -fdebug-compilation-dir /home/alex/tmp/clang-avr -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -faddrsig -o main.o -x c++ main.cpp
clang -cc1 version 11.0.0 based upon LLVM 11.0.0git default target x86_64-unknown-linux-gnu
#include "..." search starts here:
#include <...> search starts here:
/usr/include/x86_64-linux-gnu
/usr/local/include
/usr/local/lib/clang/11.0.0/include
/usr/include
End of search list.
In file included from main.cpp:1:
In file included from /usr/local/lib/clang/11.0.0/include/stdint.h:52:
In file included from /usr/include/stdint.h:26:
In file included from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33:
In file included from /usr/include/features.h:448:
/usr/include/x86_64-linux-gnu/gnu/stubs.h:7:11: fatal error: 'gnu/stubs-32.h' file not found
# include <gnu/stubs-32.h>
^~~~~~~~~~~~~~~~
1 error generated.

Thinking that maybe the old version (5.4.0) of avr-gcc might be a problem I've built a 9.2.0 version from sources

$ avr-gcc -v
Using built-in specs.
Reading specs from /opt/avr/avr-gcc/lib/gcc/avr/9.2.0/device-specs/specs-avr2
COLLECT_GCC=avr-gcc
COLLECT_LTO_WRAPPER=/opt/avr/avr-gcc/libexec/gcc/avr/9.2.0/lto-wrapper
Target: avr
Configured with: ../configure --prefix=/opt/avr/avr-gcc --target=avr --enable-languages=c,c++ --disable-nls --disable-libssp --disable-libada --with-dwarf2 --disable-shared --enable-static --enable-mingw-wildcard
Thread model: single
gcc version 9.2.0 (GCC)

But this didn't change anything, except that when running clang without file arguments it does indicate that there is no avr-gcc in the system (although there is, but probably not spliced in there where the clang/LLVM build process expects it).

$ clang --target=avr -mmcu=atmega328p
clang-11: warning: no avr-gcc installation can be found on the system, cannot link standard libraries [-Wavr-rtlib-linking-quirks]
clang-11: warning: standard library not linked and so no interrupt vector table or compiler runtime routines will be linked [-Wavr-rtlib-linking-quirks]
clang-11: error: no input files

I'd greatly appreciate any input helping to solve these problems or a pointer to working documentation.

With kind regards, Alex
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

Sam Elliott via llvm-dev

unread,
Mar 25, 2020, 8:18:03 AM3/25/20
to Alexander Entinger, llvm...@lists.llvm.org
It looks like you’re cross-compiling for an embedded target, so you need to be careful about how you treat headers (like libc’s), as the x86 ones will not be compatible with the AVR ones. The clang driver can manage this for you, if you give it enough information:

The first thing to try is adding the --gcc-toolchain argument to clang to point to the root of the avr gcc toolchain (I think in your case this will be /opt/avr/avr-gcc ). This should help the driver pick up the right include paths for AVR.

Try that see how you get on.

Sam

--
Sam Elliott
Software Developer - LLVM and OpenTitan
lowRISC CIC

Alexander Entinger via llvm-dev

unread,
Mar 25, 2020, 9:52:18 AM3/25/20
to Sam Elliott, llvm...@lists.llvm.org
Thank you for both of your input. Yes, I try to cross-compile for AVR, the simple ATMEGA328P used in every Arduino Uno. My main motivation being that I hope to be able to use a couple of STL containers, <functional> and <type_traits> on the MCU. Not sure though if this can be reached by going via the clang route.

Getting back to the compilation: when I run clang with both both -nostdlibinc (which makes it necessary to point clang to the header file location via -isystem /opt/avr/avr-libc/avr/include) and --gcc-toolchain I can compile the minimum example code.

clang++ --target=avr -nostdlibinc -isystem /opt/avr/avr-libc/avr/include --gcc-toolchain=/opt/avr/avr-gcc -mmcu=atmega328p -c main.cpp -o main.o

However, when I'm running a compilation on a more complicated embedded programm I get a lot of troubling warnings, e.g.

warning: unknown attribute '__progmem__' ignored [-Wunknown-attributes]

(which are troubling me, because if all those string constants are put in RAM instead of Flash the RAM will be pretty soon empty ;) ).

But those warnings aside I run ultimately into problems when getting to the linking step where it appears there are trouble providing implementations for avr-gcc built-in functions which I believe are located within the avr-gcc MCU specific libraries

/opt/avr/avr-libc/avr/include/util/delay.h:187: undefined reference to `__builtin_avr_delay_cycles(unsigned long)'

as well as troubles which seem to be originating from my C++ usage within the firmware

undefined reference to `vtable for __cxxabiv1::__class_type_info'

Kind regards, Alex


________________________________________
Von: Sam Elliott [sell...@lowrisc.org]
Gesendet: Mittwoch, 25. März 2020 13:17
An: Alexander Entinger
Cc: llvm...@lists.llvm.org
Betreff: Re: [llvm-dev] Build Clang/LLVM for AVR

Ayke van Laethem via llvm-dev

unread,
Mar 25, 2020, 12:07:47 PM3/25/20
to Alexander Entinger, llvm...@lists.llvm.org
  In file included from main.cpp:1:
  In file included from /usr/local/lib/clang/11.0.0/include/stdint.h:52:
  /usr/include/stdint.h:26:10: fatal error: 'bits/libc-header-start.h' file not found
  #include <bits/libc-header-start.h>
           ^~~~~~~~~~~~~~~~~~~~~~~~~~
  1 error generated.
 
I had the same issue initially. The problem here is that it tries to include /usr/include/stdint.h, which it should not because that's the header for the host system not the AVR. To work around this you can use the -nostdlibinc flag.

Alexander Entinger via llvm-dev

unread,
Mar 26, 2020, 1:42:47 AM3/26/20
to Sam Elliott, llvm...@lists.llvm.org
Good Morning,

I've created a minimum source file and build instructions which exhibit the same behaviour I see at my larger firmware project. The example involves dynamic polymorphism and builtin AVR specific functions.

#include <stdlib.h>
#include <util/delay.h>

void * operator new(size_t size) { return malloc(size); }
void operator delete(void * ptr) { free(ptr); }
__extension__ typedef int __guard __attribute__((mode (__DI__)));
extern "C" int __cxa_guard_acquire (__guard * g) { return !*(char *)(g); }
extern "C" void __cxa_guard_release (__guard * g) { *(char *)g = 1; }
extern "C" void __cxa_guard_abort (__guard * g) { }
extern "C" void __cxa_pure_virtual (void ) { }

class DelayBase
{
public:
virtual ~DelayBase() { }
virtual void delay(unsigned int const ms) = 0;
};

class Delay : public DelayBase
{
public:
virtual ~Delay() { }
virtual void delay(unsigned int const ms) override { for(unsigned int i = 0; i < ms; i++) { _delay_ms(1); } }
};

int main()
{
Delay delay;
for(;;)
{
delay.delay(10);
}
return 0;
}

Compilation is done via

$ clang++ --target=avr -nostdlibinc -isystem /opt/avr/avr-libc/avr/include --gcc-toolchain=/opt/avr/avr-gcc -mmcu=atmega328p -DF_CPU=16000000UL -O1 -c main.cpp -o main.o

and linking via

$ avr-ld main.o -o main.bin --relax --gc-sections -L/usr/lib/avr/lib/avr5 -L/usr/lib/avr/lib/avr5 -L/opt/avr/avr-gcc/lib/gcc/avr/9.2.0/avr5 -l:crtatmega328p.o -lgcc -lm -lc -latmega328p -mavr5

which results in the following error message:

avr-ld: main.o: in function `Delay::delay(unsigned int)':
main.cpp:(.progmem.data+0xa8): undefined reference to `__builtin_avr_delay_cycles(unsigned long)'
avr-ld: main.o:(.rodata._ZTI9DelayBase[_ZTI9DelayBase]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
avr-ld: main.o:(.rodata._ZTI5Delay[_ZTI5Delay]+0x0): undefined reference to `vtable for __cxxabiv1::__si_class_type_info'

Any insight into the cause of this problem would be greatly appreciated ;)
Kind regards, Alex

________________________________________
Von: llvm-dev [llvm-dev...@lists.llvm.org]&quot; im Auftrag von &quot;Alexander Entinger via llvm-dev [llvm...@lists.llvm.org]
Gesendet: Mittwoch, 25. März 2020 14:51
An: Sam Elliott

Anton Korobeynikov via llvm-dev

unread,
Mar 26, 2020, 4:09:58 AM3/26/20
to Alexander Entinger, llvm...@lists.llvm.org
Two issues here:

1. You are using C++ runtime, so you'd need to link C++ runtime
library (e.g. libc++abi / libsupc++, etc)
2. You need to link some library that provides implementation of AVR
builtins (like __builtin_avr_delay_cycles). Note that avr-gcc
implements __builtin_avr_delay_cycles as a compiler builtin function
and expands it during the codegen.

Patches are welcome ;)

On Thu, Mar 26, 2020 at 8:42 AM Alexander Entinger via llvm-dev

--
With best regards, Anton Korobeynikov
Department of Statistical Modelling, Saint Petersburg State University

Alexander Entinger via llvm-dev

unread,
Mar 26, 2020, 5:03:27 AM3/26/20
to Anton Korobeynikov, llvm...@lists.llvm.org
Hi Anton, thank you for your feedback.

Regarding 1) I'm wondering from where to obtain such a library? Certainly it does not come with avr-gcc which is the reason I'm looking at clang/LLVM in the first place. Unfortunately to the best of my knowledge it was also not produced during the compilation of the cross-compiler, since both libc++.a and libc++abi.a are for i386:x86-64 architecture (objdump -f *.a).

Regarding 2) I believe I might be able to provide a patch for this, once I've learned a bit more about the internal works of LLVM ;)

Kind regards, Alex
________________________________________
Von: Anton Korobeynikov [an...@korobeynikov.info]
Gesendet: Donnerstag, 26. März 2020 09:09
An: Alexander Entinger
Cc: Sam Elliott; llvm...@lists.llvm.org

Reply all
Reply to author
Forward
0 new messages