Зв’язування статичних бібліотек з іншими статичними бібліотеками


138

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

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

Я створив просту програму зразків, яка використовує функцію від X, але коли я намагаюся пов’язати її з X, я отримую багато помилок щодо відсутніх символів з бібліотек a_1 - a_n.

Чи є спосіб я створити нову статичну бібліотеку, Y, яка містить X і всю функціональність, необхідну для X (вибрані біти від a_1 - a_n), щоб я міг поширювати лише Y для людей, щоб зв’язати свої програми?


ОНОВЛЕННЯ:

Я переглянув, як просто скинути все з ar і зробити один мега-ліб, однак це закінчилося, включаючи безліч символів, які не потрібні (всі. МБ). Чи є приємний спосіб включити лише те, що потрібно насправді?


Це виглядає тісно пов’язаним із тим, як об’єднати кілька бібліотек C / C ++ в одну? .

Відповіді:


76

Статичні бібліотеки не зв'язуються з іншими статичними бібліотеками. Єдиний спосіб зробити це - використовувати ваш інструмент бібліотекаря / архіватора (наприклад, ar в Linux) для створення єдиної нової статичної бібліотеки шляхом об'єднання кількох бібліотек.

Редагувати: У відповідь на ваше оновлення єдиний спосіб, коли я знаю, щоб вибрати лише потрібні символи, - це створити бібліотеку вручну з підмножини файлів .o, що їх містять. Це складно, забирає багато часу та схильність до помилок. Я не знаю жодних інструментів, які допоможуть зробити це (не кажучи про те, що їх не існує), але для створення цього було б досить цікавий проект.


Привіт Ніл, я оновив питання - чи знаєш ти будь-який спосіб включити лише необхідні файли .o?
Джейсон Сундрам

Оновлення - якщо ви виявите, що хочете це зробити, зробіть крок назад і продовжуйте щось інше (якщо, як зазначає Джон Кноеллер, ви не використовуєте Visual Studio). Я багато часу займався таким підходом і нічого корисного не отримав.
Джейсон Сундрам

Інструмент GNU ld пропонує опцію, -rзавдяки якій вихід може використовуватися як вхід для ld. Якщо ви посилаєтесь один раз, вам слід отримати переїзд, ви можете сурогатувати ваші бібліотеки. (зробив це спробував).
harper

49

Якщо ви використовуєте Visual Studio, то так, ви можете це зробити.

Інструмент для створення бібліотек, який постачається разом із Visual Studio, дозволяє об’єднати бібліотеки разом у командному рядку. Я не знаю жодного способу зробити це у візуальному редакторі.

lib.exe /OUT:compositelib.lib  lib1.lib lib2.lib

5
У VS2008, у проектних властивостях compositelib у розділі Бібліотекар / Загальне, якщо ви перевіряєте [x] Залежності бібліотеки посилань, це зробить це для вас, якщо lib1 та lib2 - залежності compositelib. Здається, трохи баггі, я поставив би прапорець окремо у кожній конфігурації збірки, а не один раз у "Усі конфігурації".
Spike0xff

2
VS2015 IDE - чи не використовуєте Ви «Додаткові залежності» у бібліотекарі / загальних, щоб отримати додаткові бібліотеки, пов’язані безпосередньо з бібліотекою, яку будує ваш проект?
davidbak

@davidbak Я намагаюся розібратися в цьому за останні кілька днів і, мабуть, цей варіант застарів і нічого не робить?
Монтальдо

20

У 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

Приємно знати, але насправді це не вирішує проблему ОП, оскільки ви включаєте все, починаючи з libb.a до спільної, що може стати дуже великим, якщо вам потрібно лише кілька модулів від libb.
Ельмар Зандер

1
@ElmarZander Але ви можете використовувати ar crsT, що робить щось на зразок "символічного" замість копіювання, тоді вам потрібно лише передати одну копію даних.
Зірка блискуча

Тонкі архіви особливо використовуються на ядрі Linux v4.19: unix.stackexchange.com/questions/5518/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

10

Статична бібліотека - це лише архів .oфайлів об'єктів. Витягніть їх ar(припускаючи Unix) і запакуйте їх назад в одну велику бібліотеку.


6

Крім того, 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

Привіт, я використовую Intel IPP, і я створив свої власні функції, які я хочу, щоб усі були зведені в одну (статичну) ліб. Але коли я створю lib, а потім надсилаю проект на інший комп'ютер, який я хочу мати змогу скласти проект лише за допомогою створеної вами lib, я отримую помилку, кажучи, що потрібно .h файл бібліотеки IPP Intel Intel. Будь-яка ідея?
Рой

Файлу lib зазвичай недостатньо. Якщо ви хочете його використовувати, вам також потрібно буде включити файли заголовків. Але це вже поза темою, оскільки ця тема розповідає про зв'язок, і ваша проблема знаходиться на етапі компіляції.
evpo

гаразд. Щоб допомогти вам, мені знадобиться додаткова інформація. Подивіться на висновок збірки або журнал і подивіться, що скаржиться на відсутній .h файл. Я думаю, що це cl.exe. Якщо це так, він дасть вам ім'я складеного .cpp / .cc / .c файлу, який використовує заголовок. Як називається файл .cpp та якому проекту він належить?
evpo

Я так розгублений. Перш ніж я прочитав це, здавалося, ніколи не працював (ось так налаштовані мої проекти). Але тепер, коли я прочитав це і скинув свої проекти, це, мабуть, працює. Піди розберися! :(
Мордахай

1
@Mordachai цей хайку нижче описує ваш досвід чудово: Вчора він працював Сьогодні він не працює Windows - це так
evpo

5

Зауважте, перш ніж прочитати решту: скрипт оболонки, показаний тут, звичайно, не є безпечним у використанні та добре перевірений. Використовуйте на свій страх і ризик!

Я написав баш сценарій для виконання цього завдання. Припустимо, у вашій бібліотеці 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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.