__stdout multiply defined

OP #1592790
Lesenswert?

Hi,

ich bin gerade dabei für ein STM32 Derivat Routinen für den USART1 und 
USART2 zu schreiben. Die einzelnen Routinen sollen dann in eigene 
C-Files (usart1.c und usart2.c)  mit zugehörigen Headerfiles ausgelagert 
werden. Jedes C-File für sich kann ich in mein Projekt einbinden und die 
darin enthaltenen Funktionen problemlos aufrufen. Doch wenn ich die 
beiden Dateien gleichzeitig in mein Projekt einbinde, dann bekomme ich 
diese Fehlermeldungen:

USART.axf: Error: L6200E: Symbol __stdout multiply defined (by usart1.o 
and usart2.o).
USART.axf: Error: L6200E: Symbol __stdin multiply defined (by usart1.o 
and usart2.o).

Die beiden C-Files sind folgendermaßen aufgebaut:

.) usart1.c
1
#include "stm32f10x.h"
2
#include <stdio.h>
3
#include "usart1.h"
4

5
struct __FILE { int handle; };
6
FILE __stdout;
7
FILE __stdin;
8

9
#define PUTCHAR_PROTOTYPE_USART1 int fputc(int ch, FILE *f)
10

11
void usart1_init (unsigned long baudrate) {
12

13
[.....]
14
}
15

16
int SendChar (char ch)  {
17
[.....]
18
}
19

20
int GetChar (void)  {
21
[.....]
22
}
23

24
PUTCHAR_PROTOTYPE_USART1
25
{
26
  SendChar((char) ch);
27
  return ch;
28
}


.) usart2.c
1
#include "stm32f10x.h"
2
#include <stdio.h>
3
#include "usart2.h"
4

5
struct __FILE { int handle; };
6
FILE __stdout;
7
FILE __stdin;
8

9
#define PUTCHAR_PROTOTYPE_USART2 int fputc(int ch, FILE *f)
10

11
void usart2_init (unsigned long baudrate) {
12

13
[.....]
14
}
15

16
int SendChar1 (char ch)  {
17
[.....]
18
}
19

20
int GetChar1 (void)  {
21
[.....]
22
}
23

24
PUTCHAR_PROTOTYPE_USART2
25
{
26
  SendChar1((char) ch);
27
  return ch;
28
}

Ich versteh zwar, dass der Fehler durch den struct __FILE Block 
verursacht wird, aber wie kann ich das Problem beseitigen?

Danke!

PS: Ich verwende uVision3 von KEIL
OP #1592822
Lesenswert?

Ich muss gestehen, ich hab diesen Block ganz frech aus dem Retarget.c 
File von KEIL geklaut. Ich hab das Schlüsselwort extern jetzt 
hinzugefügt, die beiden Fehler sind verschwunden. Leider hab ich aber 
vorhin eine Fehlermeldung übersehen:
USART.axf: Error: L6200E: Symbol fputc multiply defined (by usart1.o and 
usart2.o).

PS: In einem PDF von ARM hab ich folgendes gefunden:

Symbol __stdout multiply defined (by retarget.o and stdio.o).
This means that there are two conflicting definitions of __stdout 
present – one in
retarget.o, the other in stdio.o. The one in retarget.o is your own 
definition. The
one in stdio.o is the default implementation, which was probably 
linked-in inadvertently.
stdio.o contains a number symbol definitions and implementations of file 
functions like
fopen, fclose, fflush, etc. stdio.o is being linked-in because it 
satisfies some
unresolved references.
To identify why stdio.o is being linked-in, you must link with the 
linker's "verbose" switch,
e.g.:
armlink [... your normal options...] -verbose -errors err.txt
Then study err.txt, so see exactly what the linker is linking-in, from 
where, and why.
To move forward, the user may have to either:
- Eliminate the calls like fopen, fclose, fflush, etc, or
- Re-implement the _sys_xxxx family of functions.

Kann damit jemand etwas anfangen? Ich bin da leider nicht so ganz firm, 
was diese Sachen angeht...
Gast #1592865
Lesenswert?

>vorhin eine Fehlermeldung übersehen:
>USART.axf: Error: L6200E: Symbol fputc multiply defined (by usart1.o and
>usart2.o).

Dann mach ein fputc1() für USART1 und fputc2() für USART2.
stdout kannst du aber nur für EINEN der beiden USARTS
sinnvoll verwenden.
#1593145
Lesenswert?

Bernhard B. schrieb:
> Hab gerade das gefunden: http://www.keil.com/support/docs/2014.htm
> Aber jedes Mal vorher das Target auswählen...ich weiß nicht...

Und wie stellst du dir dann vor dass zb printf wissen soll auf welche 
UART du ausgeben willst?

Du gehst das völlig falsch an.

Die Idee hinter dem Ganzen besteht darin, dass man sich in Analogie zu 
stdout ein zweites Symbol einführt, welches zb für die UART 2 steht.

stdprint würde sich zb anbieten.

Du hast nur eine EINZIGE Funktion fputc (Ich geh mal davon aus, dass das 
Makro PUTCHAR_PROTOTYPE_USART1 bzw PUTCHAR_PROTOTYPE_USART2 diese 
Funktion erzeugt) und diese Funktion verteilt dann das Zeichen je nach 
übergebenem File Argument auf die richtige UART

dann kannst du schreiben

  printf( "Hallo Welt" );
oder
  fprintf( stdout, "Holle Welt" );

und die Ausgabe geht auf UART 1 raus. Schreibst du aber

  fprintf( stdprint, "Hallo Welt" );

dann geht der Text auf der anderen USAR raus.


Es bringt nichts, sich an Internals der Stream Verwaltung und 
Verarbeitung zu vergreifen, wenn man das Prinzip nicht verstanden hat.

Und im übrigen wird eine Weiterleitung über printf IMHO sowieso 
überschätzt. Auf einem µC ist das viel Aufwand für fast nichts.

Viel einfacher ist es, wenn man sich für jedes Gerät eine 
Stringausgabefunktion macht und dann mittels sprintf (oder sonstigen 
Funktionen) und diesen speziellen String Ausgabefunktionen arbeitet.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren