Forum: Compiler & IDEs assert_param führt zu Fehlermeldungen


von Mehmet K. (mkmk)


Lesenswert?

Servus allerseits

Mein Problem: das von der StdPerLib benutzte assert_param führt beim 
Build zu Errors.

Arbeitsumgebung:
Em::Blocks vers 2.0
GCC vers. 4.7.3 20130226
STM32F407
StdPerLibF4: vers 1.3.0


Compiler Defines:
1
STM32F40_41xxx
2
USE_FULL_ASSERT
3
USE_STDPERIPH_DRIVER
4
HSE_VALUE=8000000
5
VECT_TAB_SRAM
6
DEBUG

stm32f4xx_conf.h:
1
#ifdef  USE_FULL_ASSERT
2
  #define assert_param(expr) ((expr) ? ((void)0) : assert_failed((uint8_t *)__FILE__, (uint32_t) __LINE__))
3
  void assert_failed(uint8_t *file, uint32_t line);
4
#else
5
  #define assert_param(expr) ((void)0)
6
#endif

main.cpp:
1
#ifdef  USE_FULL_ASSERT
2
    void assert_failed(uint8_t *file, uint32_t line)
3
    {
4
        debug_print( "assert_failed in file: %s, line: %ld\n", file, line );
5
        while (1);
6
    }
7
#endif

Solange ich keine Dateien der StdPerLib einbinde und nur mit den eigenen 
arbeite, kann ich in irgendeiner Datei die Zeile
1
assert_param( 4 > 5 );
einfügen und ich kriege prompt per Semihost die korrekte Fehlermeldung.

Sobald ich aber auf irgendeine Datei der StdPerLib zugreife, kriege ich 
ein Stakkato der Fehlermeldung wie z.Bsp.
1
E:\...\stm32f4xx_gpio.c|175|undefined reference to `assert_failed'

D.h., der Praeprozessor löst assert_param korrekt nach assert_failed 
auf, aber der Linker kann damit nichts anfangen.
Aber wie gesagt: nur bei den StdPerLib-Dateien. Bei meinen eigenen hat 
der Linker damit kein Problem.
Wenn ich dasselbe Szenario mit dem EWARM-Kickstart von IAR durchspiele, 
funktioniert alles ohne irgendwelche Fehler.

Hat irgendwer 'ne Idee, woran das liegen könnte?

von Rolf Magnus (Gast)


Lesenswert?

Ich vermute, daß die Datei, in der assert_failed definiert ist, vor den 
zu StdPerLib gehörenden gelinkt wird. Die muß in der 
Linker-Kommandozeile danach stehen, damit der Linker das auflösen kann.

von Mehmet K. (mkmk)


Lesenswert?

Servus Rolf

Dein Tip hat mir zwar nicht eingeleuchtet, aber seit einigen Stunden bin 
ich eh schon im "Probieren geht über Studieren" Modus :)

Da Em:Blocks kein make-file hat:
Hab also die Funktion assert_failed() in der Datei main.cpp gelöscht und 
es an das Ende der Datei stm32f4xx_gpio.c gehaengt.
Hab' nicht schlecht gestaunt, als jetzt das assert_failed() in der 
Nicht-StdPerLib-Datei als undefined reference reklamiert wurde: das 
Stakkato an Fehlermeldungen der StdPerLib-Dateien war weg.

Also habe ich die Funktion assert_failed() in die main.cpp kopiert und 
erwartet, dass jetzt der Linker über diese Redefinition meckern würde.
Von wegen: jetzt habe ich zwar keine Fehlermeldungen mehr und auch das 
Program reagiert wie es sollte ...
Nur: ich steh wieder wie zuvor vor dem Bildschirm und kratz mich am 
Kopf.
Wie kann es sein, dass der Linker 2 gleichnamige Funktionen, die nicht 
static sind, nicht beanstandet?

Und wieso ist beim Linken die Reihenfolge der Module wichtig? Es ist 
doch gerade dies eine der Aufgaben des Linkers, unter all den 
kompilierten Modulen die Funktionen herauszufischen und sie zu einem 
ausführbaren Program zusammenzufügen.

von Markus F. (mfro)


Lesenswert?

Mehmet Kendi schrieb:
> Und wieso ist beim Linken die Reihenfolge der Module wichtig?

Der Linker bindet nur die Symbole aus Libraries ein, von denen er weiß, 
daß sie benötigt werden.

In der Linker-Kommandozeile muß deswegen das Objekt, das den Bedarf hat, 
zuerst auftauchen.

Das kann u.U. (wenn kein ranlib auf die Lib ausgeführt wurde) sogar dazu 
führen, daß man ein und dieselbe Library mehrfach angeben muß.

von Mehmet K. (mkmk)


Lesenswert?

Vermutlich habe ich eine falsche Faehrte gelegt, da ich davon ausging, 
die "Standard Peripherals Library" von STMicroelectronics sei jederman 
bekannt. Sorry!
Wenn ich StdPerLib schreibe, dann meine ich nicht eine Library im 
üblichen Sinne. Das Ding heisst zwar Library, besteht aber aus einzelnen 
Dateien.

von Rolf Magnus (Gast)


Lesenswert?

Mehmet Kendi schrieb:
> Und wieso ist beim Linken die Reihenfolge der Module wichtig? Es ist
> doch gerade dies eine der Aufgaben des Linkers, unter all den
> kompilierten Modulen die Funktionen herauszufischen und sie zu einem
> ausführbaren Program zusammenzufügen.

Ja, und dazu geht er die zu linkenden Dateien eine nach der anderen 
durch. Wenn er mit einer Datei fertig ist, hat er eine Liste von noch 
nicht aufgelösten Symbolen. Diese Liste merkt er sich. Wenn er die 
nächste Datei öffnet, schaut er nach, ob er hier Symbole auflösen kann 
und tut das dann. Ggf. kommen neue noch nicht aufgelöste Symbole hinzu. 
So geht er alle Dateien durch, und die Liste der unaufgelösten Symbole 
wird jedesmal angepasst. Am Schluss müssen alle Symbole aufgelöst sein, 
sonst gibt der Linker für jedes noch in der Liste vorhandene Symbol eine 
Fehlermeldung aus.
Wenn nun ein Object-File ein Symbol definiert, das bisher nirgends 
benötigt wird, verwirft der Linker es. Wenn es dann später in einem 
anderen Object-File benötigt wird, ist es nicht mehr da.

von Mehmet K. (mkmk)


Lesenswert?

Rolf, mit dem 1. Abschnitt bin ich einverstanden. Aber der 2. Abschnitt 
leuchtet mir nicht ein.
Werde mir mal bis morgen darüber ein paar Gedanken und ein paar Tests 
machen.

von Mehmet K. (mkmk)


Lesenswert?

Problem gelöst. Die Quelle des Problems lag so um die 90cm vom 
Bildschirm entfernt. Wie immer.

Ich arbeite mich seit 2 Tagen in Em::Blocks ein und war dabei, mir ein 
Template für den von mir benutzten MCU zu erstellen. Ging auch alles 
glatt vonstatten ... bis ich entdeckte, dass man mit Ctrl-H zwischen 
Source und Header springen konnte. Geil! Nur setzte die IDE als 
Header-Extention h und nicht hpp voraus.
Mit den paar Headern die ich hatte war's ein Schnelles, sie von hpp auf 
h zu aendern. Und dabei vergass ich, diese in
1
#ifdef __cplusplus
2
 extern "C" {
3
#endif
4
..
5
#ifdef __cplusplus
6
}
7
#endif
einzubetten.


Asche auf mein Haupt! Und sorry für das unnötige Forums-Rauschen.

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.