compiler reports "multiple definition" for a symbol which does not occur there

[solved]
hi, I am totally upset >:(

compilation of my project results in following error message:

Arduino: 1.6.12 (Windows 7), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

sketch\SimpleSDAudio.cpp.o (symbol from plugin): In function `SdPlayClass::setFile(char*)':

(.text+0x0): multiple definition of `SerMonitor'

sketch\EPD_grapp.cpp.o (symbol from plugin):(.text+0x0): first defined here

c:/zusprogs/arduino/arduino-1.6.12/portable/packages/arduino/tools/avr-gcc/4.9.2-atmel3.5.3-arduino2/bin/../lib/gcc/avr/4.9.2/../../../../avr/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions

sketch\VoiceSMSClientDisplay.ino.cpp.o (symbol from plugin): In function `getDateTime()':

(.text+0x0): multiple definition of `SerMonitor'

sketch\EPD_grapp.cpp.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board Arduino/Genuino Mega or Mega 2560.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

The icons within the error message are made by the software of this posting.

My project consists of the following files:
in H:\Arduino\examples\GSM_Shield_gboard_pro\VoiceSMSClientDisplay
VoiceSMSClientDisplay.ino
EPD_grapp.cpp
EPD_grapp.h
SimpleSDAudio.cpp
SimpleSDAudio.h
epd.cpp
epd.h
in H:\Arduino\examples\libraries\GSM_GP
GSM_GP.h
GSM_GP.cpp
inetGSM_GP.h
inetGSM_GP.cpp

The locations where multiple definitions are reported are all in the first directory:
SdPlayClass::setFile(char*) in SimpleSDAudio.cpp
getDateTime() in VoiceSMSClientDisplay.ino

The function "search in files" of Notepad++ gives the following result when searching for "SerMonitor" in the first directory (...\examples\GSM_Shield_gboard_pro\VoiceSMSClientDisplay):

Search "SerMonitor" (36 hits in 3 files)
H:\Arduino\examples\GSM_Shield_gboard_pro\VoiceSMSClientDisplay\EPD_grapp.cpp (1 hit)
Line 455: if (SerMonitor) Serial.print(ws);
H:\Arduino\examples\GSM_Shield_gboard_pro\VoiceSMSClientDisplay\EPD_grapp.h (1 hit)
Line 32: boolean SerMonitor=false; // true, wenn Serial Monitor angeschlossen ist
H:\Arduino\examples\GSM_Shield_gboard_pro\VoiceSMSClientDisplay\VoiceSMSClientDisplay.ino (34 hits)
Line 204: if (i+digitalRead(A11) == 2) Serial.println(F("SerMonitor wäre true"));
Line 210: // SerMonitor = true;
Line 214: SerMonitor=true;
Line 215: if (SerMonitor) {
Line 239: if (SerMonitor) Serial.println(F("PIN ist OK"));
Line 242: if (SerMonitor) Serial.println(F("PIN nicht akzeptiert!"));
Line 248: if (SerMonitor) Serial.println(F("keine PIN erforderlich"));
Line 252: if (SerMonitor)
Line 257: if (SerMonitor) Serial.println(F("\nstatus=NOT_RGISTERED, try again"));
Line 271: if (SerMonitor) {
Line 281: if (SerMonitor)
Line 285: if (SerMonitor)
Line 289: if (SerMonitor) {
Line 300: if (SerMonitor)
Line 307: if (SerMonitor) {
Line 350: // if (SerMonitor)
Line 356: if (SerMonitor) {
Line 363: if (SerMonitor) Serial.print(F("TALKING: "));
Line 378: if (SerMonitor) Serial.print(F("start Playlist, "));
Line 381: if (SerMonitor) Serial.print(F("stopped, "));
Line 384: if (SerMonitor) Serial.println(F("Anruf beendet"));
Line 392: if (SerMonitor) {
Line 399: if (SerMonitor) {
Line 426: if (SerMonitor) {
Line 442: // if (SerMonitor) {
Line 458: if (SerMonitor) Serial.print(c);
Line 479: if (SerMonitor) {
Line 493: if (SerMonitor) {
Line 499: else if (SerMonitor) Serial.println(F("unbekannte Daten vom Funkempfaenger!!"));
Line 519: if (SerMonitor) {
Line 542: if (SerMonitor) {
Line 549: if (SerMonitor) Serial.println(F("sendHTTPdata() failed"));
Line 555: if (SerMonitor) Serial.println(F("setupGPRSConnection() failed"));
Line 561: if (SerMonitor) {

This shows that there is only one definition of SerMonitor within EPD_grapp.h.
In the functions SdPlayClass::setFile(char*) and getDateTime() there is no use of SerMonitor at all.

within SimpleSDAudio.cpp:

boolean SdPlayClass::setFile(char *fileName) {
  if(!_pBuf) {
    _lastError = SSDA_ERROR_NOT_INIT;
    return(false);
  }
  uint8_t retval;
  stop();
  _fileinfo.Size = 0;
  retval = SD_L2_SearchFile((uint8_t *)fileName, 0UL, 0x00, 0x18, &_fileinfo);
  
  if(retval) {
     _lastError = retval;
     return(false);
  } else {
		start_sec_file = _fileinfo.ActSector;
		anzsect = (_fileinfo.Size + 511)/512;
     return(true);
  }
}


within VoiceSMSClientDisplay.ino:

char* getDateTime(void) {
  // liefert einen Pointer auf den Datum-/Zeitstring vom GSM-String, sonst n.a.
  char* ptDate;
  if (gsm.SendATCmdWaitResp("AT+CCLK?",500,100,"OK",1)==1) {
    ptDate=strchr((char*)gsm.comm_buf,34)+1; // sucht nach "
    ptDate[17]=0; // der Rest wird abgeschnitten
    return (ptDate);
  }
  else {
    strcpy((char*)gsm.comm_buf,"n.a.");
    return((char*)gsm.comm_buf);
  }
}

How can the compiler report multiple definitions for a symbol which does not occur at the reported location?

Here in the forum I read about some preprocessing of the IDE and an example when this preprocessing results in an error "undefined symbol". But I cannot imagine that the preprocessing could result in my error message.

Can somebody give me tips to solve this mystery?
( I guess that further code is not necessary. The "search in file" results shows all locations where SerMonitor is used)

If somebody is interested in a very long verbose output of the compilation, then look into the attachment. The overall text is loo long for posting.

This verbose output does not help me. I cannot see why the error message occurs.

verbose_compile.txt (25.9 KB)

The icons within the error message are made by the software of this posting.

Sure blame someone else when it is your fault. The smiley faces are there because YOU did not use code tags.

My project consists of the following files:

It seems likely that you are using more than that.

However, since you only posted snippets of code, we can NOT help you. Good luck.

yes, there are some more in the library directory H:\Arduino\examples\libraries\SimpleSDAudio.

But the "search in files" for "SerMonitor" does not find any occurancies there.

It is not likely that there are really separate declarations of SetMonitor. It IS likely that the file that contains the declaration is included in more than one compilation unit, resulting in the symbol in multiple .o files which the linker sees.

The only location I could find, where SerMonitor is defined, really is within EPD_grapp.h

boolean SerMonitor=false;   // true, wenn Serial Monitor angeschlossen ist

When I delete this line and then compile, then I get errors at the locations within my sketch VoiceSMSClientDisplay.ino where SerMonitor is referenced.

In my understanding this is the proof that SerMonitor is defined only once, is'nt it?

In my code SerMonitor is used to decide if Serial.print's shall be performed.
These decisions are needed once within EPD_grapp.cpp and many times within VoiceSMSClientDisplay.ino.
Therefore the definition of SerMonitor is done within EPD_grapp.h which is included both in EPD_grapp.cpp and VoiceSMSClientDisplay.ino.
At the beginning of my sketch VoiceSMSClientDisplay.ino there is a test if SerMonitor shall be true or false, and the value is set correspondingly. It should be allowed to assign a value to a variable which is defined in a header file when the header file is included.

Now I moved the definition of SerMonitor to VoiceSMSClientDisplay.ino and deleted the reference to it within EPD_grapp.cpp - and everything is ok.
Well, it's fine to have a solution, but I do not understand this at all :frowning:

How many files include the header file where SerMonitor was defined? How many of them are compiled separately?

Now that the definition is in a file that is compiled once, there are no duplicate symbols. I don't think that that is that hard to understand.

I don't know how the IDE is generating the code for my controller.

If there are files which are compiled separately then I understand what happened.
But I don't know what files are compiled separately and what files are compiled together.
Is there a common rule for that?

Generally it is very important to know that. Up to now I believed that protecting header files with

#ifndef __filename_H__
#define __filename_H__
...
#endif

against being included more than once is a safe method to avoid multiple definitions.
If files are compiled separately then there is no protection against multiple definitions but the brain of the designer of the code.

Up to now I believed that protecting header files with...against being included more than once is a safe method to avoid multiple definitions.

It does, in ONE compilation unit. It does nothing when there are multiple compilation units.

If files are compiled separately then there is no protection against multiple definitions but the brain of the designer of the code.

Exactly. Which is why variable declarations do not belong in header files.

SupArdu:
If there are files which are compiled separately then I understand what happened. But I don't know what files are compiled separately and what files are compiled together. Is there a common rule for that?

Every .cpp file in your sketch folder is compiled separately. If you rename them to .ino they will be merged together and compiled as a single file.

SupArdu:
Up to now I believed that protecting header files with

#ifndef __filename_H__

#define filename_H
...
#endif



against being included more than once is a safe method to avoid multiple definitions. If files are compiled separately then there is no protection against multiple definitions but the brain of the designer of the code.

That is why you should declare global variables in the .cpp file, not in the .h file. If you want to be able to reference the global in another file you can put:

extern boolean SerMonitor;   // true, wenn Serial Monitor angeschlossen ist

in the EPD_grapp.h. That will tell the compiler that the variable is declared somewhere else.