Як вказати перевагу шляху бібліотеки?


94

Я складаю програму на C ++ за допомогою g++і ld. У мене є .soбібліотека, якою я хочу користуватися під час встановлення посилань. Однак бібліотека з однойменною назвою існує /usr/local/libі ldвибирає цю бібліотеку замість тієї, яку я прямо вказую. Як я можу це виправити?

У наведених нижче прикладах, моя бібліотека файлу /my/dir/libfoo.so.0. Те, що я спробував, але не працює:

  • моя команда g ++ - g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • додавання /my/dirдо початку або кінця моєї $PATHзмінної en`
  • додавання /my/dir/libfoo.so.0як аргумент до g ++

1
Які інші libfoo.*файли існують і де - .soб / н .0, .aі т.д. і т.п.?
Алекс Мартеллі,

Відповіді:


93

Додайте шлях до місця, куди спрямована ваша нова бібліотека LD_LIBRARY_PATH(вона має трохи іншу назву на Mac ...)

Ваше рішення має працювати з використанням -L/my/dir -lfooпараметрів, під час виконання використовуйте LD_LIBRARY_PATH, щоб вказати місце розташування вашої бібліотеки.

Обережно з використанням LD_LIBRARY_PATH - коротше (із посилання):

..імплікації ..:
Безпека : Пам'ятайте, що каталоги, вказані в LD_LIBRARY_PATH, шукаються до (!) стандартних розташувань? Таким чином, неприємна людина може отримати вашу програму для завантаження версії спільної бібліотеки, яка містить шкідливий код! Це одна з причин, чому виконувані файли setuid / setgid нехтують цією змінною!
Продуктивність: Завантажувач посилань повинен здійснити пошук у всіх зазначених каталогах, поки не знайде каталог, в якому знаходиться спільна бібліотека - для ВСІХ спільних бібліотек, до яких додаток пов’язаний! Це означає багато системних дзвінків до open (), які не вдасться виконати “ENOENT (немає такого файлу або каталогу)”! Якщо шлях містить багато каталогів, кількість невдалих викликів буде лінійно збільшуватись, і це можна буде визначити з часу запуску програми. Якщо деякі (або всі) каталоги перебувають у середовищі NFS, час запуску ваших програм дійсно може збільшитися - і це може сповільнити роботу всієї системи!
Невідповідність: Це найпоширеніша проблема. LD_LIBRARY_PATH змушує програму завантажувати спільну бібліотеку, з якою вона не була пов’язана, і яка, швидше за все, не сумісна з оригінальною версією. Це може бути дуже очевидним, тобто збій програми, або може призвести до неправильних результатів, якщо підібрана бібліотека не зовсім відповідає тому, що зробила б оригінальна версія. Особливо останнє часом важко налагодити.

АБО

Використовуйте параметр rpath через gcc для компонування - шлях пошуку в бібліотеці виконання буде використовуватися замість того, щоб шукати в стандартній директорії (параметр gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Це добре для тимчасового рішення. Linker спочатку шукає бібліотеки LD_LIBRARY_PATH, перш ніж переглядати стандартні каталоги.

Якщо ви не хочете постійно оновлювати LD_LIBRARY_PATH, ви можете зробити це на льоту в командному рядку:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Ви можете перевірити, що бібліотека знає про використання (приклад):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

І ви можете перевірити, яку бібліотеку використовує ваша програма:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)

22
LD_LIBRARY_PATHздійснюється пошук під час виконання, під час компіляції, яку ви хочете встановити LIBRARY_PATH. Дивіться gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren

1
Якщо ваша бібліотека повністю відрізняється від системної, тобто є такою, яку потрібно завжди використовувати, використовуйте рішення rpath. LD_LIBRARY_PATH - це хак для тестування, і він не повинен вимагати, щоб правильно виконати роботу.
user2746401

1
його DYLD_LIBRARY_PATH для Mac
cbinder

Ось повний зразок команди (для C), яка працює на основі цієї відповіді:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue

25

Це старе запитання, але, схоже, ніхто про це не згадував.

Вам пощастило, що річ взагалі пов'язувала.

Вам потрібно було змінитися

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

до цього:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Ваш компонувальник відстежує символи, які йому потрібно вирішити. Якщо він читає бібліотеку спочатку, він не має необхідних символів, тому ігнорує символи в ній. Вкажіть бібліотеки після речей, які мають на них посилатися, щоб ваш компонувальник мав символи для пошуку в них.

Крім того, -lfooвін робить пошук спеціально для файлу з іменем libfoo.aабо libfoo.soза потреби. Ні libfoo.so.0. Тож або lnназвіть, або перейменуйте бібліотеку як відповідне.

Щоб процитувати сторінку керівництва gcc:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Додавання файлу безпосередньо в g++командний рядок повинно було спрацювати, якщо, звичайно, ви не розмістили його раніше bar.cpp, змушуючи компонувальник ігнорувати його через відсутність необхідних символів, оскільки символи ще не потрібні.


22

Вказівка ​​абсолютного шляху до бібліотеки повинна працювати нормально:

g++ /my/dir/libfoo.so.0  ...

Ви пам’ятали видалити, як -lfooтільки додали абсолютний шлях?


1
Це рішення також добре працювало для мене - намагаючись встановити зв'язок із версією Qt5, відмінною від пакета розробки дистрибутиву. Дякую.
wump

Як змусити цю роботу працювати з @версійними символами? Мінімальний приклад: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

11

В якості альтернативи ви можете використовувати змінні середовища LIBRARY_PATHі CPLUS_INCLUDE_PATH, які відповідно вказують, де шукати бібліотеки, а де шукати заголовки ( CPATHце також буде робити роботу), не вказуючи параметрів -L та -I.

Редагувати: CPATHвключає заголовок із -Iі CPLUS_INCLUDE_PATHз -isystem.


Не могли б ви додати приклад для використання?
Ганна Халіл

export LIBRARY_PATH = /path/to/libв тій самій консольній сесії, де ви компілюєте
Олександр Хамез,

0

Якщо один використовується для роботи з DLL в Windows і хотів би пропустити номери версій .so у Linux / QT, додавання CONFIG += pluginвиведе номери версій. Використовувати абсолютний шлях до .so, передаючи його компонувальнику, чудово працює, як згадав пан Клачко.

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