carmincludeglobalsimplicity-studio

How to make global definitions in c? Why #pragma once or include guard not working?


I'm on a microcontroller project for a microscope with the EFM32 PG12 starter kit and simplicity studio. In this project I have made some global pin and port definitions in a .h file global_definitions.h

It's done so because complicated. Many functions in different files access the pins directly, thought timers or via the PRS.

here some of global_definitions.h:

#pragma once //not working

#define startUpMessage  "I:000:Initialization finished"

#define prsChannel 6

//pin definitions for the lasers

unsigned int laserPinNumbers[]={2,3,12,13,14,15};
unsigned int laserPorts[]={gpioPortA,gpioPortA,gpioPortD,gpioPortD,gpioPortD,gpioPortD};

unsigned int laserTimers[]={0,0,1,1,1,1};
#define timer0 WTIMER0
#define timer1 WTIMER1

and so on ...

If I try to compile my project I get errors:

arm-none-eabi-gcc -g3 -gdwarf-2 -mcpu=cortex-m4 -mthumb -T "SLM_PG12_3.ld" -Xlinker --gc-sections -Xlinker -Map="SLM_PG12_3.map" -mfpu=fpv4-sp-d16 -mfloat-abi=softfp --specs=nano.specs -o SLM_PG12_3.axf "./CMSIS/EFM32PG12B/startup_efm32pg12b.o" "./CMSIS/EFM32PG12B/system_efm32pg12b.o" "./emlib/em_cmu.o" "./emlib/em_core.o" "./emlib/em_gpio.o" "./emlib/em_prs.o" "./emlib/em_rtc.o" "./emlib/em_rtcc.o" "./emlib/em_system.o" "./emlib/em_timer.o" "./emlib/em_usart.o" "./emlib/udelay.o" "./src/i2c.o" "./src/izi_usart.o" "./src/laserSequences.o" "./src/leds.o" "./src/main.o" -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group
./src/leds.o:/home/grafmakula/SimplicityStudio/v4_workspace/SLM_PG12_3/GNU ARM v7.2.1 - Debug/../src/global_definitions.h:12: multiple definition of `laserPinNumbers'
./src/laserSequences.o:/home/grafmakula/SimplicityStudio/v4_workspace/SLM_PG12_3/GNU ARM v7.2.1 - Debug/../src/global_definitions.h:12: first defined here
./src/leds.o:/home/grafmakula/SimplicityStudio/v4_workspace/SLM_PG12_3/GNU ARM v7.2.1 - Debug/../src/global_definitions.h:13: multiple definition of `laserPorts'
./src/laserSequences.o:/home/grafmakula/SimplicityStudio/v4_workspace/SLM_PG12_3/GNU ARM v7.2.1 - Debug/../src/global_definitions.h:13: first defined here
...
collect2: error: ld returned 1 exit status
make: *** [SLM_PG12_3.axf] Error 1

The include guard

#ifndef GLOBAL_DEFINITIONS
#define GLOBAL_DEFINITIONS
...
#endif

also not working.

Waht is the right way to make global defintitions in c?

Thanks.


Solution

  • #pragma once guards a header file from multiple inclusions while compiling a single source file. So, if you compile leds.c and try to include this file multiple times, probably from other includes file of various level of inclusion, the pragma guarantees that the file only parsed once during this compilation. Same happens when you compile laserSequences.c.

    Now you have compile at least 2 source files inte .o form. Every one has included the header file once and every one has declares global variables from this header file. Linker complains because it does not know which one to use.

    The way around is to never declare variables in header files. You only provide definitions of their external linkage. The declaration must be done in one and only ond of the source files, for example:

    global_definitions.h:

    #pragma once 
    
    #define startUpMessage  "I:000:Initialization finished"
    #define prsChannel 6
    
    extern unsigned int laserPinNumbers[];
    extern unsigned int laserPorts[];
    extern unsigned int laserTimers[];
    ...
    

    now in one of the .c files, either in one you have or yet in some other, for example, global_definitions.c you can declare the vars:

    unsigned int laserPinNumbers[]={2,3,12,13,14,15};
    unsigned int laserPorts[]={gpioPortA,gpioPortA,gpioPortD,gpioPortD,gpioPortD,gpioPortD};
    
    unsigned int laserTimers[]={0,0,1,1,1,1};
    

    Also, #pragma once is a relatively recent addition (it might not work in older versions of the compiler) to the standard which replaces guard macros. They work the same ways.