8 years ago.

Multiply defined symbol despite #ifndef

Hi,

I've run into an annoying problem. I've split my program into several files, and made a library folder for my oPPM.cpp and its header oPPM.h. My include structure works like this oPPM.h -> core.h -> main.cpp. But I get the following error for all lines in my file oPPM.h: Error: Symbol PPMChannels multiply defined (by oPPM.LPC1768.o and main.LPC1768.o).

And I cannot understand why, in my mind #ifndef should make sure I get no duplicate definitions right?

oPPM.h

#ifndef oPPM_H
#define oPPM_H

#include "mbed.h"
#define PPMPulseLength 300 //high pulse length in uS
#define PPMFrameLength 20  //total frame length in mS

DigitalOut PPM_output(p21);
DigitalOut PPM_sync(p22);

/**
* variables
*/

int PPMChannels[16];
unsigned int activeChannels;
unsigned int currentChannel;
bool PPMActive;
bool PPMFrameStarted;
    
Ticker FrameTicker;
Timeout ChannelTimer;

void PPM_Init(unsigned int numberOfChannels);
void PPM_start(void);
void PPM_stop(void);
void PPM_PulseHandler(void);
void PPM_PulseTimeout(void);
void PPM_Inactive(void);

#endif /* oPPM_H */

My common.h

core.h

#include "stdio.h"
#include "mbed.h"
#include "SPI_TFT_ILI9341.h"
#include "string"
#include "Arial12x12.h"
#include "Arial24x23.h"
#include "QEI.h"
#include "oPPM.h"
#include "TFTBattery.h"

My code in oPPM.cpp:

oPPM.cpp

/**
 * @author Olle Sköld
 *
 * @section LICENSE
 *
*/ 
#include "oPPM.h"

void PPM_init(unsigned int numberOfChannels){
    activeChannels = numberOfChannels;
    currentChannel = 0;
    PPMActive = false;    
    PPMFrameStarted = false;
}

void PPM_start(void) {
    PPMActive = true;
    FrameTicker.attach_us(&PPM_PulseHandler, PPMFrameLength);
}

void PPM_stop(void) {
    PPMActive = false;
    FrameTicker.attach_us(&PPM_Inactive, PPMFrameLength);
}

void PPM_PulseHandler(void){
    PPM_output = 1;
    //start first pulse
    ChannelTimer.attach_us(&PPM_PulseTimeout, PPMPulseLength);
        
    if(currentChannel == 0){
        PPM_sync = 1;           //if this is the start pulse, switch sync pin high
    }

}
void PPM_PulseTimeout(void){
    PPM_output = 0;
    
    //Load current channel and start timer for low part
    //First, check if this was the stop pulse
    if(currentChannel == activeChannels){
        PPM_sync = 0;           //swtich sync pin low after stop bit
        return;
    } else {
        //if it wasn't the stop pulse
        ChannelTimer.attach_us(&PPM_PulseHandler, PPMChannels[currentChannel]);
    }
}

//function will be called by frame ticker if PPM is inactivated after it has been started
void PPM_Inactive(void){
    PPM_sync = !PPM_sync;   //toggle sync output when inactive
}

My main.cpp only includes core.h

Thanks in advance! I have a feeling I'm missing something simple.. :S

1 Answer

8 years ago.

Hi Olle,

In your header file (oPPM.h), you are defining variables in the global scope instead of declaring them. As a result, every source file which include oPPM.h will define contain a definition for those variables. During the link, the linker see a variable with the same identifier, the result is an error. The C++ mandate that in any translation unit, a template, type, function, or object can have no more than one definition. Hence the error.

What you can do is just declare those variables in the header file and provide a definition in your cpp file.

aPPM.h

#ifndef oPPM_H
#define oPPM_H
 
#include "mbed.h"
#define PPMPulseLength 300 //high pulse length in uS
#define PPMFrameLength 20  //total frame length in mS
 
/**
* variables
*/

// Note the use of the extern keyword which indicate to the compiler that the variable is defined somewhere else.
extern DigitalOut PPM_output;
extern DigitalOut PPM_sync;
  
extern int PPMChannels[16];
extern unsigned int activeChannels;
extern unsigned int currentChannel;
extern bool PPMActive;
extern bool PPMFrameStarted;
    
extern Ticker FrameTicker;
extern Timeout ChannelTimer;
 
void PPM_Init(unsigned int numberOfChannels);
void PPM_start(void);
void PPM_stop(void);
void PPM_PulseHandler(void);
void PPM_PulseTimeout(void);
void PPM_Inactive(void);
 
#endif /* oPPM_H */

aPPM.cpp

/**
 * @author Olle Sköld
 *
 * @section LICENSE
 *
*/ 
#include "oPPM.h"
 
/**
* variables
*/

// global definitions goes here
DigitalOut PPM_output(p21);
DigitalOut PPM_sync(p22);
  
int PPMChannels[16];
unsigned int activeChannels;
unsigned int currentChannel;
bool PPMActive;
bool PPMFrameStarted;
    
Ticker FrameTicker;
Timeout ChannelTimer;

void PPM_init(unsigned int numberOfChannels){
    activeChannels = numberOfChannels;
    currentChannel = 0;
    PPMActive = false;    
    PPMFrameStarted = false;
}
 
void PPM_start(void) {
    PPMActive = true;
    FrameTicker.attach_us(&PPM_PulseHandler, PPMFrameLength);
}
 
void PPM_stop(void) {
    PPMActive = false;
    FrameTicker.attach_us(&PPM_Inactive, PPMFrameLength);
}
 
void PPM_PulseHandler(void){
    PPM_output = 1;
    //start first pulse
    ChannelTimer.attach_us(&PPM_PulseTimeout, PPMPulseLength);
        
    if(currentChannel == 0){
        PPM_sync = 1;           //if this is the start pulse, switch sync pin high
    }
 
}
void PPM_PulseTimeout(void){
    PPM_output = 0;
    
    //Load current channel and start timer for low part
    //First, check if this was the stop pulse
    if(currentChannel == activeChannels){
        PPM_sync = 0;           //swtich sync pin low after stop bit
        return;
    } else {
        //if it wasn't the stop pulse
        ChannelTimer.attach_us(&PPM_PulseHandler, PPMChannels[currentChannel]);
    }
}
 
//function will be called by frame ticker if PPM is inactivated after it has been started
void PPM_Inactive(void){
    PPM_sync = !PPM_sync;   //toggle sync output when inactive
}

Accepted Answer

Thanks! That solved the problem! :) I thought the #ifndef would define once for the whole project, not once for each cpp file.

posted by Olle Sköld 24 Nov 2016