static-librariesavr-gcc

Can I build an avr-libc static library without specifying target MCU?


I am building an avr-libc static library like this:

avr-gcc -O2 -I. -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -Wall -Wstrict-prototypes -g -ggdb -ffunction-sections -fdata-sections -Wl,--gc-sections -mrelax -std=gnu99 -c font.c unifont.c libtft.c

and then:

avr-ar rcs libtft.a libtft.o font.o unifont.o

Including the library in a project, and building it like this:

avr-gcc -mmcu=atmega328p -DF_CPU=8000000UL -O2 -I. -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -Wall -Wstrict-prototypes -g -ggdb -ffunction-sections -fdata-sections -Wl,--gc-sections -mrelax -std=gnu99 rfm.c tft.c sdc.c avrrfm.c librfm95.a libtft.a libsdc.a --output avrrfm.elf

fails with:

/usr/lib/gcc/avr/14.2.0/../../../avr/bin/ld: libtft.a(libtft.o): in function `tftWriteSpace':
/home/dode/dev/libtft/libtft.c:284:(.text.tftWriteSpace+0x44): undefined reference to `__mulhi3'

libtft.c:284 is:

bytes_t bytes = width * height / 8;

By including -mmcu=atmega328p when building the library, the issue is solved, so I guess that when building the library without specifying the target MCU, a multiplication function that works for all MCU types is picked. Then, when building the project and specifying the MCU, another (optimized?) function is used, and the one used in the library is undefined.

Is it possible at all to build a target MCU independent static library?


Solution

  • Is it possible at all to build a target MCU independent static library?

    No. You'll need multilib granularity at least.

    Multilib options are: -mmcu=, -msp8, -mshort-calls, -mdouble= and -mlong-double= where availability depends on configure options and the compiler version, and not all combinations are possible. Showing all multilib variants, here with avr-gcc v15 that has bee configured with --with-long-double=64:

    $ avr-gcc -print-multi-lib
    .;
    avr25;@mmcu=avr25
    avr3;@mmcu=avr3
    avr31;@mmcu=avr31
    avr35;@mmcu=avr35
    avr4;@mmcu=avr4
    ...
    avrxmega3/short-calls/double64;@mmcu=avrxmega3@mshort-calls@mdouble=64
    avrxmega4/double64;@mmcu=avrxmega4@mdouble=64
    avrxmega5/double64;@mmcu=avrxmega5@mdouble=64
    avrxmega6/double64;@mmcu=avrxmega6@mdouble=64
    avrxmega7/double64;@mmcu=avrxmega7@mdouble=64
    avrtiny/double64;@mmcu=avrtiny@mdouble=64
    

    Left of ; are the multilib variants' paths like used on disk. Right of ; are the options that lead to that multilib variant (replace @ with - (a blank and a dash)).

    You can of course generate only a selection of these when you don't need all variants. In order to map options to a multilib path:

    $ avr-gcc -mmcu=atmega328p -print-multi-directory
    avr5
    

    which is very useful in Makefile or build scripts, for example when you have to select a multilib path. That is: You build multilib variants according to subdirs and options as of -print-multi-lib and then select the path according to -print-multi-directory. This is exactly what avr-gcc does when it has to select a multilib variant of libgcc.a, libc.a or libm.a, see for example the output of avr-gcc -v ... when linking.


    In the case where the library contains device specific stuff like SFR addresses and the like, you may have to switch to device granularity.