Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 878
  • Last Modified:

Expecting linker duplicate symbol error, but not getting it!

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
mrwad99
Asked:
mrwad99
3 Solutions
 
jkrCommented:
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
 
Subrat (C++ windows/Linux)Software EngineerCommented:
Including JKR's comment...

If you will remove the implementation of int GetMagicNumber() from main.cpp, then you will see the actual magic:)
0
 
mrwad99Author Commented:
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
mrwad99Author Commented:
Thanks phoffric, that's helpful.  So how come I can still build the library with duplicate symbols though?
0
 
phoffricCommented:
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
 
mrwad99Author Commented:
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
 
phoffricCommented:
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
 
mrwad99Author Commented:
Thanks all :)
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Tackle projects and never again get stuck behind a technical roadblock.
Join Now