how to make ld treat Multiply defined structs/classes as an error?

177 views Asked by At

EDIT-- clarifying the goal of my question: I lose a lot of time diagnosing problems that I expect the linker to report, caused by an admittedly bad programming style, which pops up when e.g. copy-pasting a block of code from one compilation unit to another, and altering it.

I'm looking for a way to detect this problem at compile/link time.

In this setup:

A.h

void foo();

A.cpp

struct A { 
  int values[100];
  A(){ 
    std::cout << __FILE__ << ": A::A()\n";
}};
void foo(){ 
   A a;
}

main.cpp

#include "A.h"
struct A { 
  double values[100];
  A(){ 
  std::cout << __FILE__ << ": A::A()\n";
}};
int main(){ foo(); }
// void foo(){} ===> this would cause a linker error

I would love the linker to report that the structure A, or at least the constructor A::A(), is defined twice.

However, g++ 4.4 links just fine. Running the code shows that in this case, the linker chose to use the A from A.cpp.

$ g++ -Wall A.cpp main.cpp && ./a.out
A.cpp:3
A.cpp:7
A.cpp:3

When a function foo() is present in two object files, the linker reports a multiple definition allright, but for the structures, it doesn't.

EDIT: just found by using nm -C *.o that both A.o and main.o have A::A() defined as a weak symbol. This causes it to be 'selectable' from a pool of symbols with the same name. Maybe the question can be rephrased to "how can I cause the compiler to generate strong symbols?"...

00000000 W A::A()

How can I detect this problem?

2

There are 2 answers

1
Cat Plus Plus On

It's not a problem, and it's not a redefinition. It's how C++ works. Think about it — you put class definitions in headers (exposing just declaration is far less common). Headers are pretty much copy-pasted into every translation unit that uses them. It cannot be an error to have multiple definitions of the same class in multiple TUs. So, it's not something to solve.

Compiler/linker should complain if there are different classes defined under the same name, though.

0
Luc Danton On

Maybe the question can be rephrased to "how can I cause the compiler to generate strong symbols?"...

Try to restrict the use of inline functions:

struct A {
    A();
};

// Inside A.cpp
A::A() { 
    std::cout << __FILE__ << ": A::A()\n";
}

An implementation is much more likely to report an ODR violation for a function that is not declared inline (including those that are implicitly declared inline, like members defined inside a class definition), although strictly speaking such a diagnostic is never required.