Связывание статических библиотек с другими статическими библиотеками
У меня есть небольшой фрагмент кода, который зависит от многих статических библиотек (a_1-a_n). Я хотел бы упаковать этот код в статической библиотеке и сделать его доступным для других людей.
Моя статическая библиотека, позволяет называть ее X, компилируется отлично.
Я создал простую примерную программу, которая использует функцию из X, но когда я пытаюсь связать ее с X, я получаю много ошибок о недостающих символах из библиотек a_1 - a_n.
Есть ли способ создать новую статическую библиотеку Y, содержащую X и всю функциональность, необходимую X (выбранные биты из a_1 - a_n), чтобы я мог распространять только Y, чтобы люди могли связать свои программы с
UPDATE:
Я посмотрел только на сброс всего с ar и создание одной мега-библиотеки, однако, которая заканчивается, включая множество символов, которые не нужны (все файлы .o около 700 MB, однако, статически связанный исполняемый файл - 7 МБ). Есть ли хороший способ включить только то, что на самом деле необходимо?
Это тесно связано с Как объединить несколько библиотек C/С++ в один?.
Ответы
Ответ 1
Статические библиотеки не связаны с другими статическими библиотеками. Единственный способ сделать это - использовать ваш инструмент библиотекаря/архиватора (например, ar в Linux), чтобы создать одну новую статическую библиотеку, объединив несколько библиотек.
Изменить: В ответ на ваше обновление, единственный способ, которым я знаю, выбирать только требуемые символы - это вручную создать библиотеку из подмножества файлов .o, которые их содержат. Это сложно, требует много времени и ошибок. Я не знаю никаких инструментов, которые помогут сделать это (не сказать, что их не существует), но это создаст интересный проект для его создания.
Ответ 2
Если вы используете Visual Studio, тогда да, вы можете это сделать.
Инструмент построения библиотеки, поставляемый с Visual Studio, позволяет вам объединять библиотеки в командной строке. Однако я не знаю, как это сделать в визуальном редакторе.
lib.exe /OUT:compositelib.lib lib1.lib lib2.lib
Ответ 3
В 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:
lib.exe /OUT:libab.lib liba.lib libb.lib
Ответ 4
Статическая библиотека - это просто архив объектных файлов .o
. Извлеките их с помощью ar
(предположим Unix) и упакуйте их обратно в одну большую библиотеку.
Ответ 5
В качестве альтернативы Link Library Dependencies
в свойствах проекта существует еще один способ связать библиотеки в Visual Studio.
- Откройте проект библиотеки (X), который вы хотите объединить с другими библиотеками.
- Добавьте другие библиотеки, которые вы хотите объединить с X (правый клик,
Add Existing Item...
).
- Перейдите к их свойствам и убедитесь, что
Item Type
есть Library
Это будет включать другие библиотеки в X, как если бы вы запускали
lib /out:X.lib X.lib other1.lib other2.lib
Ответ 6
Обратите внимание, прежде чем вы прочтете остальное: Оболочка script, показанная здесь, безусловно, небезопасна для использования и хорошо протестирована. Используйте на свой страх и риск!
Я написал bash script для выполнения этой задачи. Предположим, что ваша библиотека - lib1, и вам нужно добавить некоторые символы из lib2. script теперь выполняется в цикле, где он сначала проверяет, какие символы undefined из lib1 могут быть найдены в lib2. Затем он извлекает соответствующие объектные файлы из lib2 с помощью ar
, немного переименовывает их и помещает в lib1. Теперь может быть больше недостающих символов, потому что материал, который вы включили из lib2, нуждается в другом материале из lib2, который мы еще не включили, поэтому цикл должен запускаться снова. Если после некоторых проходов цикла больше никаких изменений, т.е. Никаких объектных файлов из lib2, добавленных в lib1, цикл может остановиться.
Обратите внимание, что включенные символы по-прежнему отображаются как undefined на 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
Я назвал это script libcomp
, поэтому вы можете вызвать его, например, с
./libcomp libmylib.a libwhatever.a
где lib, независимо от того, где вы хотите включить символы. Тем не менее, я считаю, что лучше всего скопировать все в отдельный каталог. Я бы не стал доверять моему script так много (однако, это сработало для меня, я мог бы включить libgsl.a в мою библиотеку с этим и оставить этот -lgsl-компилятор).