Почему флаг компоновщика библиотеки иногда должен идти в конце, используя GCC? - PullRequest
19 голосов
/ 23 февраля 2012

Я пишу небольшую программу на C, которая использует librt.Я весьма удивлен тем, что программа не будет компилироваться, если я поставлю флаг ссылки в начале, а не в конце:

В данный момент для компиляции программы я делаю:

gcc -o prog prog.c -lrt -std=gnu99

Если бы я сделал следующее, он не смог найти функции в librt:

gcc -std=gnu99 -lrt -o prog prog.c

Тем не менее, это работает с другими библиотеками.Я обнаружил проблему при попытке использовать простой Makefile.сделать фактически скомпилированный prog.c без симпатии (используя флаг -c) и затем выполнить связывание.

Это Makefile:

CC = gcc

CFLAGS = -std=gnu99

LIBS= -lrt

LDFLAGS := -lrt


prog: prog.o

        $(CC) -o prog prog.c -lrt -std=gnu99

Вывод, который я получу при вводе make,be:

gcc -std=gnu99   -c -o prog.o prog.c
gcc -lrt  prog.o   -o prog
prog.o: In function `main':
prog.c:(.text+0xe6): undefined reference to `clock_gettime'
prog.c:(.text+0x2fc): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make: *** [buff] Error 1

Теперь я создал Make-файл, который помещает ссылку в конец строки gcc, однако я озадачен, почему он не работает, если флаг ссылки находится в начале.

Буду признателен, если кто-нибудь сможет мне это объяснить.Спасибо.

Ответы [ 2 ]

22 голосов
/ 23 февраля 2012

Когда компоновщик обрабатывает каждый модуль (будь то библиотека или объектный файл), он пытается разрешить каждый неопределенный символ, одновременно добавляя в свой список неопределенных символов. Когда он достигает конца списка модулей, он либо разрешает все неопределенные символы и успешно, либо сообщает о неопределенных символах.

В вашем случае, когда он обрабатывал librt, у него не было неопределенных символов. Процесс обработки привел к тому, что clock_gettime был неопределенным символом. gcc не вернется и не найдет неопределенные символы в librt.

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

Надеюсь, это поможет.

14 голосов
/ 23 февраля 2012

Из документации ld (компоновщик GNU) (http://sourceware.org/binutils/docs/ld/Options.html#Options):

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

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

...