Linker errors after updating to Atmel AVR 3.2.0

After updating to Atmel AVR 3.2.0 my project doesn’t link anymore. I’m probably doing something that is not allowed in GCC 7.3.0 anymore, but I wouldn’t know what.
The error is:

<artificial>:(.text.startup+0x4): undefined reference to `gioSetModeOutput'

the relevant lines from main.c are:

#include "gio.h"

static const gio_t led_pin = GIO_INIT(B, 1);
int main(void)
{
    gioSetModeOutput(&led_pin);
...

The relevant lines from gio.h are

...
typedef struct
{
    volatile uint8_t *const pin; // The pin registry memory location
    volatile uint8_t *const ddr; // The data direction registry memory location
    volatile uint8_t *const prt; // The port registry memory location
    const uint8_t bit;           // The bit number
} gio_t;

#define GIO_INIT(_PORT_LTR, _BIT_NR)                                              \
    {                                                                             \
        &PIN##_PORT_LTR, &DDR##_PORT_LTR, &PORT##_PORT_LTR, P##_PORT_LTR##_BIT_NR \
    }

#define gioGetState(val) gioIsHigh(val)

#ifdef __cplusplus
extern "C"
{
#endif

    inline void gioSetModeOutput(const gio_t *const _gio)
    {
        *(_gio->prt) &= ~_BV(_gio->bit);
        *(_gio->ddr) |= _BV(_gio->bit);
    };
...

Anyone any idea what the problem could be? Thanks.

I wasn’t able to reproduce your issue with a minimal example.

If I write the platformio.ini as

[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino

and src\main.cpp as

#include <Arduino.h>
#include "test_inline.h"

static const gio_t led_pin = GIO_INIT(B, 1);

void setup() {
    gioSetModeOutput(&led_pin);
}
void loop() {

}

with src\test_inline.h as

#ifndef TEST_INLINE_H
#define TEST_INLINE_H

#include <stdint.h>
#include <Arduino.h>

typedef struct
{
    volatile uint8_t *const pin; // The pin registry memory location
    volatile uint8_t *const ddr; // The data direction registry memory location
    volatile uint8_t *const prt; // The port registry memory location
    const uint8_t bit;           // The bit number
} gio_t;


#define GIO_INIT(_PORT_LTR, _BIT_NR)                                              \
    {                                                                             \
        &PIN##_PORT_LTR, &DDR##_PORT_LTR, &PORT##_PORT_LTR, P##_PORT_LTR##_BIT_NR \
    }

#ifdef __cplusplus
extern "C"
{
#endif

    inline void gioSetModeOutput(const gio_t *const _gio)
    {
        *(_gio->prt) &= ~_BV(_gio->bit);
        *(_gio->ddr) |= _BV(_gio->bit);
    };

#ifdef __cplusplus
}
#endif

#endif

then compilation results in a success in the latest platform version (and GCC 7.3.0)

Processing nanoatmega328 (platform: atmelavr; board: nanoatmega328; framework: arduino)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/nanoatmega328.html
PLATFORM: Atmel AVR (3.2.0) > Arduino Nano ATmega328
HARDWARE: ATMEGA328P 16MHz, 2KB RAM, 30KB Flash
DEBUG: Current (avr-stub) On-board (avr-stub, simavr)
PACKAGES:
 - framework-arduino-avr 5.1.0
 - toolchain-atmelavr 1.70300.191015 (7.3.0)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 11 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\nanoatmega328\src\user_main.cpp.o
Archiving .pio\build\nanoatmega328\libFrameworkArduinoVariant.a
Compiling .pio\build\nanoatmega328\FrameworkArduino\CDC.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\HardwareSerial.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\HardwareSerial0.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\HardwareSerial1.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\HardwareSerial2.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\HardwareSerial3.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\IPAddress.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\PluggableUSB.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\Print.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\Stream.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\Tone.cpp.o
Indexing .pio\build\nanoatmega328\libFrameworkArduinoVariant.a
Compiling .pio\build\nanoatmega328\FrameworkArduino\USBCore.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\WInterrupts.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\WMath.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\WString.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\abi.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\hooks.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\main.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\new.cpp.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring_analog.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring_digital.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring_pulse.S.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring_pulse.c.o
Compiling .pio\build\nanoatmega328\FrameworkArduino\wiring_shift.c.o
Archiving .pio\build\nanoatmega328\libFrameworkArduino.a
Indexing .pio\build\nanoatmega328\libFrameworkArduino.a
Linking .pio\build\nanoatmega328\firmware.elf
Building .pio\build\nanoatmega328\firmware.hex
Checking size .pio\build\nanoatmega328\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   0.4% (used 9 bytes from 2048 bytes)
Flash: [          ]   1.5% (used 448 bytes from 30720 bytes)
======================== [SUCCESS] Took 2.08 seconds ========================

However maybe the newer compiler or C/C++ version handles these inline functions differently at which it is failing here (at gioSetModeOutput()). Here is an article with some remarks to inline functions and linking, maybe one of those options help (like static inline, __attribute__((alway_inline)), namespaces, removing the inline as a test or whatever). Or maybe the behavior changes as multiple C++ files include the header, or a C file includes the header…

If that does not help, is the full project code available somewhere?

1 Like

Hi @maxgerhardt,

Thank you for your post (#2) and the link to the article. It contained the solution to my problem.

I should have mentioned that I was using the C compiler. I’m sorry about that! Your minimal example uses the C++ compiler and that compiled and linked fine on my system as well.

You were right that the problem was in the different handling of the inline function. Changing the declaration from inline void to static inline void did the trick. Thanks again!

2 Likes