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

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

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

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

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


обновление:

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


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

6 ответов


статические библиотеки не связаны с другими статическими библиотеками. Единственный способ сделать это-использовать инструмент библиотекарь / архиватор (например,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 toolchain:

lib.exe /OUT:libab.lib liba.lib libb.lib

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


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

  1. откройте проект библиотеки (X), которую вы хотите объединить с другими библиотеками.
  2. добавьте другие библиотеки, которые вы хотите объединить с X (щелкните правой кнопкой мыши,Add Existing Item...).
  3. перейдите к их свойствам и убедитесь, что Item Type is 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=""
lib2=""

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 =$file
}
remove_tmp_files() {
    rm $remove_later
}
trap remove_tmp_files EXIT

find_symbols() {
    nm   | 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 в мою библиотеку чисел с этим и опустить, что-lgsl переключатель компилятора).