Forum: Compiler & IDEs Komischer Linker-Fehler oder Tomaten auf den Augen?


von Ulrich K. (ulrich65)


Lesenswert?

Ich baue mir gerade, angeregt durch das Ahoy-Projekt

Beitrag "Wechselrichter Hoymiles HM-xxxx 2,4 GhZ Nordic Protokoll?"

einen LoRa-Node, um die Daten des Hoymiles-Wechselrichters zu 
übertragen. Dazu verwendete ich ein Heltec LoRa-Board mit einer STM32L51 
MCU und SX1276 LoRa-Modem. Als Firmware verwende ich den offiziellen 
LoRaMac-node von Semtech,

https://github.com/Lora-net/LoRaMac-node

ergänzt um eine Definition für das Heltec-Board. Das hat sich in anderen 
Projekten schon bewährt.

Zur Steuerung des nRF24L01 Transceivers habe ich die im Ahoy-Projekt 
verwendete Arduino Library RF24 in Teilen portiert, also nur die 
Methoden, die ich zum Auslesen des Wechselrichters brauche.

Ich betreibe ein LoRa Indoor Gateway und gehe über das The Things 
Network. Um keinen übermäßigen Datenverkehr zu erzeugen, wollte ich den 
Wechselrichter alle 10 Minuten auslesen, die Daten sammeln und einmal 
pro Stunde als Block mit LoRa senden. Statt der Berechnung der Zeiten 
mit Tageslicht werde ich noch einen Lichtsensor integrieren.

Alles kompiliert ohne Warnungen und Fehler, nur beim Linken gibt es 
Probleme. Hier die relevanten privaten Methoden meiner RF24-Klasse:
1
uint8_t RF24::read_register(uint8_t reg)
2
{
3
    m_status = SpiInOut(&Rf24_spi, R_REGISTER | reg);
4
    return (uint8_t) SpiInOut(&Rf24_spi, 0xff);
5
}
6
7
void RF24::read_register(uint8_t reg, uint8_t *buf, uint8_t len)
8
{
9
    m_status = SpiInOut(&Rf24_spi, R_REGISTER | reg);
10
    while (len--) {
11
        *buf++ = SpiInOut(&Rf24_spi, 0xff);
12
    }
13
}

Das RF24_spi Objekt ist als extern deklariert und an anderer Stelle 
implementiert.

Der Linker meckert jetzt über die RF24_spi Referenzen in der ersten 
Methode, an denen in der zweiten Methode hat er nichts auszusetzen:
1
in function `RF24::read_register(unsigned char)':
2
/Users/uli/Projekte/LoRaMac-node_heltec/src/peripherals/rf24/rf24.cpp:99: undefined reference to `Rf24_spi'

Ich verwende eine Toolchain mit Arm GCC 10.2.1 auf macOS.

Hat jemand eine Idee, was da schiefläuft oder kann mir die Tomaten von 
den Augen entfernen?

Viele Grüße,
Uli

von Walter T. (nicolas)


Lesenswert?

Naja, in Deinem Quelltext-Schnipsel ist die Variable Rf24_spi wirklich 
nicht da.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ulrich K. schrieb:
> Das RF24_spi Objekt ist als extern deklariert und an anderer Stelle
> implementiert.

Wo und wie? Wenn es in einer C-Datei definiert ist muss es in C++ so 
deklariert werden:
1
extern "C" {
2
  extern DeinSpiTyp Rf24_spi;
3
}

oder, falls in einem Header deklariert der von C und C++ benutzt wird:
1
#ifdef __cplusplus
2
extern "C" {
3
#endif
4
extern DeinSpiTyp Rf24_spi;
5
#ifdef __cplusplus
6
}
7
#endif

: Bearbeitet durch User
von 900ss (900ss)


Lesenswert?

Niklas G. schrieb:
> Wenn es in einer C-Datei definiert ist muss es in C++ so deklariert
> werden:

Ack! Würde ich auch vermuten, dass das Problem daher kommt.
Bei Mix aus C++/C das name mangeling beachten.

von Ulrich K. (ulrich65)


Lesenswert?

@Walter

Rf24_spi ist am Anfang der Implementierungsdatei der Klasse RF24 
definiert:
1
 extern Spi_t Rf24_spi;


@Niklas

Das Objekt ist in einer C-Datei implementiert, also extern "C", klar.
Aber warum wird die "undefined reference" für das Objekt nur in einer 
Methode reklamiert und in der anderen nicht?

von Walter T. (nicolas)


Lesenswert?

Wenn ich raten müsste, ist Zeile 99 die erste, in der das Objekt 
referenziert wird.

Kannst Du denn auf Rf24_spi in normalem C zugreifen?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Ulrich K. schrieb:
> Aber warum wird die "undefined reference" für das Objekt nur in einer
> Methode reklamiert und in der anderen nicht?

Vielleicht gibt dein Linker den gleichen Fehler nicht mehrfach aus? Oder 
die andere Funktion wird nie aufgerufen und daher wegoptimiert?

von Ulrich K. (ulrich65)


Lesenswert?

Im C-Code kann ich auf das Objekt ohne Probleme zugreifen. Konkret bei 
der Parametrierung der SPI-Schnittstelle.

Wenn ich in der ersten Methode die beiden Funktionsaufrufe "SpiInOut" 
auskommentiere, meckert der Linker nicht, obwohl in der zweiten Methode 
Rf24_spi weiterhin unverändert referenziert wird.

von Ulrich K. (ulrich65)


Lesenswert?

@Niklas

>> Vielleicht gibt dein Linker den gleichen Fehler nicht mehrfach aus? Oder
>> die andere Funktion wird nie aufgerufen und daher wegoptimiert?

Das war der entscheidende Hinweis. Die Methode wird tatsächlich nicht 
benutzt, weil ich nur die für meinen Zweck nötigen Methoden aus der 
Arduino Library rübergeholt habe. Die entsprechenden 
write_register-Methoden, die alle verwendet werden, mag der Linker auch 
nicht.

Vielen Dank für alle Hinweise,
Uli

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

PS: Methoden gibt's in C++ nicht, nur Member-Funktionen...

von Léo (Gast)


Lesenswert?

Ulrich K. schrieb:
> Rf24_spi ist am Anfang der Implementierungsdatei der Klasse RF24
> definiert:
>  extern Spi_t Rf24_spi;

Nein. Damit ist es deklariert, aber nicht definiert.

Deklarieren bedeutet so viel wie "Es gibt irgendwo ein Objekt vom Typ 
foo und es heißt bar".

Definieren bedeutet so viel wie "Das hier ist ein Objekt vom Typ foo und 
es heißt bar".

> Das Objekt ist in einer C-Datei implementiert, also extern "C", klar.

Schreib nicht "implementiert". Das bedeutet was komplett anderes. 
Schreib "definiert", denn genau das ist es."

Wenn Du das Objekt in C-Linkage definierst, musst Du es auch in 
C-Linkage deklarieren, d.h. um Deine Deklaration gehört genau das, was 
Niklas hier beschrieben hat:

Beitrag "Re: Komischer Linker-Fehler oder Tomaten auf den Augen?"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.