Undefined ссылка на 'pthread_create' - порядок опций команды компоновщика (библиотеки до/после объектных файлов?)

Когда я пытаюсь скомпилировать это, я получаю определенную ошибку. Но это невозможно, потому что я использую правильный флаг. В server.c находится библиотека pthread.h. Итак, как я могу решить проблему связи? Я использую Linux (Ubuntu).

make
gcc -c -Wall -Wunused -ansi -pedantic -ggdb  -o Server1.o Server.c
gcc -c -Wall -Wunused -ansi -pedantic -ggdb  Util.c
gcc -o Server1.exe -Wall -Wunused -ansi -pedantic -ggdb -lpthread -lm Server1.o Util.o
Server1.o: In function `main':
/home/ruggero/ruggero_fine/Server.c:1002: undefined reference to `pthread_create'
collect2: ld returned 1 exit status
make: *** [Server1.exe] Errore 1

Ответ 1

Список библиотек после объектных файлов

При связывании только объектных файлов и библиотек список библиотек после файлов объектов:

gcc -o Server1.exe -Wall -Wunused -ansi -pedantic -ggdb  Server1.o Util.o -lpthread -lm

Когда команда связывания включает исходные файлы, перечислите исходные файлы и файлы объектов (если они есть) перед libaries. Поэтому параметры -l находятся в конце командной строки. Релевантные опции -l, определяющие, где находится библиотека, должны быть представлены перед параметром -l, определяющим библиотеку.

Дочерний вопрос:

Почему это работает?

Когда компилятор C вызывает компоновщик, он сообщает компоновщику вытащить некоторые системные объектные файлы с именами типа crt0.o и говорит ему искать символ main (или, возможно, _main(), в зависимости от локального именования). Он также предоставляет объектные файлы и библиотеки в порядке, указанном в командной строке. Когда он сталкивается с объектным файлом, компоновщик отмечает определения, которые он предоставляет, и неудовлетворенные ссылки, которые он делает. Когда он сталкивается с библиотекой, он просматривает библиотеку, чтобы узнать, может ли она удовлетворять любые неудовлетворенные ссылки. Если библиотека может предоставить любые еще неудовлетворенные ссылки, то она включает (соответствующие части) библиотеки "в исполняемом файле". Для общей библиотеки компоновщик гарантирует, что библиотека будет загружена во время выполнения. Для статической библиотеки компоновщик включает в себя объектные файлы из библиотеки, которые удовлетворяют хотя бы одной ссылке, повторное сканирование до тех пор, пока не будет никаких дополнительных ссылок, которые могут быть удовлетворены. Если библиотека не удовлетворяет никаким ссылкам, она игнорируется. Когда процесс будет завершен, если какие-либо ссылки все еще не удовлетворены, вы получите сообщения об ошибках.

Итак, в вашем сценарии у вас было -lpthread до либо Server1.o, либо Util.o. Поскольку -lpthread не предоставляет функцию main, и это был единственный соответствующий неудовлетворенный символ, он игнорировался. Библиотека математики, -lm также может быть проигнорирована или может быть пустой заглушкой, чтобы код был разработан для других систем, где библиотека математики отделена от основной библиотеки C. Затем компоновщик прочитал ваши объектные файлы и нашел ссылку на pthread_create(). Когда он затем просмотрел библиотеку C -lc (libc.so), он обнаружил, что символы удовлетворяют всем, кроме pthread_create.

Когда библиотеки перечислены после объектных файлов, тогда компоновщик знал, что ему нужно pthread_create, когда он сканирует -lpthread и гарантирует, что общая библиотека будет загружена во время выполнения.

GNU ld и параметр --as-needed

Дискуссия выше по существу нейтральна к платформе. Если вы следуете правилу "библиотеки после объектных файлов", ваша линия компоновщика имеет максимальную вероятность правильной работы на всех платформах.

Если вы используете систему с использованием пакета GNU binutils и, в частности, GNU ld, вы можете найти другое поведение.

Пособие от Sourceware (где вы перенаправлены, если вы попробуете http://www.gnu.org/software/binutils/manuals) включает в себя информацию:

--as-needed
--no-as-needed
Этот параметр влияет на теги ELF DT_NEEDED для динамических библиотек, упомянутых в командной строке после опции --as-needed. Обычно компоновщик добавляет тег DT_NEEDED для каждой динамической библиотеки, упомянутой в командной строке, независимо от того, нужна ли библиотека или нет. --as-needed приводит к тому, что тег DT_NEEDED будет выпущен только для библиотеки, которая в этой точке ссылки удовлетворяет несимвольной ссылке символа undefined из файла обычного объекта или, если библиотека не найдена в списках DT_NEEDED других библиотеки, не-слабая ссылка символа undefined из другой динамической библиотеки. Объектные файлы или библиотеки, появляющиеся в командной строке после соответствующей библиотеки, не влияют на то, просматривается ли библиотека по мере необходимости. Это похоже на правила для извлечения объектных файлов из архивов. --no-as-needed восстанавливает поведение по умолчанию.

Похоже, что разные версии разных систем используют разные значения для параметра as-needed. Хотя поведение --no-as-needed удобно в том, что оно позволяет упорядочивать библиотеки и объектные файлы в более или менее любом порядке в командной строке, это также означает, что все библиотеки, перечисленные в командной строке, загружаются во время выполнения, даже если не являются символами, фактически используемыми из библиотеки (таким образом, --no-as-needed эквивалентно гипотетическому флагов --whether-needed-or-not). Использование опции --as-needed - классическое и портативное поведение.

Случается, что некоторые дистрибутивы Linux изменили поведение по умолчанию на своих системах от --no-as-needed до --as-needed за последние 5 лет или около того (первая половина второго десятилетия третьего тысячелетия ради аргумента). Вы можете найти доказательства в поддержку этого слуха по ряду вопросов о SO.

Ответ 2

Используйте -pthread при компиляции. Попробуйте, и вы решите свою проблему.