appleline
appleline

Reputation: 27

C++: duplicate symbol using Makefile and object declaration


I have a struct defined in
a.h

#IFNDEF
#define A_H
struct a_struct
{
int val;
int val_b;
}a;
#endif

and both main.cpp and a.cpp included the header

#include "a.h"

when I use makefile with the following:

a.o: a.cpp a.h
    g++ -std=c++11 -c $<
main.o: main.cpp a.h
    g++ -std=c++11 -c $<
main: main.o a.o
    g++ -std=c++ $^ -o $@

A compilation error occurs:

duplicate symbol '_a' in:
    a.o
    main.o

Is a being redefined in a.cpp and main.cpp? Is there a way to resolve this issue without changing a.h?
In case that's not possible, how may I change the code? Thank you in advance :)

Upvotes: 0

Views: 123

Answers (1)

John Bollinger
John Bollinger

Reputation: 180161

The problem is that a.h both declares a data type struct a_struct and declares a as a variable of that type. Each translation unit that includes that header -- for example, the one based on a.cpp and the one based on main.cpp will therefore declare its own a, and if two such translation units contribute to the same program then undefined behavior results. The program being rejected on account of duplicate symbols is one possible (and fairly common) manifestation of the UB arising from such circumstances.

So,

Is a being redefined in a.cpp and main.cpp?

Yes. The declaration of a included into the translation unit of each of those source files directly causes a to be defined in each. Technically, these declarations are not themselves the definitions, but that's a bit hair-splitting.

Is there a way to resolve this issue without changing a.h?

If the program were modified so that only one translation unit in it #includes a.h, whether directly or indirectly, then it would not have multiple definitions of a (from the source it now has them). It is unclear whether that would be a viable solution for you, but that seems doubtful.

In case that's not possible, how may I change the code?

The simplest change would be to remove the declaration of a from a.h:

#ifndef A_H
#define A_H
struct a_struct
{
int val;
int val_b;
};  // <-- the main change is here
#endif

If you actually need an external variable a of type struct a_struct then you should declare it extern in the header by adding

extern struct a_struct a;

to the header

AND

adding a non-(explicitly-)extern declaration of a in exactly one of the .cpp files:

struct a_struct a;

From its name, it seems like file a.cpp would be the right place for the latter, but if you don't want to modify that then you can use main.cpp instead.

Upvotes: 1

Related Questions