I'm using Keil V5.30.0.0 and ArmClang.exe V6.14.
When I tried using std::mt19937, like so:
#include <random>std::mt19937 mt;std::uniform_int_distribution< uint32_t > dist(0);auto a = dist( mt );
I got linker errors:
.\obj\rcu.axf: Error: L6200E: Symbol __stdin multiply defined (by stdio_streams.o and retarget.o)..\obj\rcu.axf: Error: L6200E: Symbol __stdout multiply defined (by stdio_streams.o and retarget.o)..\obj\rcu.axf: Error: L6200E: Symbol __stderr multiply defined (by stdio_streams.o and retarget.o).
I'm using more or less classical retarget.c, tuned for armclang.
I tried to remove those definitions from retarget.c and then got error:
.\obj\rcu.axf: Error: L6915E: Library reports error: __use_no_semihosting_swi was requested, but _sys_open was referenced
Then I removed asm(".global __use_no_semihosting_swi\n"); and my firmware hit BKPT before main, in call to _sys_open.
Why is this happening? mt19937 and uniform_int_distribution by themselves should not use any IO, should they?
I tried using empty project (of my own) and copy-pasted your code for main. I also tried enabling retargetting of STDIN and STDOUT via RTE manager as you suggested.
Several things happened:
- size of the binary went to 84 kilobytes with -Oz, even when main is empty. Have no idea how retarget_io.c manages to waste so much space ._.- project compiled but stalled on BKPT before main with a callchain like _initio -> freopen -> _sys_open. This happens even if main is empty!
This reminded me of an issue that I stumbled in three years ago - community.arm.com/.../using-itm-retarget-with-keil-software-packs
Bloated code size is the reason why I still use a hand-written retarget.cpp (not .c, that was a misprint earlier, sorry) instead of RTE Managing it.
Here it is, more or less:
#if ( (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) ) asm(".global __use_no_semihosting_swi\n"); #elif __CC_ARM #pragma import(__use_no_semihosting_swi) namespace std { struct __FILE { int handle;} ; } #endif #include <stdio.h> #include <rt_sys.h> #include <rt_misc.h> std::FILE std::__stdout; std::FILE std::__stdin; std::FILE std::__stderr; extern "C" { int fputc(int c, FILE *f) { return ITM_SendChar(c); } int fgetc(FILE *f) { char ch = 0; return((int)ch); } int ferror(FILE *f) { /* Your implementation of ferror */ return EOF; } void _ttywrch(int ch) { ITM_SendChar(ch); } char *_sys_command_string(char *cmd, int len) { return NULL; } void _sys_exit(int return_code) { while(1); } }
So 'tuning for armclang' was this line about semihosting - asm(".global __use_no_semihosting_swi\n");
On its own this works very nicely, at least in Simulator (which is all I need at the moment).
This explains the original linker error: _sys_open is needed by the iostream functions pulled in from <random>, your retarget.cpp doesn't provide a definition and you disabled semihosting, so the linker complained that it couldn't find a suitable _sys_open. Allowing semihosting pulls in version of _sys_open that uses semihosting, which is why you end up on a breakpoint before main. (If you want to decode the semihosting call, see Chapter 7 in the ARM Compiler Software Development Guide.)
The bulk of your 84KB binary is most likely due to locale and other I/O support. <random> includes <istream> and <ostream>, which is enough to pull in the IO libraries, even if your <random> objects don't use streams. Large binary sizes aren't really the fault of retarget_io.c -- it's just a very small part of the overall puzzle.
Hmm, looks like you are correct; removing #include <random> leads to small binary.
Why this include pulls so much unused code that isn't removed even with -LTO and -ffunction-sections - is a whole other story, albeit very interesting :)
Thanks for explanation!
However.. when I used retarget_io.c, provided by RTE Manager, I didn't disable semihosting and still ended up on a breakpoint before main..