matthijskooijman / arduino-lmic

:warning: This library is deprecated, see the README for alternatives.
707 stars 650 forks source link

Unable to compile lmic lib with Arduino AVR Boards 1.8.1 #243

Closed vlastahajek closed 4 years ago

vlastahajek commented 5 years ago

After I've upgraded Arduino IDE to 1.8.10, which in turn brought Arduino AVR Boards 1.8.1, I'm unable to compile basic ttn-abp sketch, which uses lmic libary:

C:\Users\vlast\AppData\Local\Temp\ccyy7JQt.ltrans0.ltrans.o: In function `radio_irq_handler':

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/radio.c:801: undefined reference to `table_get_u2'

C:\Users\vlast\AppData\Local\Temp\ccyy7JQt.ltrans0.ltrans.o: In function `schedRx12':

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/lmic.c:1336: undefined reference to `table_get_ostime'

C:\Users\vlast\AppData\Local\Temp\ccyy7JQt.ltrans0.ltrans.o: In function `calcBcnRxWindowFromMillis':

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/lmic.c:419: undefined reference to `table_get_ostime'

C:\Users\vlast\AppData\Local\Temp\ccyy7JQt.ltrans0.ltrans.o: In function `calcRxWindow':

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/lmic.c:405: undefined reference to `table_get_ostime'

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/lmic.c:407: undefined reference to `table_get_ostime'

C:\Users\vlast\AppData\Local\Temp\ccyy7JQt.ltrans0.ltrans.o: In function `initDefaultChannels':

C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic\src\lmic/lmic.c:553: undefined reference to `table_get_u4'

collect2.exe: error: ld returned 1 exit status

Multiple libraries were found for "lmic.h"
 Used: C:\Users\vlast\OneDrive\Dokumenty\Arduino\libraries\arduino-lmic
Multiple libraries were found for "SPI.h"
 Used: C:\software\arduino.1.8.10\hardware\arduino\avr\libraries\SPI
exit status 1
Error compiling for board Arduino Pro or Pro Mini.

Works well again after I had downgraded back to 1.6.23

galagaking commented 4 years ago

Workaround: create a platform.local.txt platform.local.txt file in the /hardware/arduino/avr/ directory (same dir as platform.txt). File will replace -Os optimisation by -O2 and that will compile the code without any errors.

paulvha commented 4 years ago

Or fix the real issue: In oslmic.h, the lmic directory around line 231 it states:

 inline type table_get ## postfix(const type *table, size_t index) { \

add static to beginning of line:

static inline type table_get ## postfix(const type *table, size_t index) { \

You can now compile without a problem.

matthijskooijman commented 4 years ago

Hm, interesting. Adding static does, I think, pretty much obsolete the inline keyword (not in the sense that it prevents inlining, but inline is more about preventing multiply defined linker errors when inlining does not happen). More specifically, any call that is not inlined would result in a function definition in the compiled .o file. If multiple .o files have the same function, inline should make sure that all of them are merged into a single one (rather, one is kept and the rest is discarded), whereas the static keyword makes each of these functions local to their .o file, so all are kept.

So that means that adding static would possibly result in duplicate code in the resulting binary. Also, I can't directly see why these symbols would be missing with the original code: For each .o file, either all calls should be inlined, or the symbol should be present in them. So that does somewhat reek of a compiler bug, though it would probably need more investigation to be sure.

paulvha commented 4 years ago

inline keyword is a hint to the compiler to optimize, do not call it as a the function but add into the code, but is it really used by the compiler? Some say that inline function in C++ should be used instead of macros. Inline functions are parsed by the compiler and the macros in a program are expanded by preprocessor. It looks with the -O2 optimizer instead of the -Os it already reacts different less optimizing the code size, maybe already discarding the inline hint. Understanding compilers in depth is a science by its own, which I do not master.

matthijskooijman commented 4 years ago

inline keyword is a hint to the compiler to optimize, do not call it as a the function but add into the code, but is it really used by the compiler? Some say that inline function in C++ should be used instead of macros. Inline functions are parsed by the compiler and the macros in a program are expanded by preprocessor. It looks with the -O2 optimizer instead of the -Os it already reacts different less optimizing the code size, maybe already discarding the inline hint. Understanding compilers in depth is a science by its own, which I do not master.

As I said, the inline keyword is more an instruction for the linker to allow defining a function in a header file (which is historically (without LTO) needed to allow inlining functions) without getting linker errors. The keyword might also serve as a hint to the compiler that you are expecting the function to be inlined, but in practice I think compilers simply see if it is efficient or not. If you really want to force inlining, there's also an always_inline attribute, but that's a completely separate (and non-portable, I think) thing.

matthijskooijman commented 4 years ago

(two comments deleted, moved to #264)