Почему флаг компоновщика библиотеки иногда должен идти в конце с помощью GCC?
Я пишу небольшую программу на C, которая использует librt. Я очень удивлен тем, что программа не будет компилироваться, если я поставлю флаг ссылки в начале, а не в конце:
На данный момент для компиляции программы я делаю:
gcc -o prog prog.c -lrt -std=gnu99
Если бы я должен был сделать следующее, он не сможет найти функции в librt:
gcc -std=gnu99 -lrt -o prog prog.c
Тем не менее, это работает с другими библиотеками. Я нашел проблему при попытке использовать простой Makefile. make фактически скомпилировал 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, будет:
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
Теперь я создал Makefile, который помещает ссылку в конец строки gcc, однако я озадачен тем, почему он не работает, если флаг привязки находится в начале.
Буду признателен, если кто-нибудь сможет мне это объяснить. Спасибо.
Ответы
Ответ 1
Поскольку компоновщик обрабатывает каждый модуль (будь то библиотека или объектный файл), он пытается разрешить каждый символ undefined, одновременно добавляя к нему список символов undefined. Когда он попадает в список модулей, он либо разрешил все символы undefined, либо успешно, либо сообщает undefined символы.
В вашем случае, когда он обрабатывал librt, у него не было символов undefined. Обработка proc привела к тому, что clock_gettime является символом undefined. gcc не будет возвращаться и смотреть в librt для символов undefined.
По этой причине вы всегда должны иметь свой код, а затем ваши библиотеки, а затем библиотеки, предоставленные платформой.
Надеюсь, что это поможет.
Ответ 2
Из документации ld
(GNU linker) (http://sourceware.org/binutils/docs/ld/Options.html#Options):
Линкеров будет искать архив только один раз, в том месте, где он указан в командной строке. Если архив определяет символ undefined в некотором объекте, который появился перед архивом в командной строке, компоновщик будет содержать файлы из архива. Однако символ undefined в объекте, появляющемся позже в командной строке, не заставит компоновщик снова искать архив.
Итак, если вы укажете библиотеку слишком рано, компоновщик сканирует ее, но не найдет ничего интересного. Затем компоновщик переходит к объектному файлу, создаваемому компилятором, и находит ссылки, которые необходимо разрешить, но он уже просмотрел библиотеку и больше не будет смотреть туда.