Подтвердить что ты не робот

G++: В каком порядке должны быть связаны статические и динамические библиотеки?

Скажем, у нас есть главный исполняемый файл под названием "my_app", и он использует несколько других библиотек: 3 библиотеки связаны статически, а другие 3 связаны динамически. В каком порядке они должны быть связаны с "my_app"?

Но в каком порядке они должны быть связаны?

Скажем, мы получили libSA (как в Static A), который зависит от libSB и libSC, который зависит от libSB:

libSA -> libSB -> libSC

и три динамические библиотеки: libDA -> libDB -> libDC (libDA является основным, libDC является самым высоким)

в каком порядке они должны быть связаны? первый или последний?

g++ ... -g libSA libSB libSC -lDA -lDB -lDC -o my_app

похоже на правильный порядок, но так ли? что, если есть зависимости между любой динамической библиотекой со статической или другой?

4b9b3361

Ответ 1

В статическом случае это не имеет особого значения, потому что вы фактически не связываете статические библиотеки - все, что вы делаете, - это пакетные файлы объектов в одном архиве. Все, что вам нужно, это компиляция ваших объектных файлов, и вы можете сразу создавать статические библиотеки.

Ситуация с динамическими библиотеками более сложна, есть два аспекта:

  • Общая библиотека работает точно так же, как статическая библиотека (за исключением разделяемых сегментов, если они присутствуют), что означает, что вы можете просто сделать то же самое - просто соедините свою общую библиотеку, как только у вас будет объектных файлов. Это означает, что символы из libDA будут отображаться как undefined в libDB

  • Вы можете указать библиотеки для связи в командной строке при связывании общих объектов. Это имеет тот же эффект, что и 1., но, отмечает libDB как нуждающийся в libDA.

Разница в том, что если вы используете прежний способ, вы должны указать все три библиотеки (-lDA, -lDB, -lDC) в командной строке при связывании исполняемого файла. Если вы используете последний, вы просто указываете -lDC, и он будет тянуть остальных автоматически во время соединения. Обратите внимание, что время соединения непосредственно перед вашей программой (что означает, что вы можете получать разные версии символов, даже из разных библиотек).

Все это относится к UNIX; Windows DLL работает совсем по-другому.

Изменить после выяснения вопроса:

Цитата из руководства по эксплуатации ld.

Линкеров будет искать только архив один раз, в том месте, где он находится указанных в командной строке. Если архив определяет символ, который был undefined в некотором объекте, который появился перед архивом на командной строки, компоновщик будет включать соответствующий файл из архив. Однако символ undefinedв объекте, появляющемся позже на командной строки не вызовет компоновщика для повторного поиска в архиве.

См. параметр `- ('для того, чтобы заставить компоновщик для поиска нескольких архивов раз.

Вы можете указать один и тот же архив раза в командной строке.

Этот тип поиска в архиве стандарт для Unix-линкеров. Однако, если вы используете `ld 'в AIX, обратите внимание, что он отличается от поведения линкером AIX.

Это означает:

Любая статическая библиотека или объект, которые зависят от другой библиотеки, должны быть размещены перед ней в командной строке. Если статические библиотеки зависят друг от друга циркулярно, вы можете, например. используйте параметр командной строки -( или дважды разместите библиотеки в командной строке (-lDA -lDB -lDA). Порядок динамических библиотек не имеет значения.

Ответ 2

Это вопрос, который лучше всего разрешает тривиальный пример. В самом деле! Возьмите 2 минуты, подпишите простой пример и попробуйте! Вы узнаете что-то, и это быстрее, чем просить.

Например, данные файлы:

a1.cc

#include <stdio.h>
void a1() { printf("a1\n"); }

a2.cc

#include <stdio.h>
extern void a1();
void a2() { printf("a2\n");  a1(); }

a3.cc

#include <stdio.h>
extern void a2();
void a3() { printf("a3\n"); a2(); }

aa.cc

extern void a3();
int main()
{
  a3();
}

Продолжительность:

g++ -Wall -g -c a1.cc
g++ -Wall -g -c a2.cc
g++ -Wall -g -c a3.cc
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.cc -o aa -la1 -la2 -la3 -L.

Показывает:

./liba3.a(a3.o)(.text+0x14): In function `a3()':
/tmp/z/a3.C:4: undefined reference to `a2()'

В то время как:

g++ -Wall -g -c a1.C
g++ -Wall -g -c a2.C
g++ -Wall -g -c a3.C
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.C -o aa -la3 -la2 -la1 -L.

преуспевает. (Только порядок параметров -la3 -la2 -la1 изменяется.)

PS:

nm --demangle liba*.a

liba1.a:
a1.o:
                 U __gxx_personality_v0
                 U printf
0000000000000000 T a1()

liba2.a:
a2.o:
                 U __gxx_personality_v0
                 U printf
                 U a1()
0000000000000000 T a2()

liba3.a:
a3.o:
                 U __gxx_personality_v0
                 U printf
                 U a2()
0000000000000000 T a3()

От man nm:

  • Если строчный, символ является локальным; если в верхнем регистре символ глобальный (внешний).

  • "T" Символ находится в разделе текста (кода).

  • "U" Символ undefined.

Ответ 3

Я работал в проекте с кучей внутренних библиотек, которые, к сожалению, зависели друг от друга (и со временем это ухудшилось). Мы решили "решить" это, установив SCons, чтобы указать все библиотеки дважды при связывании:

g++ ... -la1 -la2 -la3 -la1 -la2 -la3 ...

Ответ 4

Зависимости для связывания библиотеки или исполняемого файла должны присутствовать во время ссылки, поэтому вы не можете связать libXC до того, как будет представлен libXB. Не важно, статически или динамически.

Начните с самого базового, у которого нет зависимостей (или только от вашего проекта).

Ответ 5

Хорошей практикой является сохранение библиотек независимо друг от друга, чтобы избежать проблем с порядковым номером.