1

I have a relatively small project with only a few files (.c and .h). I have been fighting multiple inclusion errors (I think). So, I created a master.h header file that has each of the other header files that are needed. ALL of the header files have the

#ifndef _MY_HEADER
#define _MY_HEADER
… Header body
#endif

guards to prevent multiple inclusion. Each of my files includes the master.h file at the top. Here is how I would expect this to work.

  1. The first file that was compiled would see the #include "master.h"
  2. Since this is the first time that this file is processed __MASTER would not have been defined yet, so it would process the file.
  3. The compiler would come to the inclusion of the next header file, an similarly, it would have not been processed yet, so the complier would process it, then it would be defined, and would not be processed again.
  4. This continues for all the header files in the master.h until all the files have been processed, and defined so they won't be processed again.
  5. The same is true of the master.h file. Once it's processed, and completed, it won't be processed again due to the guard.

Shouldn't this prevent multiple inclusion?

So here are the errors.

Building target: My_Project_Bootloader.axf
Invoking: GNU ARM C Linker
arm-none-eabi-gcc -g3 -gdwarf-2 -mcpu=cortex-m3 -mthumb -T "C:/Users/Greg/SimplicityStudio/v4_workspace/My_Project_Bootloader/GNU ARM v4.9.3 - Debug/My_Project_Bootloader_custom.ld" -nostdlib -L"C:\GCC_STUFF" --specs=nosys.specs -Xlinker --gc-sections -Xlinker -Map="My_Project_Bootloader.map" -lm -lgcc -lc -o My_Project_Bootloader.axf "./Source/aeabi_memset-thumb.o" "./Source/crt0.o" "./Source/em_emu.o" "./Source/functions.o" "./Source/main.o" "./Source/startup_efm32jg1b.o" "./Source/interrupts.o" 
./Source/main.o:(.rodata.const_ModBusIDReg+0x0): multiple definition of `const_ModBusIDReg'
./Source/functions.o:(.rodata.const_ModBusIDReg+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
make: *** [My_Project_Bootloader.axf] Error 1

I've edited/removed some of the information in this post because it turns out it is unrelated. It appears that the "multiple definition" problems the linker was having was not due to actual "multiple definitions", or inclusions for any variable. Instead, it appears as if it was due to declaring and defining the variable (in this case a const in flash) at the same time. Once I split the declaration(s) into a header file, and the actual definition or assignment into a .c file, the problems went away. Here is an example of the fix for one of the problem "variables". I will pay much closer attention to the declaration and definition aspects of variables now. The tools used was GCC. Thank you for all the comments.

// boot.h
// declare const array
const unsigned char const_ModBusIDReg[7][48];


// boot.c
#include boot.h

// define const array
const unsigned char const_ModBusIDReg[7][48] =
{
"String1",          // reg00
"String2",          // reg01
"String3",          // reg02
"String4",          // reg03
"String5",          // reg04
"String6",          // reg05
"String7"           // reg06
 };
  • Note that you should not create function or variable names that start with an underscore, in general. [C11 §7.1.3 Reserved identifiers](https://port70.net/~nsz/c/c11/n1570.html#7.1.3) says (in part): — _All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use._ — _All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces._ See also [What does double underscore (`__const`) mean in C?](https://stackoverflow.com/a/1449301/15168) – Jonathan Leffler May 17 '18 at 15:42
  • I've removed the leading underscore(s) from each multiple inclusion guard name, and the error results are the same. I was hoping that the ".gnu.linkonce.sectionname" in the linker script file would prevent multiple inclusion at link time, but I guess I don't understand what this does. – Gregory Helton May 17 '18 at 15:59
  • The spelling of the header guards is a minor issue, and tangential to the main problem, which is that you are probably defining rather than declaring global variables in the headers. Make sure that the headers _declare_ rather than _define_ the variables. See also [How do I use `extern` to share variables between source files?](https://stackoverflow.com/questions/1433204/15168) – Jonathan Leffler May 17 '18 at 16:03
  • Although I have lots of defines, they are used for constants rather than variables. Here is an example of XmitBuf and RcvBuf problem. This is to force these buffers into fixed sections that are exactly the size needed, and they are only declared in one place in one header file. __attribute__( ( section(".xmitbuf")))unsigned char XmitBuf[256]; __attribute__( ( section(".rcvbuf") ) )unsigned char RcvBuf[256]; – Gregory Helton May 17 '18 at 17:27
  • Well, the header that contains those definitions can only be included in one source file. However, the names you quote are not the ones the linker complains about. You probably have similar definitions for the names in the error messages. Those need to be similar to `extern __attribute__( ( section(".xmitbuf")))unsigned char XmitBuf[256];` etc, preceded by `extern`, in the header, and then one (and only one) source file contains the declaration without the `extern`. What you've got isn't working; you're going to have to change it. It's hard to help more without source code (see MCVE — [MCVE]). – Jonathan Leffler May 17 '18 at 17:37
  • I have taken all variable definitions (where memory is allocated), and put them into one source file "boot.c", then I have most of the #defines, and put them into a single header file "boot.h" along with the function protos. Both of these files are guarded against multiple inclusion. Also, the extern keyword was taken off the variable declarations. The result is the same - pretty much the same error message as the original post. How can there be duplicate definitions ? There are now only two files which allocate/define everything, and no duplicates within them . – Gregory Helton May 17 '18 at 21:13
  • If you want more help, you're gonna need to produce an MCVE. It'll need two source files and one header. It needs to reproduce the multiple definition linking error, but it doesn't matter what the variable names are. The header will declare/define as you are now; the source files will both include the header, and will compile separately to object code, but fail to link as now. The header should be less than 10 lines long; the source files might be 10-20 lines each — you may be able to reduce the counts still further. – Jonathan Leffler May 17 '18 at 21:48

2 Answers2

0

Usually #ifndef HEADER_NAME like you did avoid any including conflicts. But you said "Each of my files includes the master.h" so i suggest that your .c should not include anything else than they own associated .h. (It might already be the case).

Also, beware of including .c.

I don't know about your linker script but what tool do you use to compile ?

Welgriv
  • 714
  • 9
  • 24
0

The problem is a linker issue, not a per source file issue. It won't be solved by stopping headers from being included multiple times in a single translation unit (TU — source file plus included files).

It appears that you have four symbols (const_ModBusIDReg, const_ModBusRegAttr, const_ModBusRegDefaults, const_ModBusRegLimits) which are defined in multiple source files, possibly because you define rather than declare them in a header.

Variables cited in a header must be prefixed with extern — otherwise, they are definitions, not declarations.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • It should work. Per [**6.2.2 Linkages of identifiers**, paragraph 5](https://port70.net/~nsz/c/c11/n1570.html#6.2.2p5) of the C standard: "If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external." So, leaving off `extern` for file-scope variables has no effect. [Paragraph 2](https://port70.net/~nsz/c/c11/n1570.html#6.2.2p2) states: "In the set of translation units and libraries that constitutes an entire program, each declaration of a particular identifier with external linkage denotes the same object or function." – Andrew Henle May 17 '18 at 16:39
  • Yes, it's linkage is external. It is also a [tentative definition](https://port70.net/~nsz/c/c11/n1570.html#6.9.2), but if there is no alternative (e.g. initialized) definition at the end of the TU, it becomes an actual definition. And then there's [J.5.11](https://port70.net/~nsz/c/c11/n1570.html#J.5.11) that says you'll often get away with it — but clearly, the compiler in use is not letting the OP get away with it. That might be because it uses a strict ODR (one definition rule), or it might be because the header(s) define the variables with initializers. – Jonathan Leffler May 17 '18 at 16:46