Зачем создавать .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.

до сих пор это, казалось, помогло им понять.;)