1

I have come across a slightly unexpected behaviour of the linking process and I would like to ask for clarification.

It seems that linking against an object file and against a static library containing the same set of symbols is not equivalent. The former results in multiple definition error whereas the latter appears to link correctly.

Minimal example

File a.c and b.c are the same:

void myfunc() {
}

File c.c is the "main":

void myfunc();

int main()
{
    myfunc();
    return -1;
}

The compile-link workflow goes as follows:

$ gcc -c a.c b.c c.c
$ gcc c.o a.o b.o   # Breaks!
a.o: In function `myfunc':
a.c:(.text+0x0): multiple definition of `myfunc'
b.o:b.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
$ ar rvs libb.a b.o
$ gcc c.o a.o -L./ -lb  # Works fine?

My question here is: why is the second linking allowed and the first is not if the symbols contained in the object and the static library are the same?

Also, is this behaviour compiler or system specific?

Extension

This is potentially a separate question, but maybe useful to put it here. The problem of multiple references re-emerges with a static library if an additional function is defined in b.c file e.g. for b.c containing

void myfunc() {
}
void anotherfunc() {
}

And now the linking step breaks with the same error as before:

gcc b.c 
gcc -L./ c.o -lb  a.o 
a.o: In function `myfunc':
a.c:(.text+0x0): multiple definition of `myfunc'
.//libb.a(b.o):b.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit stat

2 Answers2

2

A library is just a collection of object files. There is no check on multiple definitions.

An executable can have only one definition of a function. In the linking process the linker fixes the calls (addresses) of the functions in the objects. If it encouters a second definition of the same function (name), it doesn't know which one to use.

Note that having multiple definitions in a static library will generally also result in the linker complaining about multiple definitions because it doesn't know which object of the library to use. Having multiple definitions in multiple libraries can be solved by giving the linker an order of the libraries: it will use the first symbol it encounters.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Sorry, I am not sure if I understand your response. Could you develop your first paragraph? My question is about linking against static library and against an object file. It appears to me that in the linking process the check on multiple definitions does not occur. – Robert Manson-Sawko May 11 '18 at 13:58
-1

The linker looks for the definition in the archive only if it has not found the definition already. In your case,
$ gcc c.o a.o -L./ -lb # Works fine?
works because the linker has already found the definition of myfunc() in a.c. A quick test of this is to include prints in a.c and b.c to check which myfunc() is used when you run your executable. More info here.