If we have a function foo() which has same prototype in two different libraries with different implementation and if we include only single header file (which has declaration of function), what happens if we try to compile or execute the program at compile or runtime ?
-
Did you try that? – Basile Starynkevitch Jan 05 '19 at 07:48
-
3The problem will appear at link time, linker will tell you that there is a conflict and you'll have to choose one of the two libraries... For dynamically loaded libraries, the problem could be very different. – Jean-Baptiste Yunès Jan 05 '19 at 07:50
-
@Jean-BaptisteYunès: Having the same symbol in two libraries generally does not produce an error. Object modules are linked from libraries on demand, not always. That is, a linker typically links in an object module from a library only if it provides a definition for a symbol referenced by a previous module and not yet defined. So a second definition of a symbol will not be linked in (and will not cause an error) unless it is in a module that also defines another symbol that is still needed. – Eric Postpischil Jan 05 '19 at 12:33
-
@EricPostpischil this highly depends on the linker... – Jean-Baptiste Yunès Jan 06 '19 at 13:19
-
@Jean-BaptisteYunès: Highly? It is very common linker behavior. One of the main features of linking with a library is that only needed modules are linked in, so the executable is not bloated with unnecessary modules. A natural consequence of that is that a module is linked in only if it provides a definition that is needed, so a later module that provides a definition of the same symbol is not linked in. – Eric Postpischil Jan 06 '19 at 14:25
2 Answers
Per your tags, you are asking about the linkage of static libraries. The linker doesn't know or care what source language(s) its input files were compiled from. The C language is immaterial to the question, but I'll use C for illustration.
Read the Stackoverflow tag Wiki about static libraries and it will explain that linking your program with a static library is exactly the same as linking your program with 0 or more of the object files that are archived in the static library - namely the 0 or more object files that the linker needs to provide definitions for otherwise unresolved symbol-references in the program.
Once the linker has found an object file p.o
file in a static library libx.a
that provides it
with a definition for some symbol foo
that the program refers to, it will link
the object file libx.a(p.o)
into the program to resolve foo
. It will not
try to find any other definition of foo
in any other object file q.o
file in any other
static library liby.a
that comes after libx.a
in the linkage.
So if there is any other object file q.o
in any other static library liby.a
that comes later in the linkage than libx.a
that also contains a definition of
foo
, that object file liby.a(q.o)
will not even be linked into the program
unless the linker needs it provide a definition of some other symbol bar
that the program refers to. Assuming that is not the case, liby.a(q.o)
might
as well not exist, for linkage purposes.
The linker will not link multiple definitions of the same symbol from libx.a(p.o)
and liby.a(q.o)
if it
does not need to. It will link the first object file, libx.a(p.o)
, that defines foo
into the program, and then it is done with defining foo
.
Here's an illustration of that:
main.c
extern void foo(void);
extern void bar(void);
int main(void)
{
foo();
bar();
return 0;
}
p.c
#include <stdio.h>
void foo(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
q.c
#include <stdio.h>
void foo(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
r.c
#include <stdio.h>
void bar(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
Function foo
is defined in p.c
and also in q.c
.
Compile all the .c
files to .o
files:
$ gcc -c main.c p.c q.c r.c
Create three static libraries, one from each of p.o
, q.o
, r.o
:
$ ar rcs libx.a p.o
$ ar rcs liby.a q.o
$ ar rcs libz.a r.o
Then link a program, inputting libx.a
before liby.a
:
$ gcc -o prog main.o libz.a libx.a liby.a -Wl,-trace-symbol=foo
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: libx.a(p.o): definition of foo
The diagnostic linkage option -Wl,-trace-symbol=foo
asks the linker to tell
us the names of the files that are linked into prog
where it finds unresolved references to foo
and
also the name of the file where foo
is defined. You see that foo
is referenced in main.o
and the definition provided by libx.a(p.o)
is linked. The other definition of foo
in
liby.a(q.o)
is not linked. This linkage is exactly the same as
gcc -o prog main.o r.o p.o
which contains only the definition of foo
from p.o
, as the program
shows:
$ ./prog
foo from p.c
bar from r.c
Now relink prog
, this time with liby.a
before libx.a
:
$ gcc -o prog main.o libz.a liby.a libx.a -Wl,-trace-symbol=foo
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: liby.a(q.o): definition of foo
This time, the definition of foo
was linked from liby.a(q.o)
. This linkage is exactly the same as:
gcc -o prog main.o r.o q.o
which contains only the definition of foo
from q.o
, as the program
shows:
$ ./prog
foo from q.c
bar from r.c
The linker does not care how many definitions of foo
you offer it in
different object files in different static libraries. It only cares that
if foo
is referenced in the program, then foo
is defined, exactly once,
by the files that it links into the program.
If you compel the linker to link files into the program that contain more
than one definition of foo
, then by default and normally the linker will
give you a multiple definition error and the linkage will fail, because
there cannot be more than one definition of foo
in a program. Here's an
illustration of that:
qr.c
#include <stdio.h>
void foo(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
void bar(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
Compile that file:
$ gcc -c qr.c
Archive qr.o
in a new static library:
$ ar rcs libyz.a qr.o
The object file libyz.a(qr.o)
defines both foo
and bar
. So we can link
our program like:
$ gcc -o prog main.o libyz.a -Wl,-trace-symbol=foo,-trace-symbol=bar
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: main.o: reference to bar
/usr/bin/ld: libyz.a(qr.o): definition of foo
/usr/bin/ld: libyz.a(qr.o): definition of bar
And it runs like:
$ ./prog
foo from qr.c
bar from qr.c
But if we attempt to link it like:
$ gcc -o prog main.o libx.a libyz.a -Wl,-trace-symbol=foo,-trace-symbol=bar
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: main.o: reference to bar
/usr/bin/ld: libx.a(p.o): definition of foo
/usr/bin/ld: libyz.a(qr.o): in function `foo':
qr.c:(.text+0x0): multiple definition of `foo'; libx.a(p.o):p.c:(.text+0x0): first defined here
/usr/bin/ld: libyz.a(qr.o): definition of bar
collect2: error: ld returned 1 exit status
there is a multiple definition of foo
. That is because:
- The linker needed a definition of
foo
and found the first one inlibx.a(p.o)
; so it linked that file into the program. It won't search for any other one. - The linker needed a definition of
bar
and found the first one inlibyz.a(qr.o)
; so it linked that file into the program. It won't search for any other one. - But
libyz.a(qr.o)
contains another definition offoo
as well as a definition ofbar
. So now two definitions offoo
have been linked, and that is an error.
I said that you'll get a multiple definition error by default if you make the linker attempt to link into the program more than one file that defines a symbol.
But you can avoid that by telling the linker than the symbol is weakly defined, provided that your linker understands this concept (as the GNU and Apple linkers do).
GCC compilers support a non-standard language extension, the __attribute__
syntax
that you can use to communicate to the linker that a symbol definition is weak.
Here's an illustration of that:
qr.c (2)
#include <stdio.h>
void __attribute__((weak)) foo(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
void bar(void)
{
printf("%s %s %s\n",__func__,"from",__FILE__);
}
Recompile:
$ gcc -c qr.c
Delete libyz.a
and recreate it:
$ rm libyz.a
$ ar rcs libyz.a qr.o
Retry the linkage that just failed:
$ gcc -o prog main.o libx.a libyz.a -Wl,-trace-symbol=foo,-trace-symbol=bar
/usr/bin/ld: main.o: reference to foo
/usr/bin/ld: main.o: reference to bar
/usr/bin/ld: libx.a(p.o): definition of foo
/usr/bin/ld: libyz.a(qr.o): definition of bar
This time, no error. The definition of foo
from libx.a(p.o)
is
linked. The weak definition from libyz.a(qr.o)
is ignored. The program
runs like:
$ ./prog
foo from p.c
bar from qr.c
If a symbol definition isn't weak, it is strong. The linker's rules are:
- At most one strong definition of a symbol can be linked.
- If one or more weak definitions, as well as a strong definition, are input, then the one strong definition is linked and the all the weak ones are ignored.
- If only weak definitions are input, then the linker can pick any one of them arbitrarily. (In practice, it picks whichever one if finds first).
Do not use weak symbol definitions simply to escape from multiple definition errors that take you by surprise. Such surprises mean that you don't understand your linkage. Analyse it and fix it so that you are no longer trying to make a program containing multiple definitions of the same thing.
Weak symbol definitions are usually generated by your compiler, behind the scenes, to implement features of the source language that require them ( e.g. global inline function definitions, or template instantiations in C++). Use them yourself only if you understand exactly why you want the linker to input multiple definitions of the same symbol.

- 55,740
- 12
- 153
- 182
-
Thanks for the reply. I really like the way you explained everything. It was just awesome. – user3747488 Jan 05 '19 at 13:01
What happens is implementation specific (and could be not even specified in C11 standard n1570, but I leave you to check that; AFAIK that standard don't speak of libraries - just of translation units). I believe the scenario you gives is some undefined behavior, so you could be scared (since anything is allowed to happen). And it probably is implementation defined.
In practice, on my Linux system, I'll get some error at link time (at least for static libraries). Read the Program Library HowTo and the documentation of the ld
linker. Be aware that the GCC compiler is (sometimes) running ld
(with many extra options, which are usually hidden to you). So invoke gcc
with the -v
flag (to understand how ld
is started by your gcc
command).
If you link two shared libraries on Linux, it becomes more interesting. But read Drepper's How to Write Shared Libraries. IIRC, the first symbol definition overrides the second. For example, you could use jemalloc and link the -ljemalloc
ahead of the implicit -lc
(with both libraries defining a malloc
symbol). Be also aware of plugins and of the dynamic linker (on Linux, see dlopen(3) & dlsym(3) & ld-linux.so(8)).
Linux also has weak symbols, see this, and its GCC has visibility attribute.
On Windows (which I don't know and never used) things could be different. However, you'll still be able some "multiply defined symbol" error at link time.
The linker works in an operating system specific way. So read Levine's Linkers and Loaders (which explains how both Windows and Unix linkers work, and the details are different). To learn more about OSes, read Operating Systems: Three Easy Pieces (freely downloadable).

- 223,805
- 18
- 296
- 547
-
In practice, on your Linux system, you do not get some error at link time just because two libraries (static or otherwise) contain the same symbol. And saying the first “overrides” the second is partly true in a sense but is not a good description of the linking process. Generally (subject to command-line options and so on), the linker selects modules to extract from libraries based on demand: Each module is linked in if it supplies a definition for a symbol that is referenced but not yet defined… – Eric Postpischil Jan 05 '19 at 13:45
-
… So, if two libraries merely define the same symbol, there is no error. (You can even have the same symbol defined multiple times in one library, in different modules.) An error arises only if multiple definitions are actually linked in, which may occur when a module is linked in because it defines a symbol that is needed and it also defines a symbol that was previously defined. – Eric Postpischil Jan 05 '19 at 13:47