Each library will ship include a copy of A. However, at runtime only one will be used by all the components of the process.
// h.h
extern int a;
void b(void);
void c(void);
// a.c
#include "h.h"
int a = 0;
// b.c
#include <stdio.h>
#include "h.h"
void b(void)
{
printf("%i\n", a++);
}
// c.c
#include <stdio.h>
#include "h.h"
void c(void)
{
printf("%i\n", a++);
}
//main.c
#include <stdio.h>
#include "h.h"
int main()
{
b();
c();
}
#Makefile
main: libxc.so libxb.so
cc -o main main.c -L. -lxc -lxb
libxb.so:
cc -fPIC -shared a.c b.c -o libxb.so
libxc.so:
cc -fPIC -shared a.c c.c -o libxc.so
$make
$ LD_LIBRARY_PATH=. ./main
0
1
Symbol table from libxa.so:
53: 000000000020098c 4 OBJECT GLOBAL DEFAULT 24 a
From libxc.so:
53: 000000000020098c 4 OBJECT GLOBAL DEFAULT 24 a
The default visibility is STV_DEFAULT which according to LSB:
STV_DEFAULT: The visibility of symbols with the STV_DEFAULT
attribute is as specified by the symbol's binding type. That is,
global and weak symbols are visible outside of their
defining
component (executable file or shared object). Local symbols are
hidden, as described below. Global and weak symbols are also
preemptable, that is, they may by preempted by definitions of the same
name in another component.
man 5 elf:
STV_DEFAULT: Default symbol visibility rules.
Globa and weak symbols are available to other
modules; references in the local module can
be interposed by definitions in other
modules.
About the SysV ABI:
When resolving symbolic references, the
dynamic linker examines the symbol tables with a breadth-first search.
That is, it first looks at the symbol table of the executable
program itself, then at the symbol tables of the
DT_NEEDED entries (in order), then at the second level DT_NEEDED
entries, and so on.
If that's not what's expected, using STV_HIDDEN on the symbol prevents it from behind visible outside of the shared object.
In contrast, on Windows a symbol is always imported from a given DLL and the symbols are not exported to other DLLs by default anyway.