Связывание статических библиотек с другими статическими библиотеками
У меня есть небольшой кусок кода, который зависит от многих статических библиотек (a_1-a_n). Я хочу упаковать этот код в статическую библиотеку и сделать его доступным для других людей.
моя статическая библиотека, назовем ее X, отлично компилируется.
Я создал простой пример программы, которая использует функцию из X, но когда я пытаюсь связать ее с X, я получаю много ошибок о недостающих символах из библиотек a_1-a_n.
есть ли способ, что я могу создать новый статический библиотека, Y, которая содержит X и всю функциональность, необходимую X (выбранные биты из a_1 - a_n), чтобы я мог распространять только Y для людей, чтобы связать свои программы?
обновление:
Я посмотрел, как просто сбрасывать все с ar и создание одного мега-lib, однако, в конечном итоге включает в себя много символов, которые не нужны (все .o файлы около 700 МБ, однако, статически слинкованный исполняемый файл 7 МБ). Есть ли хороший способ включить только что на самом деле нужно?
Это выглядит тесно связанным с как объединить несколько библиотек C/C++ в одну?.
6 ответов
статические библиотеки не связаны с другими статическими библиотеками. Единственный способ сделать это-использовать инструмент библиотекарь / архиватор (например,ar на Linux) для создания статической библиотеки путем объединения нескольких библиотек.
изменить: в ответ на ваше обновление, единственный способ, который я знаю, чтобы выбрать только символы, которые необходимы, чтобы вручную создать библиотеку из подмножества.o файлы, которые содержат их. Это трудно, время потребление и склонность к ошибкам. Я не знаю никаких инструментов, чтобы помочь сделать это (не сказать, что они не существуют), но было бы довольно интересным проектом для его создания.
Если вы используете Visual Studio, то да, вы можете это сделать.
средство построения библиотек, поставляемое с Visual Studio, позволяет объединять библиотеки в командной строке. Я не знаю, как это сделать в визуальном редакторе.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
на Linux или MingW, с GNU toolchain:
ar -M <<EOM
CREATE libab.a
ADDLIB liba.a
ADDLIB libb.a
SAVE
END
EOM
ranlib libab.a
если вы не удалить liba.a
и libb.a
, вы можете сделать "тонкий архиве":
ar crsT libab.a liba.a libb.a
в Windows, с MSVC toolchain:
lib.exe /OUT:libab.lib liba.lib libb.lib
статическая библиотека-это просто архив .o
объектные файлы. Извлеките их с помощью ar
(предполагая, Unix) и упаковать их в одну большую библиотеку.
вместо Link Library Dependencies
в свойствах проекта есть другой способ связать библиотеки в Visual Studio.
- откройте проект библиотеки (X), которую вы хотите объединить с другими библиотеками.
- добавьте другие библиотеки, которые вы хотите объединить с X (щелкните правой кнопкой мыши,
Add Existing Item...
). - перейдите к их свойствам и убедитесь, что
Item Type
isLibrary
это будет включать другие библиотеки в X, как если бы вы запускали
lib /out:X.lib X.lib other1.lib other2.lib
Примечание, прежде чем читать остальное: сценарий оболочки, показанный здесь, конечно, не безопасен в использовании и хорошо протестирован. Используйте на свой страх и риск!
я написал сценарий bash для выполнения этой задачи. Предположим, что ваша библиотека lib1, и вам нужно включить некоторые символы из lib2. Теперь скрипт работает в цикле, где он сначала проверяет, какие неопределенные символы из lib1 можно найти в lib2. Затем он извлекает соответствующие объектные файлы из lib2 с ar
, переименовывает их немного, и помещает их в lib1. Теперь может быть больше недостающих символов, потому что материал, который вы включили из lib2, нуждается в другом материале из lib2, который мы еще не включили, поэтому цикл должен запускаться снова. Если после некоторых проходов цикла больше нет изменений, т. е. нет объектных файлов из lib2, добавленных в lib1, цикл может остановиться.
обратите внимание, что эти символы по-прежнему числятся как определен nm
, поэтому я отслеживаю объектные файлы, которые были добавлены в lib1, сами по себе, в чтобы определить, можно ли остановить цикл.
#! /bin/bash
lib1=""
lib2=""
if [ ! -e $lib1.backup ]; then
echo backing up
cp $lib1 $lib1.backup
fi
remove_later=""
new_tmp_file() {
file=$(mktemp)
remove_later="$remove_later $file"
eval =$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
find_symbols() {
nm | cut -c20- | sort | uniq
}
new_tmp_file lib2symbols
new_tmp_file currsymbols
nm $lib2 -s --defined-only > $lib2symbols
prefix="xyz_import_"
pass=0
while true; do
((pass++))
echo "Starting pass #$pass"
curr=$lib1
find_symbols $curr "--undefined-only" > $currsymbols
changed=0
for sym in $(cat $currsymbols); do
for obj in $(egrep "^$sym in .*\.o" $lib2symbols | cut -d" " -f3); do
echo " Found $sym in $obj."
if [ -e "$prefix$obj" ]; then continue; fi
echo " -> Adding $obj to $lib1"
ar x $lib2 $obj
mv $obj "$prefix$obj"
ar -r -s $lib1 "$prefix$obj"
remove_later="$remove_later $prefix$obj"
((changed=changed+1))
done
done
echo "Found $changed changes in pass #$pass"
if [[ $changed == 0 ]]; then break; fi
done
я назвал этот скрипт libcomp
, так что вы можете назвать его, например, с
./libcomp libmylib.a libwhatever.a
где libwhatever, где вы хотите включить символы из. Однако я думаю, что безопаснее всего сначала скопировать все в отдельный каталог. Я бы не доверял своему сценарию так сильно (однако он работал для меня; я мог бы включить libgsl.a в мою библиотеку чисел с этим и опустить, что-lgsl переключатель компилятора).