Связывание статических библиотек с другими статическими библиотеками
У меня есть небольшой кусок кода, который зависит от многих статических библиотек (a_1-a_n). Я хотел бы упаковать этот код в статическую библиотеку и сделать его доступным для других людей.
Моя статическая библиотека, давайте назовем это X, прекрасно компилируется.
Я создал простой пример программы, которая использует функцию из X, но когда я пытаюсь связать ее с X, я получаю много ошибок о пропущенных символах из библиотек a_1 - a_n.
Есть ли способ, которым я могу создать новую статическую библиотеку, Y, которая содержит X и все функциональные возможности, необходимые для X (выбранные биты из a_1 - a_n), чтобы я мог распространять только Y, чтобы люди могли связать свои программы?
ОБНОВИТЬ:
Я посмотрел на простой дамп всего с помощью ar и создание одной мегабиблиотеки, однако, в результате получается множество ненужных символов (все файлы.o имеют размер около 700 МБ, однако статически связанный исполняемый файл равен 7). MB). Есть ли хороший способ включить только то, что действительно нужно?
Это тесно связано с тем, как объединить несколько библиотек C/C++ в одну?,
6 ответов
Статические библиотеки не связаны с другими статическими библиотеками. Единственный способ сделать это - использовать инструмент библиотекаря / архиватора (например, ar в Linux) для создания единой новой статической библиотеки путем объединения нескольких библиотек.
Редактировать: в ответ на ваше обновление единственный известный мне способ выбрать только необходимые символы - это вручную создать библиотеку из подмножества файлов.o, которые их содержат. Это сложно, отнимает много времени и подвержено ошибкам. Я не знаю каких-либо инструментов, которые могли бы помочь сделать это (не говоря уже о том, что они не существуют), но это сделало бы довольно интересный проект по его созданию.
Если вы используете Visual Studio, то да, вы можете сделать это.
Инструмент для создания библиотек, поставляемый с Visual Studio, позволяет объединять библиотеки в командной строке. Я не знаю, как сделать это в визуальном редакторе.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
В Linux или MingW, с набором инструментов GNU:
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:
lib.exe /OUT:libab.lib liba.lib libb.lib
Статическая библиотека - это просто архив .o
объектные файлы. Извлечь их с ar
(при условии Unix) и упакуйте их обратно в одну большую библиотеку.
Обратите внимание, прежде чем читать остальное: сценарий оболочки, показанный здесь, безусловно, небезопасен для использования и хорошо протестирован. Используйте на свой риск!
Я написал скрипт bash для выполнения этой задачи. Предположим, ваша библиотека -lib1, а из которой вам нужно включить некоторые символы -lib2. Теперь скрипт выполняется в цикле, где сначала проверяется, какие неопределенные символы из lib1 можно найти в lib2. Затем он извлекает соответствующие объектные файлы из lib2 с ar
, переименовывает их немного и помещает в lib1. Теперь может быть больше пропущенных символов, потому что материал, который вы включили из lib2, нуждается в другом материале из lib2, который мы еще не включили, поэтому цикл необходимо запустить снова. Если после нескольких проходов цикла больше нет изменений, то есть нет добавленных объектных файлов из lib2 в lib1, цикл может остановиться.
Обратите внимание, что включенные символы по-прежнему отображаются как неопределенные nm
, поэтому я отслеживаю объектные файлы, которые были добавлены в lib1, сами, чтобы определить, можно ли остановить цикл.
#! /bin/bash
lib1="$1"
lib2="$2"
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 $1=$file
}
remove_tmp_files() {
rm $remove_later
}
trap remove_tmp_files EXIT
find_symbols() {
nm $1 $2 | 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
где libwh независимо от того, где вы хотите включить символы. Тем не менее, я думаю, что безопаснее всего сначала скопировать все в отдельный каталог. Я бы не стал доверять своему сценарию (однако, он сработал для меня; я мог бы включить libgsl.a в мою библиотеку числовых данных и пропустить этот переключатель компилятора -lgsl).
В качестве альтернативы Link Library Dependencies
в свойствах проекта есть другой способ связать библиотеки в Visual Studio.
- Откройте проект библиотеки (X), которую вы хотите объединить с другими библиотеками.
- Добавьте другие библиотеки, которые вы хотите в сочетании с X
Add Existing Item...
). - Перейдите к их свойствам и убедитесь,
Item Type
являетсяLibrary
Это будет включать в себя другие библиотеки в X, как будто вы запустили
lib /out:X.lib X.lib other1.lib other2.lib