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


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.