Почему я получаю «неопределенную ссылку» при связывании с моей собственной статической библиотекой? [Дубликат]

Вы можете использовать словари, чтобы выполнить это. Словари - это хранилища ключей и ценностей.

>>> dct = {'x': 1, 'y': 2, 'z': 3} >>> dct {'y': 2, 'x': 1, 'z': 3} >>> dct["y"] 2

Вы можете использовать имена переменных ключей для достижения влияния переменных переменных без риска для безопасности.

>>> x = "spam" >>> z = {x: "eggs"} >>> z["spam"] 'eggs'

В тех случаях, когда вы думаете сделать что-то вроде [ ! d2] var1 = 'foo' var2 = 'bar' var3 = 'baz' ...

список может быть более уместным, чем dict. Список представляет упорядоченную последовательность объектов с целыми индексами:

l = ['foo', 'bar', 'baz'] print(l[1]) # prints bar, because indices start at 0 l.append('potatoes') # l is now ['foo', 'bar', 'baz', 'potatoes']

Для упорядоченных последовательностей списки удобнее, чем dict с целыми ключами, потому что списки поддерживают итерацию в порядке индекса, нарезки, append , и другие операции, которые потребуют неудобного управления ключами с помощью dict.

385
задан Ciro Santilli 新疆改造中心 六四事件 法轮功 9 June 2015 в 18:48
поделиться

10 ответов

Компонент GNU ld - это так называемый интеллектуальный компоновщик. Он будет отслеживать функции, используемые предыдущими статическими библиотеками, постоянно отбрасывая те функции, которые не используются из его таблиц поиска. В результате, если вы связали статическую библиотеку слишком рано, то функции в этой библиотеке больше не будут доступны для статических библиотек позже в линии ссылок.

Типичный компоновщик UNIX работает слева направо, поэтому поместите все ваши зависимые библиотеки слева и те, которые удовлетворяют этим зависимостям справа от линии ссылки. Вы можете обнаружить, что некоторые библиотеки зависят от других, в то время как другие библиотеки зависят от них. Здесь все усложняется. Когда дело доходит до круговых ссылок, исправьте свой код!

90
ответ дан casualcoder 20 August 2018 в 20:36
поделиться
  • 1
    Это что-то только с gnu ld / gcc? Или это что-то общее с линкерами? – Mike 5 September 2008 в 04:17
  • 2
    По-видимому, больше компиляторов Unix имеют схожие проблемы. MSVC не полностью свободен от этих проблем, но они, похоже, не так уж плохи. – MSalters 28 April 2009 в 15:42
  • 3
    Средства MS dev не склонны показывать эти проблемы так сильно, потому что, если вы используете целую цепочку инструментов для всех, она заканчивает настройку правильного компоновщика, и вы никогда не замечаете эту проблему. – Michael Kohne 28 August 2009 в 21:59
  • 4
    Компонент MSVC менее чувствителен к этой проблеме, потому что он будет искать все библиотеки для символа без ссылок. Заказ библиотеки по-прежнему может повлиять на , символ будет разрешен, если более чем одна библиотека имеет символ. Из MSDN: «Библиотеки также выполняются в порядке командной строки, со следующим оговоркой: сначала ищутся символы, которые неразрешимы при вводе объектного файла из библиотеки, а затем следующие библиотеки из командной строки и / DEFAULTLIB (указать библиотеку по умолчанию), а затем в любые библиотеки в начале командной строки & quot; – Michael Burr 24 April 2012 в 07:19
  • 5

Я видел это много, некоторые из наших модулей связывают более 100 библиотек нашего кода плюс система & amp; Сторонние библиотеки.

В зависимости от разных компоновщиков HP / Intel / GCC / SUN / SGI / IBM / etc вы можете получить нерешенные функции / переменные и т. д., на некоторых платформах вам нужно дважды перечислить библиотеки.

По большей части мы используем структурированную иерархию библиотек, ядро, платформу, разные уровни абстракции, но для некоторых систем вам все равно придется играть с порядком в команде link.

Как только вы нажмете на документ решения, чтобы следующий разработчик не смог его снова обработать.

Мой старый лектор говорил: « высокая степень сцепления и низкая связь », это по-прежнему актуально и сегодня.

19
ответ дан darrenp 20 August 2018 в 20:36
поделиться

Порядок ссылок определенно имеет значение, по крайней мере на некоторых платформах. Я видел сбои для приложений, связанных с библиотеками в неправильном порядке (где неправильные средства A связаны до B, но B зависит от A).

2
ответ дан David Cournapeau 20 August 2018 в 20:36
поделиться

Другой альтернативой было бы указать список библиотек дважды:

gcc prog.o libA.a libB.a libA.a libB.a -o prog.x

Выполняя это, вам не нужно беспокоиться о правильной последовательности, так как эта ссылка будет разрешена во втором блоке.

7
ответ дан eckes 20 August 2018 в 20:36
поделиться

Вот пример, чтобы прояснить, как все работает с GCC при использовании статических библиотек. Итак, предположим, что мы имеем следующий сценарий:

  • myprog.o - содержащий функцию main(), зависящую от libmysqlclient
  • libmysqlclient - статично, ради примера (вы предпочтете разделяемую библиотеку, конечно, поскольку libmysqlclient огромен); в /usr/local/lib; и зависит от материала из libz
  • libz (dynamic)

Как мы это связываем? (Примечание: примеры компиляции на Cygwin с использованием gcc 4.3.4)

gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too

gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works
49
ответ дан Lumi 20 August 2018 в 20:36
поделиться

Быстрый совет, который меня опрокинул: если вы ссылаетесь на компоновщик как «gcc» или «g ++», то использование «--start-group» и «--end-group» не будет передавать эти параметры до линкера - и не будет отмечена ошибка.

Вам нужно записать их как «-Wl, - start-group» и т. Д., Чтобы сообщить GCC передать аргумент через к компоновщику.

4
ответ дан M.M 20 August 2018 в 20:36
поделиться

(см. историю этого ответа, чтобы получить более сложный текст, но теперь я думаю, что читателю легче увидеть реальные командные строки).


Общие файлы, общие для всех команд ниже

$ cat a.cpp
extern int a;
int main() {
  return a;
}

$ cat b.cpp
extern int b;
int a = b;

$ cat d.cpp
int b;

Связывание со статическими библиотеками

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o

$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

Компонент выполняет поиск слева направо и отмечает неразрешенные символы. Если библиотека разрешает символ, он принимает объектные файлы этой библиотеки для разрешения символа (b.o из libb.a в этом случае).

Зависимости статических библиотек друг от друга работают одинаково - библиотека, которая нуждается в символах, должна быть первой, а затем библиотекой, которая разрешает символ.

Если статическая библиотека зависит от другой библиотеки , но другая библиотека снова зависит от прежней библиотеки, есть цикл. Вы можете разрешить это, включив циклически зависимые библиотеки с помощью -( и -), например -( -la -lb -) (вам может понадобиться избежать появления парсеров, таких как -\( и -\)). Затем компоновщик выполняет поиск вложенных библиотек несколько раз, чтобы гарантировать, что зависания на велосипеде разрешены. Кроме того, вы можете указывать библиотеки несколько раз, поэтому каждый из них находится друг перед другом: -la -lb -la.

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

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!

$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

Здесь то же самое - библиотеки должны следуйте объектным файлам программы. Разница здесь в статических библиотеках заключается в том, что вы не должны заботиться о зависимостях библиотек друг от друга, потому что динамические библиотеки сами сортируют свои зависимости .

Некоторые недавние дистрибутивы, по-видимому, по умолчанию используют флаг компоновщика --as-needed, который обеспечивает, чтобы объектные файлы программы приходили перед динамическими библиотеками. Если этот флаг передан, компоновщик не будет ссылаться на библиотеки, которые фактически не нужны исполняемому файлу (и он обнаруживает это слева направо). Мой недавний дистрибутив archlinux по умолчанию не использует этот флаг, поэтому он не дал ошибку, чтобы не следовать правильному порядку.

Неправильно пропустить зависимость b.so от d.so при создании первого. При связывании a вам потребуется указать библиотеку, но a действительно не нуждается в самом целочисленном b, поэтому не следует заботиться о собственных зависимостях b.

Вот пример последствий, если вы пропустили определение зависимостей для libb.so

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)

$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"

. Если теперь вы посмотрите на зависимости, которые имеет двоичный файл, вы заметите сам бинарный файл зависит также от libd, а не только от libb. Бинарный файл нужно будет перемотать, если позже libb зависит от другой библиотеки, если вы сделаете это так. И если кто-то загружает libb, используя dlopen во время выполнения (подумайте о загрузке плагинов динамически), вызов также не удастся. Поэтому "right" действительно должен быть wrong.

480
ответ дан psmears 20 August 2018 в 20:36
поделиться
  • 1
    Повторяйте до тех пор, пока все символы не будут решены, а вы думаете, что они могут управлять топологическим типом. LLVM имеет 78 статических библиотек на своем собственном уровне, с теми, кто знает, какие зависимости. Правда, у него также есть скрипт для определения параметров компиляции / ссылки, но вы не можете использовать его при любых обстоятельствах. – Steve314 11 July 2010 в 14:27
  • 2
    @Steve это то, что делают программы lorder + tsort. Но иногда нет порядка, если у вас есть циклические ссылки. Затем вам просто нужно перебирать список библиотек, пока все не будет разрешено. – Johannes Schaub - litb 18 August 2011 в 20:01
  • 3
    @Johannes. Определите максимальные сильно связанные компоненты (например, алгоритм Tarjans), затем топологически сортируйте (по сути нециклический) орграф компонентов. Каждый компонент можно рассматривать как одну библиотеку - если требуется какая-либо одна библиотека из компонента, цикл (и) зависимостей приведет к необходимости использования всех библиотек в этом компоненте. Нет, нет необходимости циклически перебирать все библиотеки, чтобы разрешить все, и не нужно неудобных параметров командной строки. Один метод, использующий два известных алгоритма, может корректно обрабатывать все случаи. – Steve314 18 August 2011 в 23:44
  • 4
  • 5
    Ваш ответ помог мне решить мои ошибки связи, и вы очень четко объяснили, КАК избежать неприятностей, но есть ли у вас какие-либо идеи, ПОЧЕМУ он был предназначен для работы таким образом? – Anton Daneyko 18 March 2014 в 12:29
  • 6
    Фантастическая запись: она получает от меня голос. Я добавлю в раздел решение циклических зависимостей , я оставлю его на оригинальном плакате, если они захотят изменить, что при передаче опций --start-group и --end-group с использованием gcc вы должны предшествует -Wl,<option>, как в -Wl,--start-group <archives> -Wl,--end-group. Это упоминается в справочной странице, на которую ссылаются, но здесь очень полезно упоминать об этом. – Andrew Falanga 4 September 2014 в 17:27

Я бы предположил, что это связано с тем, что некоторые из этих библиотек зависят от других библиотек, и если они еще не были связаны, вы получите ошибки компоновщика.

0
ответ дан roo 20 August 2018 в 20:36
поделиться

Вы можете использовать опцию -Xlinker.

g++ -o foobar  -Xlinker -start-group  -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a  -Xlinker -end-group 

ALMOST равно

g++ -o foobar  -Xlinker -start-group  -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a  -Xlinker -end-group 

Осторожно!

  1. Порядок в группе важен! Вот пример: библиотека отладки имеет процедуру отладки, но библиотека без отладки имеет слабую версию. Вы должны поместить библиотеку отладки FIRST в группу или вы решите на не-отладочную версию.
  2. Вам нужно перед каждой библиотекой в ​​списке групп с -Xlinker
5
ответ дан sra 20 August 2018 в 20:36
поделиться
19
ответ дан darrenp 31 October 2018 в 15:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: