Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
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 }