Связывание статических библиотек с другими статическими библиотеками

У меня есть небольшой фрагмент кода, который зависит от многих статических библиотек (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 ++ в одну?.


person Jason Sundram    schedule 28.01.2010    source источник


Ответы (6)


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

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

person Community    schedule 28.01.2010
comment
Привет, Нил, я обновил вопрос - знаете ли вы, как включить только необходимые файлы .o? - person Jason Sundram; 29.01.2010
comment
Обновление - если вы обнаружите, что хотите сделать это, сделайте шаг назад и займитесь чем-нибудь другим (если, как указывает Джон Кнеллер, вы не используете Visual Studio). Я потратил много времени на этот подход и не получил ничего полезного. - person Jason Sundram; 12.04.2011
comment
Инструмент GNU ld предоставляет параметр -r, позволяющий использовать выходные данные как входные для ld. Если вы сделаете ссылку один раз, вы должны получить перемещаемый объект, который может заменить ваши библиотеки. (пробовал хотя). - person harper; 28.12.2014

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

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

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib
person John Knoeller    schedule 28.01.2010
comment
В VS2008 в свойствах проекта compositelib в разделе Librarian / General, если вы отметите [x] Link Library Dependencies, он сделает это за вас, если lib1 и lib2 являются зависимостями compositelib. Это кажется немного глючным, я бы установил флажок отдельно в каждой конфигурации сборки, а не один раз в «Все конфигурации». - person Spike0xff; 13.02.2013
comment
VS2015 IDE - разве вы не используете дополнительные зависимости в разделе Librarian / General, чтобы получить дополнительные библиотеки, связанные непосредственно с библиотекой, которую создает ваш проект? - person davidbak; 06.05.2016
comment
@davidbak Я пытаюсь понять это в последние пару дней, и, по-видимому, эта опция устарела и ничего не делает? - person Montaldo; 09.05.2016

В 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
person Star Brilliant    schedule 28.12.2014
comment
Приятно знать, но на самом деле это не решает проблему OP, поскольку вы включаете все из libb.a в совместную библиотеку, которая может стать очень большой, если вам нужно всего несколько модулей из libb. - person Elmar Zander; 16.01.2015
comment
@ElmarZander Но вы можете использовать ar crsT, который делает что-то вроде символической ссылки вместо копирования, тогда вам нужно отправить только одну копию данных. - person Star Brilliant; 16.01.2015
comment
Тонкие архивы особенно используются в ядре Linux v4.19: unix.stackexchange.com/questions/5518/ - person Ciro Santilli 新疆再教育营六四事件ۍ 21.11.2018

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

person Nikolai Fetissov    schedule 28.01.2010

В качестве альтернативы 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
person evpo    schedule 13.08.2013
comment
Привет, я использую Intel IPP, и я создал свои собственные функции, которые я хочу, чтобы все они были упакованы в одну (статическую) библиотеку. Тем не менее, когда я создаю библиотеку, а затем отправляю проект на другой компьютер, на котором я хочу иметь возможность скомпилировать проект только с использованием созданной мной библиотеки, я получаю сообщение об ошибке, в котором говорится, что требуется файл .h библиотеки Intel IPP. Любая идея? - person Royi; 23.02.2015
comment
lib обычно бывает недостаточно. Если вы хотите его использовать, вам также нужно будет включить файлы заголовков. Но здесь это не по теме, так как в этой ветке говорится о компоновке, а ваша проблема находится на стадии компиляции. - person evpo; 27.02.2015
comment
Ok. Чтобы помочь вам, мне понадобится дополнительная информация. Посмотрите на вывод сборки или журнал и посмотрите, что жалуется на отсутствующий файл .h. Думаю, это cl.exe. В этом случае вы получите имя скомпилированного файла .cpp / .cc / .c, который использует заголовок. Как называется этот файл .cpp и какому проекту он принадлежит? - person evpo; 04.03.2015
comment
Я так растерялся. До того, как я это прочитал, казалось, что это никогда не работало (так мои проекты уже настроены). Но теперь, когда я прочитал это и сбросил свои проекты, он, по-видимому, работает. Иди разберись! :( - person Mordachai; 06.03.2018
comment
@Mordachai, это хайку, приведенное ниже, прекрасно описывает ваш опыт: вчера это сработало, сегодня не работает, Windows такая - person evpo; 07.03.2018

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

Я написал сценарий 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

где lib, откуда вы хотите включить символы. Однако я думаю, что безопаснее всего сначала скопировать все в отдельный каталог. Я бы не стал так сильно доверять своему сценарию (однако он сработал для меня; я мог бы включить libgsl.a в свою числовую библиотеку с этим и не использовать переключатель компилятора -lgsl).

person Elmar Zander    schedule 15.01.2015
comment
Это отлично. Для большого проекта (›500 тысяч символов в› 40 тысячах объектов в исходной библиотеке, из которых мне понадобилось ~ 1000 символов) это заняло около часа, тогда как gcc может сделать то же самое с динамической компоновкой за несколько секунд. Есть ли какая-то фундаментальная причина, по которой это не так просто сделать и раскрыть с помощью инструментов компилятора? - person ZachB; 05.08.2020