Black Mamba
Black Mamba

Reputation: 31

Why one definition rule (ODR) is not honoured by g++ in this case ? .

As you see, there are multiple definitions of testfn symbol while linking, but the linker takes the first occurence (in linking order) and ignores the other occurances in other libraries. This probably is the way how the linker works.

But Is there any way to enforce linker to flag error on seeing multiple symbols in different linked libraries ? Or any other options to catch such duplicate definitions ?


Content of test1.h:

#ifndef TEST1
#define TEST1
void testfn();
#endif

Content of test1.cpp

#include "test1.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file1" << endl;
}

Content of test.h:

#ifndef TEST
#define TEST
void testfn();
#endif

Content of test.cpp:

#include "test.h"
#include <iostream>
using namespace std;
void testfn()
{
cout << "file" << endl;
}

Content of main.cpp:

#include "test.h"
#include "test1.h"

int main()
{
testfn();
return 0;

}

Created a shared libraries.

 g++ -fPIC -shared libtest1.so test1.cpp
 g++ -fPIC -shared libtest.so test.cpp

Created executable with library order#1

g++ -o main main.cpp -ltest -ltest1

Created executable with library order#2

g++ -o main1 main.cpp -ltest1 -ltest

Ouput of main

./main
file

Ouput of main1

 ./main1
file1

Upvotes: 2

Views: 822

Answers (2)

Michael Burr
Michael Burr

Reputation: 340218

I don't see a way to get GNU ld to complain about multiple symbol definitions across shared libraries. However, if normal static library archives are involved, you might be able to use the --whole-archive/--no-whole-archive set of options to get what you want:

For example, after building libtest.a and libtest1.a instead of the shared library versions, I get no errors with the following link commands:

$ g++  -o main main.cpp   -ltest1 -ltest  -L.
$ ./main
file1

$ g++  -o main main.cpp   -ltest -ltest1  -L.
$ ./main
file

But do get errors for the following:

$ g++  -o main main.cpp -Wl,--whole-archive -ltest1 -ltest -Wl,--no-whole-archive -L.
./libtest.a(test.o): In function `testfn()':
test.cpp:(.text+0x0): multiple definition of `testfn()'
./libtest1.a(test1.o):test1.cpp:(.text+0x0): first defined here
collect2: ld returned 1 exit status

I'm not sure you would want to use --whole-archive for release builds - maybe only as a sanity check for possibly name conflicts (I think that using --whole-archive normally will increase the size of your binary for no good reason).

Also, as mentioned before, this seems to have no effect on shared libraries.

Upvotes: 0

James Curran
James Curran

Reputation: 103515

First of all, it is honoring the ODR, by only taking one of the methods out of the library. And that's just the way shared libraries work.

If you want to see the compiler complain about this, link them all together, without the library step.

g++ -o main1 main.cpp test1.cpp test.cpp

So your question becomes, "How do I tell if I have two libraries which both contain a indentifier with the same name?" Keep in mind that this is often not a problem and sometimes done intentionally. I'd suggest running the library tool (I'm not familiar with the g++ toolset) to get listing of the libraries, and run DIFF of them.

Upvotes: 2

Related Questions