Как встраивать копии библиотеки stati c? - PullRequest
6 голосов
/ 17 января 2020

Вот структура моего решения:

enter image description here

A.lib определяет:

int a(void) { return 1; }

B.lib определяет:

int b(void) { return a(); }

C.lib определяет:

int c(void) { return a() * 2; }

SharedStaticLibsTest.exe определяет:

int main(void) { std::cout << b() + c() << std::endl; return 0;}

Я решил проверить (через DumpBin) код, добавленный в результат применения. Оказывается, библиотеки B и C используют единственный экземпляр библиотеки A. Есть ли способ (в образовательных целях) использовать два разных экземпляра A внутри B и C? Может быть, есть указатель c для компоновщика? Я понимаю, что такое поведение может иметь неожиданные побочные эффекты, которые зависят от logi c библиотеки A.

PS Я заменил ссылки на проект прямым включением файла .lib в свойствах проекта. Теперь проекты B, C имеют копию проекта A. Но в конечном проекте все еще есть единственная копия библиотеки A. Я понятия не имею, как линкер решает эту проблему.

1 Ответ

4 голосов
/ 20 января 2020

Прежде всего, если в построении вы когда-нибудь получите два экземпляра A, все экспортируемые идентификаторы из A должны следовать правилу One-Definition-Rule .

То есть, даже если технически у вас могут быть две разные версии A, если они не являются одинаковыми для всех намерений и целей, ваша программа недействительна и ни компилятор, ни компоновщик не обязаны вам сообщать (стандартные вызовы C ++ это плохо сформировано, никакой диагностики c требуется ). На практике это означает, что вы будете иметь очень странных ошибок в вашей программе и не будете знать, откуда они берутся.

При этом технически ничто не мешает вам создавать ситуации, подобные той, которую вы спросить. Обычно stati c зависимости обрабатываются только на этапе компоновки. Таким образом, stati c library B в зависимости от другого stati c library A не заставит одного экспортировать символы из другого - B не будет содержать символов из A.

Вместо этого ваша система сборки будет отслеживать эту зависимость, и как только вы достигнете стадии компоновщика (например, создавая исполняемый файл, зависящий от B), система сборки позаботится о том, чтобы обе библиотеки получить связь. Это также означает, что если у вас нет системы сборки или вы неправильно сконфигурировали свою сборку, вы получите ошибки компоновщика за пропуск символов из библиотеки A, даже если вы явно ссылаетесь на B и C .

Таким образом, канонический, переносимый способ дублирования символов требует протягивания их через динамические c библиотеки , потому что они проходят через компоновщик. Если вы измените B и C на динамические c библиотеки, они оба будут ссылаться на A и содержать свои собственные отдельные версии используемых функций из A. Если вы изменили A между зданиями B и C, они будут содержать разные определения. Надеюсь, ваша система сборки постарается предотвратить это. Обратите внимание, что в стандарте C ++ не так много сказано о динамических библиотеках c, поэтому о технических особенностях того, как здесь разрешаются символы, и каков будет эффект дублированных символов, см. В руководстве по вашей операционной системе.

В MSV C есть дополнительная возможность сделать это и для stati c библиотек. В свойствах проекта для B или C перейдите к Библиотекарь -> Общие и установите для Зависимости библиотеки ссылок значение Yes. Теперь, если вы перестроите и снова посмотрите на дампы для B.lib и C.lib, они также должны содержать символы из A. Конечно, при построении результирующего исполняемого файла компоновщик выбирает либо версию из B, либо из C (или также из A напрямую, в зависимости от того, как вы связываете) для каждого из символов A. это используется. Пожалуйста, не делайте этого в производстве.

...