Référence indéfinie

Bonjour :smiley: je viens vous embêter avec des référence indéfinie.
J'ai crée une librairie statique (très simple juste pour tester) que j'ai compilé en .a grâce au makefile suivant

CXX=avr-g++

CXXFLAGS = -Wall -Wextra
CXXFLAGS += -std=c++17

# ------ les bibliothèques extérieures

AVR_ARDUINO=/usr/share/arduino/hardware/archlinux-arduino/avr

CPPFLAGS += -I$(AVR_ARDUINO)/cores/arduino
CPPFLAGS += -I$(AVR_ARDUINO)/variants/standard

all: libLed.a

libLed.a: Led.o
	ar rcs $@ $<

Led.o: Led.cpp
	avr-gcc -c $< -o $@ $(CPPFLAGS)

clean:
	$(RM) *.o *.a

La librairie est une classe qui gère une led, avec un constructeur qui set le pinMode, un get pour la pin, une fonction d’écriture via digitialWrite et une fonction de clignotement de la led.

mon main :

#include <Led.h>

void setup(){}

Led led(2);

void loop(){
  led.flash(1000);
}

Mon main est donc compilé par le makefile suivant

CXX=avr-g++

CXXFLAGS = -Wall -Wextra
CXXFLAGS += -std=c++17

# ------ les bibliothèques extérieures

AVR_ARDUINO=/usr/share/arduino/hardware/archlinux-arduino/avr

CPPFLAGS += -I$(AVR_ARDUINO)/cores/arduino
CPPFLAGS += -I$(AVR_ARDUINO)/variants/standard

LED_ARDUINO = /home/breizh/Documents/Cours/stage/Sujet/simplecase/lib

CPPFLAGS += -I$(LED_ARDUINO)
LDLIBS   += -L$(LED_ARDUINO)
LDLIBS   += -lLed

CXXFLAGS+=-fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -flto -mmcu=atmega328p
LDFLAGS+=-flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p

# ------- structure du projet ---------------------------

MAIN = simplecase.cpp
OBJ += $(MAIN:.cpp=.o)

# -------- dependances ---------------------------------

all: simplecase

simplecase: $(OBJ)
	$(LINK.cc) -o $@ $^ $(LDLIBS)

simplecase.o:	simplecase.cpp

# ---- divers ---------------------------------------------
clean:
	$(RM) *.o

Ce qui est étrange et que j'ai du mal à comprendre c'est que j'ai des référence indéfinie sur les fonctions de base d'Arduino comme le delay() ou digitalWrite()

/usr/bin/avr-ld : /usr/lib/gcc/avr/10.3.0/../../../../avr/lib/avr5/crtatmega328p.o:(.init9+0x0) : référence indéfinie vers « main »
/usr/bin/avr-ld : /home/breizh/Documents/Cours/stage/Sujet/simplecase/lib/libLed.a(Led.o) : dans la fonction « Led::Led(int) » :
Led.cpp:(.text+0x28) : référence indéfinie vers « pinMode »
/usr/bin/avr-ld : /home/breizh/Documents/Cours/stage/Sujet/simplecase/lib/libLed.a(Led.o) : dans la fonction « Led::writeLed(int) » :
Led.cpp:(.text+0x5a) : référence indéfinie vers « digitalWrite »
/usr/bin/avr-ld : /home/breizh/Documents/Cours/stage/Sujet/simplecase/lib/libLed.a(Led.o) : dans la fonction « Led::flash(int) » :
Led.cpp:(.text+0xb2) : référence indéfinie vers « delay »
/usr/bin/avr-ld : Led.cpp:(.text+0xdc) : référence indéfinie vers « delay »
collect2: error: ld returned 1 exit status
make: *** [makefile:32 : simplecase] Erreur 1

A priorie la librairie Arduino est link correctement avec le -I mais ça bloque et je n'arrive pas à comprendre pour quoi ^^ je ne suis pas contre avoir des indication ou des pistes sur l'erreur.
Merci d'avance !

Il reste simplement à faire l'édition de liens avec la librairie ARDUINO, celle qui s'appelle core.a et qui est construite par l'IDE (voir les messages de compilation de l'IDE).

Quel est l'intérêt de ravailler avec un Makefile ?
J'y vois beaucoup d'inconvénients :

  • il va falloir construire autant de librairies core.a que de plateformes
  • il va falloir également construire les librairies des bibliothèques utilisées

L’intérêt à terme est d'inclure une grosse librairie pas du tout prévu pour Arduino. cf Makefile et librairie par Breizh291 - OpenClassrooms si jamais tu veut plus d'info.
Mais du coup je tente de repasser par une librairie plus simple avant. Donc je fait un -Lcore.a -lcore je suppose mais comment construire les core.a ? Et juste -I$(PATH_ARDUINO) ne suffit pas ?

Non, cela ne suffit pas.
Il faut compiler chaque fichier source du core ARDUINO et mettre les objets en librairie à l'aide de avr-gcc-ar.
Ensuite il faut passer core.a en argument au linker, comme s'il s'agissait d'un objet.

Quelles sont les autres possibilité ? Tout bourrer dans ~/Arduino/lib ? J'ai commencé par faire ça en mettant les .h et .cpp dans un dossier umlrts qu'il à l'aire de reconnaître car à la compilation sous l'IDE j'ai le message Utilisation de la bibliothèque umlrt prise dans le dossier : /home/breizh/Arduino/libraries/umlrt (legacy) mais quand même des référence indéfinie vers des fonction bien définie. Je m'y prend peut-être comme un pied ^^

Il suffit de faire une compilation d'un exemple simple avec l'IDE ARDUINO et s'inspirer des messages produits.
Activer l'option "Afficher les résultats détaillés".

C'est l'une des première choses que j'ai tenté aussi, mais ça ne règles pas le problème de référence indéfinie. J'ai aussi tenté via Arduino-Builder :

ARDUINO=/usr/share/arduino
CART=archlinux-arduino:avr:uno
UML_ARDUINO = /home/breizh/Documents/Cours/stage/Sujet/uml-rt-port-for-arduino/umlrt-arduino_lib

Main :
	arduino-builder -compile -verbose -hardware $(ARDUINO)/hardware -tools $(ARDUINO)/tools-builder -libraries $(UML_ARDUINO) -fqbn=$(CART) -build-path build -warnings default TopMain.ino

La aussi, même problème.

C'est à dire ? Qu'il y a des références indéfinies en utilisant l'IDE ?

Je mélange peut-être un peu tout, j'essaie de synthétiser :
Mon objectif final est de compiler un programme pour arduino en utilisant une grosse librairie (umlrts) sauf que la, j'ai des référence indéfinie sur des fonctions de la librairie. J'ai essayé via l'IDE, via Arduino-Builder et via avr-g++. Dans les 3 cas, le résultat est le même.

J'ai donc essayé et faire la même choses mais avec une librairie beaucoup moins touffu (Led) ou la, j'ai des référence indéfinie vers des fonctions Arduino.

Je ne suis pas foncièrement contre passer par l'IDE, pour la librairie Led cela fonctionne nickel mais pas pour la librairie umlrts ou la, j'ai des référence indéfinie vers des fonctions de la librairie pourtant à priori bien définie.

J’espère avoir été plus clair et merci de ton aide ^^

Compilation d'un fichier du core :

/home/riton/.arduino15/packages/arduino/tools/avr-gcc/5.4.0-atmel3.6.1-arduino2/bin/avr-gcc -c -g -Os -std=gnu11 -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10811 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR -I/mnt/sdc1/riton/arduino-1.8.11/hardware/arduino/avr/cores/arduino -I/mnt/sdc1/riton/arduino-1.8.11/hardware/arduino/avr/variants/eightanaloginputs /mnt/sdc1/riton/arduino-1.8.11/hardware/arduino/avr/cores/arduino/wiring.c -o /tmp/arduino_build_193277/core/wiring.c.o

La compilation produit un fichier objet .c.o qui est mis en librairie (core.a)

/home/riton/.arduino15/packages/arduino/tools/avr-gcc/5.4.0-atmel3.6.1-arduino2/bin/avr-gcc-ar rcs /tmp/arduino_build_193277/core/core.a /tmp/arduino_build_193277/core/wiring.c.o

Ensuite au niveau de la ligne de commande de lien on retrouve core.a :

/home/riton/.arduino15/packages/arduino/tools/avr-gcc/5.4.0-atmel3.6.1-arduino2/bin/avr-gcc -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections -mmcu=atmega328p -o /tmp/arduino_build_193277/Blink.ino.elf /tmp/arduino_build_193277/sketch/Blink.ino.cpp.o /tmp/arduino_build_193277/core/core.a -L/tmp/arduino_build_193277 -lm