Зачем ld нужна библиотека, от которой зависит мой исполняемый файл? - PullRequest
0 голосов
/ 15 декабря 2018

Я пытаюсь собрать свой исполняемый файл (который зависит от библиотеки utils.so), используя следующую команду

g++ -L/path/to/libutils -lutils -I/path/to/utils_headers executable.cpp -o executable

На самом деле у меня нет utils.so - только заголовочные файлы библиотеки utils,

Я получаю сообщение об ошибке:

ld: cannot find -lutils

Нужен ли компоновщику доступ ко всем библиотекам, от которых зависит мой исполняемый файл, для создания моего исполняемого файла?Если да, то я хотел бы знать, зачем ему нужен доступ к ним.

Мой исполняемый файл - это общая библиотека.Я уверен, что для его сборки достаточно заголовочных файлов из библиотеки utils (т.е. без использования utils.so).

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

Параметр связывания -lutils по умолчанию направляет компоновщик на поиск сначала в указанных каталогах поиска библиотеки (-Ldir), а затем в его каталогах поиска по умолчанию для любого из файлов libutils.so (общая библиотека) илиlibutils.a (статическая библиотека), предпочитая libutils.so, если они оба находятся в одном каталоге поиска.

Если такой файл найден, компоновщик прекращает поиск и добавляет этот файл во входные файлысвязь, независимо от того, разрешает ли она какие-либо ссылки в связи .Компоновщик не может знать, разрешает ли файл какие-либо ссылки, если он не вводит файл.

Если такого файла не найдено, компоновщик выдает ошибку: cannot find -lutils.Потому что вы сказали ему найти libutils.{so|a}, а он не смог.

Вы говорите:

Мой исполняемый файл - это общая библиотека

Но это не так.«т.Ваша команда compile-and-link:

$ g++ -L/path/to/libutils -lutils -I/path/to/utils_headers executable.cpp -o executable

не является попыткой связать общую библиотеку.Это попытка связать программу. 1

Это попытка связать общую библиотеку:

$ g++ -shared -I/path/to/utils_headers -o libexecutable.so executable.cpp -L/path/to/libutils -lutils

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

Итак, вы можете связать libexecutable.so вот так, или вы можете связать его просто так:

$ g++ -shared -I/path/to/utils_headers -o libexecutable.so executable.cpp

Это два разныхсвязи: в случае успеха они создают разные выходные файлы.

В первой связи некоторые символы будут (предположим) преобразованы в определения, приведенные в libutils.so или libutils.a (в зависимости от того, какой из них найден), иэто будет отражено следующим образом:

  • libutils.so найдено: Раздел .dynamic в libexecutable.so содержит структуру DT_NEEDED, которая выражает зависимость во время выполненияна libutils.so.libutils.so необходимо будет включить в любую связь, которая включает libexecutable.so, но выходной файл такой связи сам будет содержать зависимость времени выполнения только от libexecutable.so.

  • libutils.a найдено: libexecutable.so само содержит определения для всех используемых им символов, которые определены объектными файлами вlibutils.a. 2 libexecutable.so могут быть включены в последующие связи без необходимости libutils.{so|a}.

Во второй связи раздел .dynamic в libexecutable.so будет не выражать зависимость времени выполнения от libutils.so или файл содержит определения любых символов, предоставленных libutils.{so|a}.libutils.so (снова) необходимо будет включить в последующую связь, которая включает в себя libexecutable.so, но выходной файл такой связи получит независимые зависимости времени выполнения как для libexecutable.so, так и libutils.so.

Но, если вы укажете -lutils в связи - или какой-либо связи - и компоновщик не сможет найти libutils.{so|a} ни в одном из своих каталогов поиска, то вы получите ошибку, которую видите, потому что вы сказали компоновщикуввести файл, влияние которого на связь может быть определено и реализовано только в том случае, если этот файл найден - и его невозможно найти.


[1] Попытка, которая может быть неудачной, поскольку он использует библиотеки перед объектными файлами, которые ссылаются на них

[2] См. static-library , чтобы понять, почему.

0 голосов
/ 15 декабря 2018

Как правило, компоновщик ELF нуждается в достаточно точном представлении общего объекта, с которым он связан. Это не обязательно должен быть фактически работающий общий объект, просто достаточно близкое его представление.Несколько вещей абсолютно требуют данных, которые недоступны в самом объекте:

  • При компиляции программ на С ссылка на глобальный объект данных неполного типа не содержит информацию о размере,Компоновщик не может поместить объект в сегмент данных, если он не получает информацию о размере откуда-либо.По умолчанию (при компиляции для исполняемых файлов, включая PIE) объект должен быть размещен в сегменте данных по многим целям из-за перемещений, которые компилятор использует для компиляции доступа к глобальным объектам данных.
  • Аналогично, редактор ссылокможет привести к неправильному выравниванию глобальных объектов данных, если у него недостаточно информации.
  • Многие библиотеки используют управление версиями символов.Информация о версии символа доступна только тогда, когда редактор ссылок может видеть общий объект.Если эта информация отсутствует, редактор ссылок не выдаст версию символа, которая инструктирует динамический компоновщик связывать символ с базовой версией во время выполнения, что приводит к незначительным ошибкам.

Однако, есливы используете только символы функций C (не символы данных или разновидности символов, которые требуются C ++) и целевая библиотека не использует версионирование символов, вы можете использовать библиотеку-заглушку для компоновки.Это библиотека, которая определяет все функции, которые вам нужны, и имеет соответствующее имя, но эти функции - всего лишь пустышки, которые на самом деле ничего не делают.

...