Solved

Expecting linker duplicate symbol error, but not getting it!

Posted on 2014-04-10
9
718 Views
Last Modified: 2014-04-18
Ah hello.

I am looking in more depth at Linux programming, right now static libraries.  I have the following code:
/* 
Library.h
*/
#ifndef LIBRARY_H
#define	LIBRARY_H

#ifdef	__cplusplus
extern "C" {
#endif

    int GetMagicNumber();


#ifdef	__cplusplus
}
#endif

#endif	/* LIBRARY_H */


/* 
Library.c
*/
int GetMagicNumber()
{
	 return 42;
}

/* 
Library 2.c
*/
int GetMagicNumber()
{
	 return 42 * 2;
}

/* 
Main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include "../StaticLibrary/Library.h"


int main(int argc, char** argv) {

    printf("%d\n", GetMagicNumber());
    return (EXIT_SUCCESS);
}

int GetMagicNumber()
{
	 return 7;
}

Open in new window


Now, first of all I wouldn't have expected the static library to build as it has two different implementations of GetMagicNumber().  Secondly, I thought main.c would complain since it effectively has three versions of GetMagicNumber() to chose from!

The program runs and outputs 7.

I am building this with Netbeans on Windows 7 using a remote Linux host.  The build output is as follows:

"/usr/bin/gmake" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
gmake[1]: Entering directory `/home/wad/Code/NetBeansProjects/CApp'
cd ../StaticLibrary && /usr/bin/gmake  -f Makefile CONF=Debug
gmake[2]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
gmake[3]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake"  -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[4]: Entering directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/Library.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/Library.o.d" -o build/Debug/GNU-Linux-x86/Library.o Library.c
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/Library2.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/Library2.o.d" -o build/Debug/GNU-Linux-x86/Library2.o Library2.c
mkdir -p dist/Debug/GNU-Linux-x86
rm -f dist/Debug/GNU-Linux-x86/libstaticlibrary.a
ar -rv dist/Debug/GNU-Linux-x86/libstaticlibrary.a build/Debug/GNU-Linux-x86/Library.o build/Debug/GNU-Linux-x86/Library2.o 
ar: creating dist/Debug/GNU-Linux-x86/libstaticlibrary.a
a - build/Debug/GNU-Linux-x86/Library.o
a - build/Debug/GNU-Linux-x86/Library2.o
ranlib dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[4]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
gmake[3]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
gmake[2]: Leaving directory `/home/wad/Code/NetBeansProjects/StaticLibrary'
"/usr/bin/gmake"  -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/capp
gmake[2]: Entering directory `/home/wad/Code/NetBeansProjects/CApp'
mkdir -p build/Debug/GNU-Linux-x86
rm -f "build/Debug/GNU-Linux-x86/main.o.d"
gcc    -c -g -MMD -MP -MF "build/Debug/GNU-Linux-x86/main.o.d" -o build/Debug/GNU-Linux-x86/main.o main.c
mkdir -p dist/Debug/GNU-Linux-x86
gcc     -o dist/Debug/GNU-Linux-x86/capp build/Debug/GNU-Linux-x86/main.o ../StaticLibrary/dist/Debug/GNU-Linux-x86/libstaticlibrary.a
gmake[2]: Leaving directory `/home/wad/Code/NetBeansProjects/CApp'
gmake[1]: Leaving directory `/home/wad/Code/NetBeansProjects/CApp'

Open in new window



I am sure I am doing something silly, or have misunderstood something, but I cannot see it.  Can you?

TIA
0
Comment
Question by:mrwad99
9 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 83 total points
ID: 39992696
I am not surprised that the program itself builds without errors, since the presence of 'GetMagicNumber()' in it's source code eliminates the need to look for it in the static lib. The 'local' implementation will be chosen.

As for the lib, what symbols are listed when you do a 'nm libstaticlibrary.a'?
0
 
LVL 8

Expert Comment

by:Subrat (C++ windows/Linux)
ID: 39993282
Including JKR's comment...

If you will remove the implementation of int GetMagicNumber() from main.cpp, then you will see the actual magic:)
0
 
LVL 19

Author Comment

by:mrwad99
ID: 39994444
Right, OK.

nm gives me

Library.o:
0000000000000000 T GetMagicNumber

Library2.o:
0000000000000000 T GetMagicNumber

Open in new window


...which looks odd; how can we have two identical functions?

Secondly, are you saying there is logic that a linker will not look in the additional dependencies if it finds a definition locally?  I've never heard of that...where it is documented?

TIA
0
 
LVL 32

Assisted Solution

by:phoffric
phoffric earned 167 total points
ID: 39994485
0
Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

 
LVL 19

Author Comment

by:mrwad99
ID: 39994850
Thanks phoffric, that's helpful.  So how come I can still build the library with duplicate symbols though?
0
 
LVL 32

Expert Comment

by:phoffric
ID: 39994882
My post dealt with linking, not with libraries. You put into the library whatever modules you choose. As C libraries, it is not a good idea to have duplicate symbols. I am guessing that when you link with your library, that the first symbol it finds matching an undefined reference will be selected and the other one ignored.

This is a serious issue with C that has been improved upon greatly with C++. Once I had to go into one of two different 3rd party binary libraries and edit duplicate symbols to make them unique. They chose a function name that was so simplistic that it is hardly surprising that another 3rd party matched. Then, in the application, I had to change one of the names to the edited name to be able get correct functionality. For example, in my case, the program originally built fine, but when trying to access a graphics engine, it hit a database instead and, not surprisingly, crashed.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 39996481
OK, so fundamentally speaking, it is wrong for a static library to have duplicate symbols it, from the library's point of view?  I mean, what we are seeing here is obviously undesirable, but since a static library is just a collection of object files, thinking about it, I don't see any reason why we can't have identical symbols.  It seems to fit with what we are seeing here.

Thoughts?
0
 
LVL 32

Accepted Solution

by:
phoffric earned 167 total points
ID: 39997988
It is a bad idea for a static library to have .o files in it that result in duplicate symbols.

It is a bad idea for two different static libraries to have .o files in them that result in duplicate symbols in the different libraries; but because libraries are often 3rd party, you may have to deal with this unfortunate situation by using a binary editor to modify one of the symbols (at least that worked for me 20 years ago).

If you are creating a 3rd party library, then prefix every symbol with some unique symbol to lower the chances of name collisions.

When the linker encounters a static library, it searches it for undefined references. When it finds a .o file in the library that has the undefined reference, then it loads the entire .o file. If that newly loaded .o file has other symbols that collide with already existing defined symbols, then you will get a linker duplicate error message. Thus, the order in which you specify your .o files and library archive files may or may not result in duplicate symbol message. You are lucky if you get this duplicate symbol error message as it points out that you have duplicate symbols. If you do not get the error message, then the program that you built may be unwittingly containing the undesired symbol and the program may behave not in the desired manner.

Perhaps now, you can appreciate better the value of C++ namespaces that not only help organize your project, but also helps avoid name collisions. Using nested namespaces even further reduces the name collision chance against 3rd party C++ libraries.
0
 
LVL 19

Author Closing Comment

by:mrwad99
ID: 40008760
Thanks all :)
0

Featured Post

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now