Linux find undefined symbol

Benohead’s Software Blog

Linux: C++ lookup error – undefined symbol

At a customer site, we had a C++ program (renamed for the purpose of this blog to myprogram) which was failing after running for some time. It’s a program processing messages from an external system and seemed to fail only when the processing of the message triggered some given operations. The error message was:

The first thought was to use ldd to check whether everything was fine:

So many not found ! Ok I must have forgotten something… Of course, LD_LIBRARY_PATH is probably not set in my shell:

  • pidof return the id of the process running the specified program
  • /proc/10132/environ contains the whole environment of the specified process
  • strings is required to convert the 0x00 separated strings of /proc/xxx/environ
  • The rest just gets the line LD_LIBRARY_PATH=… and uses export to set it in my shell as well

Now I have the same LD_LIBRARY_PATH as the process running myprogram and can rerun ldd:

Everything looks OK. So it’s not that a library is missing. Also the paths to the libraries are OK.

Executing ldd -r -d myprogram basically just shows me the same plus an error with the missing symbol.

Finally, comparing the size of the library files on this system and at another customer site with the exact same version of the software gave us the answer: somehow a different version of one of our library landed there and didn’t contain the missing symbol.

So the search ended there. Otherwise we’d have had to use the following:

Use c++filt to find out the method behind the mangled symbol name:

Use nm to list the symbols in the libraries shown by ldd:

This will show the mangled symbol names. For demangled symbols, use the -C option:

Источник

undefined symbol статической библиотеки

Всем привет. У меня возникла следующая проблема:

есть библиотека mimetic с открытым кодом, собрал её как статическую libmimetic.a.

использую её в своем классе, который тоже собирается как статическая библиотека libparser.a.

этот класс является членом класса-обёртки для создания своего плагина libplugin.so.

А попытка загрузить плагин в основном приложении при помощи QPluginLoader заканчивается ошибкой «undefined symbol: _ZN7mimetic18ContentDisposition5labelE».

При помощи утилиты nm я поискал этот символ в созданных выходных файлах:

0000000000000000 t _GLOBAL__sub_I__ZN7mimetic18ContentDisposition5labelE

0000000000000000 R _ZN7mimetic18ContentDisposition5labelE

Не понимаю почему этот символ остается с пометкой undefined и как это изменить, если, конечно, это решит мою проблему. Буду рад любым конструктивным советам.

Проект пишу в Qt, компилятор GCC

Статические библиотеки чувствительны к порядку при линковке. Как линкуете? Ну и не страдайте фигнёй, используйте нормальные сошки.

Где-то в описании своего проекта надо задать зависимость библиотеки parser от mimetic так чтобы эта зависимость пробрасывалась системой сборки до plugin . Как уже написали порядок линковки важен, но система сборки должна сама это разруливать.

Статические библиотеки чувствительны к порядку при линковке. Как линкуете?

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

Читайте также:  Linux mint boot from flash

У ТСа, как я понял, динамическое подключение плагина, но символ, который нужен плагину находится в статической библиотеке, но он был на этапе линковки не нужен и не помещен в бинарник.

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.

Вроде как, объединение в группы это исправляет или смена на линкер, которому порядок не важен.

У ТСа, с виду, при линковки libplugin.so не указано -lmimetic . Но без подробностей как идет сборка трудно сказать.

Этот пример не о том, объектники не совсем библиотеки, если речь про библиотеки, то их и надо собирать как библиотеки и там порядок не важен и даже невозможен, так как взаимная зависимость библиотек — везде и всюду.

Забавно, что в gcc любой порядок прокатывал до версии 8.X.X. При переходе на 9-ю версию начались рвать подводные камни, пришлось местами менять порядок либ.

У ТСа, с виду, при линковки libplugin.so не указано -lmimetic.

Для статической mimetic.a это ведь ничего не даст.

Именно так. Если линкуются две библиотеки и одна использует символы из другой, то они слинкуются только в одном порядке.

undefined symbol: _ZN7mimetic18ContentDisposition5labelE

Не хотелось расписывать, но таки придётся. Если библиотека содержит несколько объектников, то символы будут последовательно выбраны и прилинкованы одним проходом просмотра библиотек. Но если символы в одном из объектников в каждой библиотеке, то все требуемые объектники будут заюзаны, а символы будут рекурсивно слинкованы, что ТСу и надо.

Молодец! Только вот это распарсь:

И зачем же ты врёшь?

Не думаю, что в GCC 8 что-то меняли, это не какое-то новое поведение. Обычно разница в поведении объясняется различиями в параметрах по умолчанию в разных дистрибутивах, так что некоторые просто не сталкиваются пока умолчания не поменяют.

Я дал полное объяснение с примером, в чём проблема у ТСа, беретё, выполняете и не врёте.

Описание того как линкер якобы работает вообще не понял (хотя я знаю как). Так что просто переделал пример, чтобы это было видно, а не скрывалось зависимостями от m.c к обоим объектным файлам в библиотеках:

а не скрывалось зависимостями от m.c к обоим объектным файлам в библиотеках:

А это ведь и надо ТСу сделать. У него нет зависимости от символа в основном модуле, но есть в плагине, но загружается только плагин без подгрузки нужного символа. Отсюда и получается, что либо внести символ в объектник плагина либо сделать экпортируемым символом из основного бинаря, чтобы оно его захотело, каким угодно пустым хаком, ну там адрес получить и прочим stub-ом.

А, так это был такой своеобразный вариант решения. Я не понял.

Раз плагин зависит от этой библиотеки, то ему её и тащить.

Второй вариант диковато смотрится. Приложение не должно выборочно включать те символы, которые используются в плагинах. Тогда уже логично всю библиотеку затащить через —whole-archive , если она большинству плагинов необходима.

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

Читайте также:  How to reboot linux

Много много лет компилил на всем, на чем может компилиться, от слакварей с центозами до дебианов, от фри всех версий до солярки, синологи, какие только можно роутеры. И тут мне вдруг присылают, что моя программа не компилится на убунте 20-й… Пришлось поменять местами $(LIBS) $(OBJS), которые шли в таком порядке больше 20 лет… Меня это удивило немного, но не сильно нарпягло. В убунте стоит gcc 9.x.x

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

открываешь любой проект на гитхабе на qt и смотришь как они собирают и экспортируют символы

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

Но не обращая внимание на это, у меня остается непонимание почему линковщик не пытается определить этот символ.

в файле contentdescription.h содержится объявление переменной:

которое добавляется в parser.cpp при подключении этого файла при помощи #include.

В одном из методов моего класса она используется следующим образом:

В моем понимании, если бы я не использовал в своем коде mimetic::ContentDescription::label, то линковщик мог бы оставить символ этой переменной неразрешенным, а раз я эту переменную использую, то он должен найти определение, либо выдать ошибку, что ему это не удалось сделать, но видимо у меня проблемы с пониманием процесса сборки.

Вы оказались правы. После указания в pro-файл проекта, создающего плагин, библиотеки -lmimetic всё получилось. Но пришлось почему-то указывать не обычным способом:

У Вас, возможно, проблемы в настройках проектов. В идеале должно быть так: в билд системе указывается что plugin зависит от parser , а parser зависит от mimetic . Для сборки plugin билд система прописывает где искать хиадеры обоих библиотек, а для линковки какие либы линковать и в каком порядке. Если все это делать руками, то можно упороться, особенно при развесистых зависимостях.

Источник

Запускаю приложение — выдает undefined symbol

Добрый день, товарищи. Ситуация такая: есть сервер, на котором благополучно работает одна тулза некогда написанная на qt. Так вот. Появилась необходимость перенести все на новый сервер.
Все перенеслось, однако теперь на новом серве эта тулза не запускается и выдает :

undefined symbol _ZN9QListData11detach_growEPii

На старом серве стоит Debian Lenny, на новом и собственно у меня Debian Stable.
Чем вообще может быть вызвана данная ошибка, и что за этакий «символ»?

Я бы проверил какие версии Qtшных so’шек там и там

ты серьёзно это?

Пересобрать её не пробовал?

Может тулза не его, а исходники хз где.

ты всегда через через 5 слов читаешь?

Также не помешает полная переустановка всех qt’шных пакетов.

ССЗБ. ЗЫ как крайний вариант, собрать все нужные .so со старой тачки, перекинуть в отдельную папку на новом серве и юзать LD_LIBRARY_PATH.

Не думаю что встанет без проблем.

Надеюсь всё будет так: ты распакуешь руками пакетик в директорию с исполняемым файлом. Файло вначале посмотрит нужные soшки в текущей директории, возрадуется и перестанет материться. Или можно пакеты распаковать куда-нибудь и развлекаться с export LD_LIBRARY_PATH или как его там.

Собственно, думаю проблема действительно в версиях. Ещё такая штука, есть некий deb пакет, я так понимаю как раз с нужными версиями so’шек. Но вопрос: если собирали его в lenny, станет он без проблем на stable?

З.Ы. Тулза не моя, исходников х3 где.

Читайте также:  Как изменить внешний вид линукс минт

Можно ручками распаковать содержимое в отдельную папочку (в /opt/, например, или в /usr/local/). Потом пути прописать правильно и все.

А если я их в отдельную папку, которую потом запихку в lib, так не покатит?

А если я их в отдельную папку, которую потом запихку в lib, так не покатит?

Нет так делать не стоит.

Только так и сработает. Искать либы в директории с исполняемым файлом умеет только винда.

Хм, а что мешает прописать -L. в ключах gcc?

Хм, а что мешает прописать -L. в ключах gcc?

Казалось бы, причём тут это

Не покатило. Распаковал деб пакет. И скинул папку из пакета в /usr/lib/

Я же писал ранее, что скидывать надо либо в /opt/’имя программы’/, либо в /usr/local/lib/ и писать скрипт для запуска программы, который будет устанавливать переменную LD_LIBRARY_PATH, добавляя в начало этот путь.

С LD_LIBRARY_PATH можно «скидывать» куда угодно.

Конечно можно. Главное не потерять потом и с системными файлами не спутать.

Спасибо. Буду рыть что такое LD_LIBRARY_PATH, и с чем его едят

Всем спасибо. Создал RunMapGetter.sh

Остался ещё один косяк. У проги есть конфиговский файл. В нем указан путь к папке с которой нужно работать тулзе. Так вот при запуске через

Относительными путями в программе. Если исполняемый файл был в /usr/bin, а переехал в /opt/progname/bin, и путь к конфигу зашит как ../../etc/prog.conf, то конфиг надо перенести в /opt/progname/etc/

Конфиг всегда лежил там, где и исполняемый файл. Там же он находится и сейчас.

Чем вообще может быть вызвана данная ошибка

Несовпадением версии Qt используемой для сборки и для запуска.

Внутренняя функция реализации шаблона QList. Ссылка на нее затянулась из заголовков, т.к. это шаблон (если бы был обычный класс, все обращения к деталям реализации остались бы в пределах Qt)

лучше проверить где действительно должен быть конфиг:

MapGetter.sh присутствует в /home/mobitee/mapgettool

strace -xf -eopen -o out.log RunMapGetter.sh

strace -xf -eopen -o out.log ./RunMapGetter.sh При условии что RunMapGetter.sh в текушей директрии.

если strace скажет, что программа ищет конфигурацию только по тому пути (i:\Project\MapGetter\files\), то можно попробовать такую штуку (допустим файл конфига называется config.cfg):

даже если так запустить?

Вижу что тут что-то дельное, но сразу объясню, в чем трабл ещё раз. Программа запускается. В конфиге указывается папка, с которой тулза должна работать. Конфиг лежит рядом с тулзой, и папка указана. Как только запускается тулза, она пишет с какой папкой работает. Так вот. Если я запускаю программу на старом сервере, все ок, пишет что работает с той папкой, которая в конфиге. А при запуске на новом сервере через .sh пишет что будет работать с папкой, ну совсем не той, что в конфигах, и путь к папке этой виндосовский. Предполагаю, что тулза писалась в винде, и путь там по дефоулту.

Что можете сейчас посоветовать?

strace и sed. Тулза конфиг похоже не находит, а где она его ищет скажет strace. Как отличаются пути до тулзы на старом и новом сервере?

Источник

Оцените статью