При создании общей библиотеки нужны только заголовочные файлы зависимых библиотек? - PullRequest
0 голосов
/ 20 февраля 2019

Скажем, общая библиотека A зависит от другой общей библиотеки B .

В этом случае, когда я собираю A , могу ли янужен только заголовочный файл B ?Потому что B нужен только тогда, когда я создаю какую-то программу, которая нуждается в A .Это правильно?Не могли бы вы объяснить детали?

1 Ответ

0 голосов
/ 20 февраля 2019

Вы правы.Вот конкретная иллюстрация.

ах

#ifndef A_H
#define A_H

extern void aa(void);

#endif

ac

#include "a.h"
#include "b.h"

void aa(void)
{
    bb();
}

чч

#ifndef B_H
#define B_H

extern void bb(void);

#endif

вс

#include "b.h"
#include <stdio.h>

void bb(void)
{
    puts(__func__);
}

main.c

#include "a.h"

int main(void)
{
    aa();
    return 0;
}

Мы создаем общую библиотеку liba.so.Сначала скомпилируйте объектный файл PIC (независимый от позиции) .

$ gcc -Wall -Wextra -o a.o -c -fPIC a.c

Теперь объектный файл a.o содержит неопределенную ссылку на bb:

$ readelf -s a.o

Symbol table '.symtab' contains 11 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
    10: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND bb

Ссылка на общую библиотеку:

$ gcc -shared -o liba.so a.o

Теперь общая библиотека также делает неопределенную ссылку на bb:

$ readelf --dyn-syms liba.so

Symbol table '.dynsym' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
     2: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND bb
   ...

Это нормально. Компоновщик создаст общую библиотеку, содержащую неопределенные ссылки .

Создайте еще одну общую библиотеку libb.so таким же образом:

$ gcc -Wall -Wextra -o b.o -c -fPIC b.c
$ gcc -shared -o libb.so b.o

Эта общая библиотека определяет bb:

$ readelf --dyn-syms libb.so

Symbol table '.dynsym' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   ...
    11: 000000000000060a    19 FUNC    GLOBAL DEFAULT   12 bb

Затем попробуйте создать программу:

$ gcc -Wall -Wextra -o main.o -c main.c
$ gcc -o prog main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `aa'
collect2: error: ld returned 1 exit status

Вот что происходит, когда мы связываемся ни с liba, ни с libb.Компоновщик не будет создавать программу , содержащую неопределенные ссылки.Итак:

$ gcc -o prog main.o liba.so
liba.so: undefined reference to `bb'
collect2: error: ld returned 1 exit status

вот что происходит, когда мы связываемся с liba, но не libb.Если мы свяжемся с обоими, как:

$ gcc -o prog main.o liba.so libb.so

Успех!Но будь осторожен.Если мы поменяем порядок библиотек:

$ gcc -o prog main.o libb.so liba.so
liba.so: undefined reference to `bb'
collect2: error: ld returned 1 exit status

, связь снова не будет выполнена.И так же:

$ gcc -o prog libb.so liba.so main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `aa'
collect2: error: ld returned 1 exit status

Компоновщик должен видеть библиотеку после других библиотек или объектных файлов, которые зависят от него.Таким образом, main.o должен быть связан до liba, а liba должен быть связан до libb.

И еще одна последняя ошибка .

$ gcc -o prog main.o liba.so libb.so

или эквивалентно:

$ gcc -o prog main.o -L. -la -lb

успешно связывает программу prog, но:

$ ./prog
./prog: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory

не запускает .Поскольку загрузчик времени выполнения все еще не знает, где искать liba или libb

Загрузчик знает, что prog нужны некоторые общие библиотеки с именами liba.so и libb.so, потому что компоновщик написалэта информация в prog:

$ readelf -d prog

Dynamic section at offset 0xda8 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [liba.so]
 0x0000000000000001 (NEEDED)             Shared library: [libb.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 ...

Как и в компоновщике, существуют каталоги , в которых загрузчик будет искать общие библиотеки по умолчанию .Он найдет libc.so.6 (библиотека GNU C) в одном из этих каталогов по умолчанию.Но он не найдет liba.so или libb.so, который я только что встроил в любой из них.

Но я могу сказать компоновщику предоставить недостающую информацию для загрузчика, связав программувместо этого вот так:

$ gcc -o prog main.o -L. -la -lb -Wl,-rpath=$PWD

С -Wl,-rpath=$PWD я говорю gcc передать (расширенный) параметр -rpath=$PWD компоновщику, и если мы это сделаем, мы увидим:

$ readelf -d prog

Dynamic section at offset 0xd98 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [liba.so]
 0x0000000000000001 (NEEDED)             Shared library: [libb.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [/home/imk/develop/so/scrap1]
 ...

Так что теперь, когда загрузчик загружает prog, он увидит, что RUNPATH=/home/imk/develop/so/scrap1 - это каталог не по умолчанию, где он также должен искать любые общие библиотеки NEEDED.prog и все его зависимости во время выполнения могут быть успешно загружены:

$ ./prog
bb
...