Связывание статических библиотек с другими статическими библиотеками
Вопрос
У меня есть небольшой фрагмент кода, который зависит от многих статических библиотек (a_1-a_n).Я бы хотел упаковать этот код в статическую библиотеку и сделать его доступным для других людей.
Моя статическая библиотека, назовем ее X, отлично компилируется.
Я создал простой пример программы, которая использует функцию из X, но когда я пытаюсь связать ее с X, я получаю много ошибок об отсутствующих символах из библиотек a_1 - a_n.
Есть ли способ, которым я могу создать новую статическую библиотеку, Y, которая содержит X и всю функциональность, необходимую для X (выбранные биты из a_1 - a_n), чтобы я мог распространять только Y для людей, с которыми они могут связывать свои программы?
Обновить:
Я рассматривал возможность просто сбросить все с ar однако создание одной мега-библиотеки в конечном итоге приводит к включению множества ненужных символов (все файлы .o имеют размер около 700 МБ, однако статически связанный исполняемый файл составляет 7 МБ).Есть ли хороший способ включить только то, что действительно необходимо?
Это выглядит тесно связанным с Как объединить несколько библиотек C / C ++ в одну?.
Решение
Статические библиотеки не связаны с другими статическими библиотеками.Единственный способ сделать это - использовать ваш инструмент библиотекаря / архиватора (например 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:
lib.exe /OUT:libab.lib liba.lib libb.lib
Статическая библиотека - это просто архив .o
объектные файлы.Извлеките их с помощью ar
(предполагая Unix) и упакуйте их обратно в одну большую библиотеку.
В качестве альтернативы Link Library Dependencies
в свойствах проекта есть другой способ связать библиотеки в Visual Studio.
- Откройте проект библиотеки (X), которую вы хотите объединить с другими библиотеками.
- Добавьте другие библиотеки, которые вы хотите объединить с X (щелкните правой кнопкой мыши,
Add Existing Item...
). - Зайдите в их свойства и убедитесь
Item Type
являетсяLibrary
Это будет включать другие библиотеки в 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="$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
где libwhatever - это то место, откуда вы хотите включить символы.Однако я думаю, что безопаснее всего сначала скопировать все в отдельный каталог.Я бы не стал так сильно доверять своему сценарию (однако у меня он сработал;Я мог бы включить libgsl.a в свою библиотеку numerics с этим и исключить этот переключатель компилятора -lgsl).