Зачем создавать .a файл из .o для статического связывания?
Рассмотрим этот код:
one.c:
#include <stdio.h>
int one() {
printf("one!\n");
return 1;
}
two.c:
#include <stdio.h>
int two() {
printf("two!\n");
return 2;
}
prog.c
#include <stdio.h>
int one();
int two();
int main(int argc, char *argv[])
{
one();
two();
return 0;
}
Я хочу связать эти программы вместе. Поэтому я делаю это:
gcc -c -o one.o one.c
gcc -c -o two.o two.c
gcc -o a.out prog.c one.o two.o
Это работает отлично.
Или я мог бы создать статическую библиотеку:
ar rcs libone.a one.o
ar rcs libtwo.a two.o
gcc prog.c libone.a libtwo.a
gcc -L. prog.c -lone -ltwo
Итак, мой вопрос: зачем мне использовать вторую версию - ту, где я создал ".a" файлы, вместо того, чтобы связывать мои ".o" файлы? Оба они кажутся статически связанными, так есть ли преимущество или архитектурная разница в одном против другого?
Ответы
Ответ 1
Обычно библиотеки представляют собой коллекции объектных файлов, которые могут использоваться в нескольких программах.
В вашем примере нет преимущества, но вы могли бы сделать:
ar rcs liboneandtwo.a one.o two.o
Затем связь вашей программы становится проще:
gcc -L. prog.c -loneandtwo
Это действительно вопрос упаковки. У вас есть набор объектных файлов, которые, естественно, образуют набор связанных функций, которые могут быть повторно использованы в нескольких программах? Если это так, то они могут быть заведомо заархивированы в статическую библиотеку, иначе, вероятно, нет никакого преимущества.
На заключительном этапе ссылки есть одно важное различие. Любые файлы объектов, которые вы связали, будут включены в окончательную программу. Файлы объектов, которые находятся в библиотеках, включаются только в том случае, если они помогают разрешать любые символы undefined в других объектных файлах. Если они этого не сделают, они не будут связаны с окончательным исполняемым файлом.
Ответ 2
Разница была бы в размере исполняемого файла, хотя, возможно, и не для вашего примера.
При связывании с библиотекой включаются только биты, используемые вашим исполняемым файлом. При связывании объектного файла вы берете все это.
Например, если ваш исполняемый файл должен включать каждую математическую функцию в математическую библиотеку, когда вы ее используете, она будет намного больше, чем нужно, и содержать много неиспользуемого кода.
Интересно сравнить это с моделью динамической компоновки Windows. Там ОС должна загружать все DLL (динамически связанные библиотеки) полностью, что использует ваш исполняемый файл, что может привести к раздуванию в ОЗУ. Преимущество такой модели заключается в том, что ваш исполняемый файл сам по себе меньше, а связанные Dll могут уже находиться в памяти, используемой каким-либо другим исполняемым файлом, поэтому их не нужно снова загружать.
В статической привязке функции библиотеки загружаются отдельно для каждого исполняемого файла.
Ответ 3
Технически результат точно такой же. Обычно вы создаете библиотеки для служебных функций, поэтому вместо того, чтобы кормить компоновщик с десятками объектных файлов, вам просто нужно связать библиотеку.
BTW, совершенно не имеет смысла создавать .a файл, содержащий только один файл .o.
Ответ 4
Вы можете поместить коллекцию файлов в архив (.a) для последующего повторного использования. Хорошей иллюстрацией является стандартная библиотека.
Иногда имеет смысл организовать большие проекты в библиотеках.
Ответ 5
Основное преимущество заключается в том, когда вы должны ссылаться, вы можете просто указать одну библиотеку вместо всех отдельных объектных файлов. Также существует небольшое преимущество в управлении файлами, когда вы сталкиваетесь с одной библиотекой, а не с кучей объектных файлов. В свое время это также дало значительную экономию дискового пространства, но текущие цены на жесткий диск делают это менее важным.
Ответ 6
Всякий раз, когда меня задают этот вопрос (по freshers в моей команде), "почему (или иногда даже" что есть ").a?", я использую ниже ответ, который использует .zip как аналог.
"dotAy похож на zip файл всех dotOh, которые вы бы хотели связать, создавая exe/lib. Экономия на диске, плюс не нужно вводить имена всех задействованных dotOhs.
до сих пор это, казалось, помогло им понять.;)