Прежде чем я перейду к ответу на ваш вопрос, как он был описан, я отмечу, что не совсем ясно, чего вы пытаетесь достичь в конце, и, вероятно, есть лучшее решение вашей проблемы.
Тем не менее, есть две основные проблемы с попытками сделать то, что вы описали:
Во-первых, вам нужно будет разложить libpthread
и libstdc++
на объектные файлы, с которыми они сделаны. Это связано с тем, что бинарные файлы ELF (используемые в Linux) имеют два уровня загрузки библиотеки времени выполнения - даже когда исполняемый файл статически связан, загрузчик должен загружать статически связанные библиотеки в двоичном файле при выполнении, и сопоставьте правильные адреса памяти. Это делается до общего связывания библиотек, которые динамически загружаются (разделяемые объекты) и отображаются в разделяемую память. Таким образом, общий объект не может быть статически связан с такими библиотеками, поскольку на момент загрузки объекта все статические связанные библиотеки уже были загружены. Это одно из различий между связыванием со статической библиотекой и простым объектным файлом - статическая библиотека не просто вклеивается, как любой объектный файл, в исполняемый файл, но все же содержит отдельные таблицы, на которые ссылаются при загрузке. (Я полагаю, что это в отличие от гораздо более простых статических библиотек в MS-DOS и классических Windows, .LIB
файлов, но может быть и больше, чем я помню) .
Конечно, вам не нужно разлагать libpthread
и libstdc++
, вы можете просто использовать объектные файлы, сгенерированные при их создании. Однако собрать их может быть немного сложно (ищите объекты, на которые ссылается окончательное правило Makefile этих библиотек). И вам придется использовать ld
напрямую, а не gcc
/ g++
для связи, чтобы избежать связи с динамическими версиями.
Вторая проблема является косвенной. Если вы сделаете вышеописанное, у вас обязательно будет такой общий объект / динамическая библиотека, которую вы просили собрать. Однако это будет не очень полезно, так как после того, как вы попытаетесь связать обычный исполняемый файл, который использует эти libpthread
/ libstdc++
(последняя из которых является любой программой на C ++), с этим общим объектом, он потерпит неудачу с конфликтами символов - символами статические libpthread
/ libstdc++
объекты, с которыми вы связали свой общий объект, будут конфликтовать с символами из стандартного libpthread
/ libstdc++
, используемого этим исполняемым файлом, независимо от того, динамически или статически он связан со стандартными библиотеками .
Конечно, вы можете затем попытаться скрыть все символы в статических объектах из libstdc++
/ libpthread
, используемые вашей общей библиотекой, сделать их каким-то образом закрытыми или переименовать их автоматически при связывании, чтобы нет конфликта Однако, даже если вы заставите это работать, вы найдете некоторые нежелательные результаты во время выполнения, так как оба libstdc++
/ libpthread
сохраняют довольно много состояния в глобальных переменных и структурах, которые вы бы теперь дублировали и каждый не знал о другой. Это приведет к несоответствиям между этими глобальными данными и состоянием базовой операционной системы, таким как дескрипторы файлов и границы памяти (и, возможно, некоторые значения из стандартной библиотеки C, такие как errno
для libstdc++
, и обработчики сигналов и таймеры для libpthread
.
Чтобы избежать слишком широкой интерпретации, я добавлю замечание: время от времени могут иметь веские основания для желания статически связываться даже с такими базовыми библиотеками, как libstdc++
и даже libc
, и хотя с недавними системами и версиями этих библиотек это становится немного сложнее (из-за небольшой связи с используемым загрузчиком и специальными приемами компоновщика), определенно возможно - я сделал это несколько раз, и знать о других случаях, в которых это все еще делается. Однако , в этом случае вам нужно статически связать весь исполняемый файл . Статическая связь со стандартными библиотеками в сочетании с динамической связью с другими объектами обычно невозможна.
Редактировать : Одна проблема, о которой я забыл упомянуть, но которую важно учитывать, касается C ++. К сожалению, C ++ не был разработан, чтобы хорошо работать с классической моделью связывания и загрузки объектов (используется в Unix и других системах). Это делает разделяемые библиотеки в C ++ не очень переносимыми, как они должны быть, потому что многие вещи, такие как информация о типах и шаблоны, не разделены между объектами (часто принимаются вместе с большим количеством реального библиотечного кода во время компиляции из заголовков). ). libstdc++
по этой причине тесно связан с GCC, и код, скомпилированный с одной версией g++
, будет работать только с libstdc++
с этой (или очень похожей) версией g++
. Как вы наверняка заметите, если вы когда-нибудь попытаетесь собрать программу с GCC 4 с любой нетривиальной библиотекой в вашей системе, которая была скомпилирована с GCC 3, это не просто libstdc++
. Если ваша причина для этого заключается в том, чтобы убедиться, что ваш общий объект всегда связан с конкретными версиями libstdc++
и libpthread
, против которых он был создан, это не поможет, потому что программа, использующая другой / несовместимый libstdc++
также будет создан с несовместимым компилятором C ++ или версией g++
, и, таким образом, в любом случае не сможет связываться с вашим общим объектом, за исключением реальных libstdc++
конфликтов .
Если вы задаетесь вопросом «почему это не было сделано проще?», Стоит задуматься над общим рассуждением : чтобы C ++ прекрасно работал с динамическими / разделяемыми библиотеками (что означает совместимость между компиляторами и возможность замены динамическая библиотека с другой версией с совместимым интерфейсом без перестройки всего, что ее использует), требуется не только стандартизация компилятора, но и на уровне загрузчика операционной системы, структура и интерфейс файлов объектов и библиотек и работа компоновщика потребуется значительно расширить за пределы относительно простой классики Unix, используемой в распространенных операционных системах ( Microsoft Windows, системы на базе Mach и родственники NeXTStep, такие как Mac OS, родственники VMS и некоторые системы мэйнфреймов, также включены ) для встроенного кода сегодня. Компоновщик и динамический загрузчик должны знать о таких вещах, как шаблоны и типизацию, имея в некоторой степени функциональность небольшого компилятора , чтобы фактически адаптировать код библиотеки к заданному типу - и ( личное субъективное наблюдение здесь ) кажется, что промежуточный промежуточный код более высокого уровня (вместе с языками более высокого уровня и компиляцией точно в срок) завоевывает популярность быстрее и, вероятно, будет стандартизирован раньше, чем такие расширения нативного объекта форматы и компоновщики.