Связывание статических библиотек с другими статическими библиотеками - PullRequest
118 голосов
/ 28 января 2010

У меня есть небольшой фрагмент кода, который зависит от многих статических библиотек (a_1-a_n). Я хотел бы упаковать этот код в статическую библиотеку и сделать его доступным для других людей.

Моя статическая библиотека, давайте назовем ее X, прекрасно компилируется.

Я создал простой пример программы, которая использует функцию из X, но когда я пытаюсь связать ее с X, я получаю много ошибок о пропущенных символах из библиотек a_1 - a_n.

Есть ли способ, которым я могу создать новую статическую библиотеку, Y, которая содержит X и все функциональные возможности, необходимые для X (выбранные биты из a_1 - a_n), чтобы я мог распространять только Y, чтобы люди связывали свои программы с


UPDATE:

Я смотрел на простой дамп всего с помощью ar и создание одной мегабиблиотеки, однако в итоге получается много ненужных символов (все файлы .o занимают около 700 МБ однако статически связанный исполняемый файл равен 7 МБ). Есть ли хороший способ включить только то, что действительно нужно?


Это выглядит тесно связанным с Как объединить несколько библиотек C / C ++ в одну? .

Ответы [ 6 ]

63 голосов
/ 28 января 2010

Статические библиотеки не связаны с другими статическими библиотеками. Единственный способ сделать это - использовать инструмент библиотекаря / архиватора (например, ar в Linux) для создания одной новой статической библиотеки путем объединения нескольких библиотек.

Редактировать: В ответ на ваше обновление единственный известный мне способ выбрать только необходимые символы - вручную создать библиотеку из подмножества файлов .o, которые их содержат. Это сложно, отнимает много времени и подвержено ошибкам. Мне неизвестны какие-либо инструменты, которые бы помогли сделать это (не говоря уже о том, что они не существуют), но это сделало бы довольно интересный проект по его созданию.

41 голосов
/ 28 января 2010

Если вы используете Visual Studio, тогда да, вы можете сделать это.

Средство построения библиотек, поставляемое с Visual Studio, позволяет объединять библиотеки в командной строке. Я не знаю, как это сделать в визуальном редакторе.

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib
19 голосов
/ 28 декабря 2014

В 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
8 голосов
/ 28 января 2010

Статическая библиотека - это просто архив .o объектных файлов. Извлеките их с помощью ar (при условии Unix) и упакуйте их обратно в одну большую библиотеку.

5 голосов
/ 13 августа 2013

В качестве альтернативы Link Library Dependencies в свойствах проекта есть другой способ связать библиотеки в Visual Studio.

  1. Откройте проект библиотеки (X), которую вы хотите объединить с другими библиотеками.
  2. Добавьте другие нужные вам библиотеки в сочетании с X (щелчок правой кнопкой мыши, Add Existing Item...).
  3. Перейдите к их свойствам и убедитесь, что Item Type это Library

Это будет включать другие библиотеки в X, как если бы вы запустили

lib /out:X.lib X.lib other1.lib other2.lib
3 голосов
/ 16 января 2015

Примечание перед прочтением: Показанный здесь сценарий оболочки, безусловно, небезопасен для использования и хорошо протестирован. Используйте на свой страх и риск!

Я написал скрипт 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).

...