В сущности, вы заметили, что компоновщик не может разрешить символ динамически, если он может разрешить его статически.См .:
main.c
extern void foo(void);
extern void need_dynamic_foo(void);
extern void need_static_foo(void);
int main(void){
foo();
need_dynamic_foo();
need_static_foo();
return 0;
}
dynamic_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (dynamic)");
}
void need_dynamic_foo(void)
{
puts(__func__);
}
static_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static)");
}
void need_static_foo(void)
{
puts(__func__);
}
Скомпилируйте исходники так:
$ gcc -Wall -c main.c static_foo.c
$ gcc -Wall -fPIC -c dynamic_foo.c
Создайте общую библиотеку:
$ gcc -shared -o libfoo.so dynamic_foo.o
И свяжите программу:
$ gcc -o prog main.o static_foo.o libfoo.so -Wl,-rpath=$PWD
Он работает так:
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
Так что foo
и need_static_foo
были статически разрешены к определениям из static_foo.o
, а определение foo
из libfoo.so
было проигнорировано, несмотря натот факт, что libfoo.so
был , необходим и дал определение need_dynamic_foo
.Не имеет значения, если мы изменим порядок связи на:
$ gcc -o prog main.o libfoo.so static_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static)
need_dynamic_foo
need_static_foo
Также не имеет значения, если мы заменим static_foo.c
на:
static_weak_foo.c
#include <stdio.h>
void __attribute__((weak)) foo(void)
{
puts("foo (static weak)");
}
void need_static_foo(void)
{
puts(__func__);
}
Скомпилируйте это и выполните повторную ссылку:
$ gcc -Wall -c static_weak_foo.c
$ gcc -o prog main.o libfoo.so static_weak_foo.o -Wl,-rpath=$PWD
$ ./prog
foo (static weak)
need_dynamic_foo
need_static_foo
Хотя определение foo
в static_weak_foo.c
теперь объявлено слабым, тот факт, что foo
может быть статически разрешенным к этому определению по-прежнему исключает необходимость его динамического разрешения.
Теперь, если мы напишем другой исходный файл, содержащий другое строгое определение foo
:
static_strong_foo.c
#include <stdio.h>
void foo(void)
{
puts("foo (static strong)");
}
и скомпилируйте его и сделайте ссылку следующим образом:
$ gcc -Wall -c static_strong_foo.c
$ gcc -o prog main.o static_weak_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
мы видим:
$ ./prog
foo (static strong)
need_dynamic_foo
need_static_foo
Теперь libfoo.so
все еще дает определениеneed_dynamic_foo
, потому что другого нет;static_weak_foo.o
по-прежнему предоставляет единственное определение need_static_foo
, а определение foo
в libfoo.so
по-прежнему игнорируется, поскольку символ может быть разрешен статически.
Но в этом случае есть два определенияfoo
в разных файлах, которые доступны для статического разрешения: слабое определение в static_weak_foo.o
и строгое определение в static_strong_foo.o
.По правилам связывания, с которыми вы знакомы, побеждает сильное определение.
Если бы оба эти статически связанных определения foo
были сильными, то, конечно, была бы ошибка множественного определения, например:
$ gcc -o prog main.o static_foo.o libfoo.so static_strong_foo.o -Wl,-rpath=$PWD
static_strong_foo.o: In function `foo':
static_strong_foo.c:(.text+0x0): multiple definition of `foo'
static_foo.o:static_foo.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
, в котором динамическое определение в libfoo.so
не играет роли .Таким образом, вы можете руководствоваться этим практическим принципом: правила, с которыми вы знакомы для арбитража между слабыми и сильными определениями одного и того же символа в связи, применяются только к конкурирующим определениям , которые могут вызвать ошибку множественного определения в отсутствие weak
атрибут .