2016-04-21 3 views
0

Всюду я ищу то, что на самом деле делает линкер (помимо перемещения, которое некоторые, кажется, ставят под «загрузкой»), люди приводят примеры двух (скажем) модулей C, которые вызывают функции друг от друга.Предварительная обработка по сравнению с привязкой

Насколько я понимаю, к этому следует позаботиться о предварительной обработке (#include и т. Д.). Я могу понять, что если я хочу собрать два модуля в разное время, мне нужно будет связать их позже. Но когда я использую say gcc, он напрямую выводит исполняемый файл, поэтому в этом контексте я действительно не вижу точки привязки, кроме случаев, когда препроцессор (который будет рекурсивным, я думаю) окончательным удаляет объектный код.

Примечание: Я имею в виду статическую ссылку здесь. Я могу понять, когда дело доходит до динамической компоновки.

+1

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

+1

#include используется для включения объявлений, а не фактического кода. Обычно заголовочный файл не содержит исполняемого кода (по крайней мере, на C). – rici

+0

'gcc' - это инструмент-драйвер, который вызывает компилятор C (' cc1') для компиляции и вызывает компоновщик ('ld') для связывания. Вот почему вы можете представить , что он «напрямую выводит исполняемый файл» без ссылки. Это не так. Вы можете указать 'gcc' * not * для вызова компоновщика, передав ему опцию' -c' . Попытайтесь создать программу таким образом. –

ответ

1

gcc использует множество инструментов для создания исполняемого файла, один из них - компилятор, а также компоновщик, препроцессор и т. Д., Чтобы увидеть, что он на самом деле делает для него -v. Если вы хотите увидеть промежуточные файлы используют -save-temps то есть, как только вы создали файлы ниже попробовать это ...

gcc-5 -save-temps -v -std=c11 -Wall -pedantic-errors main.c foo.c 

Если посмотреть в каталоге вы увидите несколько дополнительных файлов ...

a.out // Executable when no name is specified 
foo.c // original foo.c 
foo.h // original foo.h 
foo.i // Preprocessed ouput of foo.c and foo.h 
foo.o // foo Object file 
foo.s // foo assembler 
main.c // original main.c 
main.i // main preprocessed 
main.o // main object file 
main.s // main assembler 

Если вы посмотрите в main.i вы заметите, что он содержит этот

# 1 "foo.h" 1 


int foo(int i); 

, но он не знает, что на самом деле делает функция Foo. Это все в foo.i. Это также означает, что при создании объектных файлов main.o знает, что ему нужна функция foo. Соединительный символ foo в main.o с foo в foo.o - это то, что делает компоновщик.

Вот пример, создайте следующие три файла

foo.h

#ifndef FOO_H 
#define FOO_H 
int foo(int i); 
#endif 

foo.c

#include "foo.h" 
int foo(int i) { 
    return i - 1729; 
} 

main.c

#include "foo.h" 
#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 
int main(void) { 
    printf("%d\n", foo(1)); 
    return 0; 
} 

Создать их Объектные файлы, т.е. не исполняемые следующим образом, обратите внимание, я добавил многословные флаги это ..

gcc-5 -v -std=c11 -Wall -pedantic-errors main.c foo.c -c 

Если вы использовали -o флаг вы увидите реальную команду компоновщика, НКУ чтобы связать объекты с исполняемым файлом, т.е.

На этом этапе вы найдете в своем каталоге два объектных файла. Вы можете создать исполняемый файл, используя ld, следующим образом (обратите внимание, что это специфичный для Mac, используйте вывод gcc -v, чтобы найти правильную команду для вашего компьютера).

ld -dynamic -arch x86_64 -macosx_version_min 10.11.3 -lSystem main.o foo.o -o fooer 
Смежные вопросы