gcc что это такое

Gcc что это такое

Что такое gcc и g++? Если задать этот вопрос людям, которые хотя бы отдаленно знакомы с Linux, то наверняка можно получить следующий ответ: «gcc — это компилятор языка Си, а g++ — компилятор С++». В каком-то смысле это будет правильный ответ. А если этим же людям задать другой вопрос: «А вы знаете, что на самом деле не существует компилятора g++, а gcc — это не Си-компилятор?» Бьюсь об заклад, что в 99% случаев можно услышать в ответ обвинения в ламерстве, дебилизме, параличе мозга, врожденной болезнью Дауна и пр. Ты тоже входишь в эти 99%? Тогда читай ниже.

Несмотря на то, что на момент написания этой статьи уже появилась версия GCC 3.3.2, речь однако пойдет о версии 2.96. Именно эта версия установлена на моем стареньком Red Hat 7.1 и меня совершенно не втыкает выкачивать около 30 МБ (если не ошибаюсь, именно столько весит архив GCC 3.3.2), т. к. 2.96 меня пока что полностью устраивает. Я просмотрел список изменений и дополнений, прошедших с версии 2.96 и не заметил ни чего существенного, чтобы могло бы повлиять на ход этой статьи. Но в качестве домашнего задания, я оставляю тебе проверить все сказанное здесь для других версий компилятора и сообщить о результатах мне.

Подопытная крыса

Создадим простейшую тестовую программку на С++ и сохраним ее под именем hello.cpp:

Выполним сначала компиляцию с помощью g++:

Все проходит без ошибок, в текущей директории образуется выполняемый файл hello. Теперь попробуем произвести компиляцию этой же программы с помощью gcc:

Компиляция не проходит, на экран вываливаются ошибки вроде тех, что показаны на скриншоте (см. рис. 1).

gcc что это такое. Смотреть фото gcc что это такое. Смотреть картинку gcc что это такое. Картинка про gcc что это такое. Фото gcc что это такое

Рис.1. gcc отказывается компилить CPP-программу

Между тем gcc отлично справляется с любой Си-прогой. Так, значит, gcc не понимает программ на C++, а только Си-программы? Значит g++ и gcc два разных компилятора? Зачем же я тогда завел весь этот разговор? Подожди, подожди, давай обратимся к man.

Если ты не умеешь читать

Откроем man g++. Прямо с первых строк, в разделе описания читаем (я привожу сразу перевод):
«Компиляторы Си и Си++ объединены; g++ — это скрипт, который вызывает gcc с опциями языка С++. gcc пропускает входные файлы через одну или более из четырех стадий: препроцессирование, компиляцию, ассемблирование и линковку».

Поэтому обратимся лучше к самому свежему мануалу, а именно к «GCC 3.3.2 Manual», который можно найти на официальном сайте http://gcc.gnu.org/onlinedocs/. Вот что там можно прочитать (далее перевод):
«Несколько версий компиляторов объединены (C, C++, Objective-C, Ada, Fortran, Java). Вот почему мы используем название «GNU Compiler Collection». GCC может компилировать программы написанные на любом из этих языков. Ada, Fortran, Java описаны в отдельных мануалах.

Когда ссылаются на C++ компиляцию, обычно называют компилятор «G++». Поскольку есть только один компилятор, будет точным называть его «GCC» вне зависимости от языка; однако термин «G++» более полезен, когда ударение стоит на компиляции С++ программ».

Если ты так ничего и не понял

Как же так, мы ведь вначале статьи на эксперименте убедились, что gcc и g++ работают по-разному, а в мануале сказано, что есть только один компилятор GCC? Давай не будем делать поспешных выводов, а лучше снова обратимся к man. В разделе FILES обоих манов («man gcc» и «man g++») мы обнаружим интересную деталь (см. рис. 2), оказывается, что для компиляции Си-программ используется компилятор cc1, а для программ на C++ как gcc, так и g++ вызывают cc1plus! Так вот они настоящие компиляторы! Там же мы увидим имена файлов препроцессора, линкера и пр., причем все эти файлы являются составной частью пакета GCC! Значит, gcc и g++ просто вызывают указанные файлы, выполняя поочередно все этапы создания бинарника (препроцессирование, компиляцию, ассемблирование и линковку)!

gcc что это такое. Смотреть фото gcc что это такое. Смотреть картинку gcc что это такое. Картинка про gcc что это такое. Фото gcc что это такое

Рис.2. Вот они настоящие компиляторы!

Сравнение работы gcc и g++

Хорошо, мы убедились, что gcc и g++ одинаково смогли справиться с задачей, но может быть на внутреннем уровне они отличаются? Может быть процесс создания исполняемого файла в них идет по-разному, а ведь это в свою очередь может свидетельствовать о том, что это совершенно независимые компиляторы? Что ж попытаемся выяснить и это. Естественно мы не будем рыться в исходниках GCC, т. к. компилятор это не программка в сотню строк и одной бутылочки, чтобы разобраться, явно не хватит. Для того чтобы увидеть, что происходит в действительности, существует замечательный ключик –v. Результат компиляции с использованием этого ключа показан на рисунке 3.

gcc что это такое. Смотреть фото gcc что это такое. Смотреть картинку gcc что это такое. Картинка про gcc что это такое. Фото gcc что это такое

Рис.3. Результат компиляции с опцией –v

Чтобы сравнить выходные данные gcc и g++, я сохранил результаты вывода в текстовые файлы:

gcc –v –o hello hello.cpp 2>tmp_gcc.txt

И воспользовавшись утилитой diff, выяснил, что выходные данные оказались практически одинаковыми. Отличие заключается лишь в именах темповых файлов, например в одном случае: /tmp/cczEKZcb.ii, а в другом: /tmp/ccdVfS2M.ii — но это само собой разумеющиеся отличия! Следовательно, процесс создания исполняемого файла на «внутреннем» уровне в обоих случаях протекает совершенно одинаково. Давай рассмотрим этот процесс в деталях.

gcc и g++ по косточкам

Далее я привожу пошаговый разбор той информации, которую выводят gcc и g++ с использованием ключа –v (tmp_gcc.txt или tmp_g++):


Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs

gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)

Эти строки говорят о том, что происходит чтение файла specs, на основании которого будет строиться дальнейшая компиляция, а также показывается номер версии компилятора gcc. Еще раз отмечаю: gcc и g++ выводят совершенно идентичную информацию!

Первым вызывается препроцессор cpp0, он заменяет в программе комментарии пробелами, вставляет файлы #include, преобразует директивы #define, #ifdef, #undef и пр. В результате препроцессирования образуется темповый файл /tmp/cczEKZcb.ii, необходимый для дальнейшей компиляции.


ignoring nonexistent directory «/usr/local/include»

ignoring nonexistent directory «/usr/i386-redhat-linux/include»

#include «. » search starts here:

#include search starts here:

End of search list.

Теперь в работу вступает компилятор С++: cc1plus, который на основании файла /tmp/cczEKZcb.ii, полученного на этапе препроцессирования, создает исходник на ассемблере /tmp/ccw4l1Ud.s.

Далее наступает этап ассемблирования, для чего вызывается стандартный ассемблер as, который создает объектный файл /tmp/cc5T4w7y.o.

Завершается все линковкой. Линковщик collect2 объединяет объектные файлы с необходимыми разделяемыми библиотеками и создает исполняемый файл. Ключ –L показывает, в каких директориях происходит поиск библиотек.

Ну и какие выводы?

История GCC

Первая версия gcc была создана основателем «Free Software Foundation» Ричардом Столманом в 1987 году. Первоначально аббревиатура GCC означала «GNU C Compiler», т. к. gcc тогда компилировал только Си-программы. Теперь GCC расшифровывается, как «GNU Compiler Collection», т. к. включает в себя множество компиляторов: C, C++, Objective-C, Ada, Java и пр. Огромный вклад в развитие GCC внесла компания Cygnus под руководством Майкла Тиманна (Michael Tiemann). В 1997 между Cygnus и «Free Software Foundation», из-за некоторых разногласий произошел раскол, и Cygnus создала свою версию компилятора EGCS. Однако в 1999 году конфликт был исчерпан и проект EGCS слился с GCC. Последнюю версию компилятора GCC всегда можно найти на официальном FTP-сервере: ftp://ftp.gnu.org/gnu/gcc/.

Особенность G++

В статье я не сказал об одной мелкой детали. G++ всегда по умолчанию линкует библиотеку математических подпрограмм libm (по крайней мере, версия GCC 2.96). По этой причине программы скомпилированные g++ получаются всегда немного большего размера, чем те же программы полученные с помощью gcc. Если при компиляции с помощью gcc в командной строке указать флаг –lm будет получен тот же эффект.

Источник

Национальная библиотека им. Н. Э. Баумана
Bauman National Library

Персональные инструменты

GCC (GNU Compiler Collection)

GNU Compiler Collection (обычно используется сокращение GCC) — набор компиляторов для различных языков программирования, разработанный в рамках проекта GNU(является рекурсивным акронимом, расшифровывающимся, как «GNU is Not Unix»). GCC является свободным программным обеспечением, распространяется фондом свободного программного обеспечения (FSF) на условиях GNU GPL и GNU LGPL и является ключевым компонентом GNU toolchain. Он используется как стандартный компилятор для свободных UNIX-подобных операционных систем.

Изначально названный GNU C Compiler был выпущен в 1987 году и поддерживал только язык Си. Позднее GCC был расширен для компиляции исходных кодов на таких языках программирования, как C++, Objective-C, Java, Fortran, Ada и Go.

С версии 4.2.2 GCC перешёл на лицензию GPLv3.

Будучи официальным компилятором системы GNU, GCC также является главным компилятором для сборки ряда других операционных систем; среди них — различные варианты Linux и BSD, а также ReactOS, Mac OS X, OpenSolaris, NeXTSTEP, BeOS и Haiku.

GCC часто выбирается для разработки программного обеспечения, которое должно работать на большом числе различных аппаратных платформ. Различия между «родными» для каждой из аппаратных платформ компиляторами приводят к трудностям при разработке кода, который бы корректно компилировался разными компиляторами, а кроме того, при использовании различных компиляторов сильно усложняются сборочные скрипты, которые должны собирать ПО для всех аппаратных платформ. При использовании GCC для компиляции кода под разные платформы будет использован один и тот же синтаксический анализатор. Поэтому если удалось собрать программу для одной из целевых платформ, то велика вероятность, что программа нормально соберётся и для других платформ.

Содержание

История

В настоящее время GCC поддерживается группой программистов со всего мира. GCC является лидером по количеству процессоров и операционных систем, которые он поддерживает.

Лицензия

Языки

C версии 4.6 стандартный компилятор включает в себя front-end’ы для языков:

Fortran front-end был G77 до версии 4.0, которая поддерживает только FORTRAN 77. В новых версиях G77 отбрасывается в пользу нового GNU Fortran front-end (сохранив большую часть расширений языка G77), что поддерживает Fortran 95 и большинство частей Fortran 2003 и Fortran 2008, а также front-end для CHILL был понижен из-за отсутствия технического обслуживания.

Архитектуры

Список поддерживаемых GCC (для версии 4.3) процессоров включает в себя:

Менее известные процессоры, поддерживаемые в стандартном релизе:

Дополнительные типы архитектур и процессоров, которые поддерживаются версиями GCC, но поддержкой которых занимаются сторонние организации (не Фонд свободного программного обеспечения):

Компилятор GCJ Java может выбрать либо родной язык архитектуры машины или Java Virtual Machine Java bytecode.

Разработка

Текущая стабильная версия GCC 6.2 была выпущена 22 августа 2016 г. [5]

Начиная с версии 4.8, GCC реализован в C ++. [6]

Источник

GNU Compiler Collection, первые шаги

Эта заметка призвана на простых примерах познакомить начинающего nix-разработчика с инструментами GNU, в частности с компилятором GCC.

С его помощью мы и создадим простейшую программу. По большому счету все, как обычно. Заводим специальную папку, в которой будет размещаться проект.
Создаем в ней файл с именем: hello.c
Открываем файл в любом текстовом редакторе и пишем простейший код:

#include
int main(void)
<
printf(«Hello world!»);
return(0);
>

Сохраняем файл и выполняем команду: gcc hello.c

В созданной нами папке появился новый файл — a.out, это название присваивается по умолчанию, если специально не задано другого.

И радуемся в связи с первой написанной программой в линуксе!

Идем далее. При запуске исполняемого файла, если мы укажем только его название, система будет искать его в каталогах /usr/bin и /usr/local/bin, и, естественно, не найдет. Первый из них предназначен для размещения стабильных версий программ, как правило, входящих в дистрибутив Linux. Второй – для программ, устанавливаемых самим пользователем (за стабильность которых никто не ручается). По умолчанию, при сборке программы, устанавливаются в каталог /usr/local/bin.

Флаги используемые при компиляции

Название получаемого файла такое же, но компилятор изменяет расширение .c на .o (но указать можно и вручную).

Флаг -x используем, если создаётся объектный файл из исходника, уже обработанного препроцессором (например такого, какой мы получили выше), мы должны обязательно указать явно, что компилируемый файл является файлом исходного кода, обработанный препроцессором, и имеющий теги препроцессора. В противном случае он будет обрабатываться, как обычный файл C++, без учёта тегов препроцессора, а значит связь с объявленными функциями не будет устанавливаться.

Для чего нужна вся эта возня с промежуточными этапами?
Программы редко состоят из одного файла. Как правило исходных файлов несколько, и они объединены в проект. И в некоторых исключительных случаях программу приходится компоновать из нескольких частей, написанных, возможно, на разных языках. В этом случае приходится запускать компиляторы разных языков, чтобы каждый получил объектный файл из своего исходника, а затем уже эти полученные объектные файлы компоновать в исполняемую программу.

Источник

Незамысловатый блог

03.12.2010

О GCC, компиляции и библиотеках

Основы

Перейдём к практике. Напишем, откомпилируем и исполним какую-нибудь незамысловатую программу. Не будем оригинальничать, в качестве исходного файла примера программы на языке C сотворим файл с вот таким содержимым:

printf( «Hello World \n » );

Теперь в каталоге c hello.c отдадим команду:

Через несколько долей секунды в каталоге появиться файл a.out :

Это и есть готовый исполняемый файл нашей программы. По умолчанию gcc присваивает выходному исполняемому файлу имя a.out (когда-то очень давно это имя означало assembler output).

Запустим получившийся программный продукт:

Утилита file выводит информацию о типе (с точки зрения системы) переданного в коммандной строке файла, для некоторых типов файлов выводит всякие дополнительные сведения касающиеся содержимого файла.

$ file hello.c
hello.c: ASCII C program text
$ file annotation.doc
annotation.doc: CDF V2 Document, Little Endian, Os: Windows, Version 5.1, Code page: 1251, Author: MIH, Template: Normal.dot, Last Saved By: MIH, Revision Number: 83, Name of Creating Application: Microsoft Office Word, Total Editing Time: 09:37:00, Last Printed: Thu Jan 22 07:31:00 2009, Create Time/Date: Mon Jan 12 07:36:00 2009, Last Saved Time/Date: Thu Jan 22 07:34:00 2009, Number of Pages: 1, Number of Words: 3094, Number of Characters: 17637, Security: 0

Вот собственно и всё, что требуется от пользователя для успешного применения gcc 🙂

Процесс компиляции можно разбить на 4 основных этапа: обработка препроцессором, собственно компиляция, ассемблирование, линковка (связывание).

Опции gcc позволяют прервать процесс на любом из этих этапов.

После препроцессинга наступает очередь компиляции. Компилятор преобразует исходный текст программы на языке высокого уровня в код на языке ассемблера.

Получить исполняемый код разумеется можно и из файла hello.s :

Если полученный объектный файл hello.o передать линковщику, последний вычислит адреса ссылок, добавит код запуска и завершения программы, код вызова библиотечных функций и в результате мы будем обладать готовым исполняемым файлом программы.

Ну вот пожалуй о компиляции и все. Теперь коснемся некоторых, на мой взгляд важных, опций gcc.

Компиляция с уровнем оптимизации по умолчанию:

Компиляция с максимальным уровнем оптимизации:

Увы, для реальных проектов разница в производительности при различных уровнях оптимизации практически не заметна.

Об опциях передаваемых линковщику будет сказано ниже.

Собственно о компиляции все. Далее поговорим о раздельной компиляции и создании библиотек.

c c-header c-cpp-output

objective-c objective-c-header objective-c-cpp-output

objective-c++ objective-c++-header objective-c++-cpp-output

Назначение аргументов должно быть понятно из их написания (здесь cpp не имеет ни какого отношения к C++, это файл исходного кода предварительно обработанный препроцессором). Проверим:

Раздельная компиляция

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

2. Позволяет сократить время повторной компиляции проекта. Если изменения внесены в один файл нет смысла перекомпилировать весь проект, достаточно заново откомпилировать только этот изменённый файл.

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

4. Без раздельной компиляции не существовало бы библиотек. Посредством библиотек реализовано повторное использование и распространение кода на C/C++, причем кода бинарного, что позволяет с одной стороны предоставить разработчикам простой механизм включения его в свои программы, с другой стороны скрыть от них конкретные детали реализации. Работая над проектом, всегда стоит задумываться над тем, а не понадобиться что-либо из уже сделанного когда-нибудь в будущем? Может стоит заранее выделить и оформить часть кода как библиотеку? По моему, такой подход, существенно упрощает жизнь и экономит массу времени.

GCC, разумеется, поддерживает раздельную компиляцию, причем не требует от пользователя каких либо специальных указаний. В общем все очень просто.

Вот практический пример (правда весьма и весьма условный).

Набор файлов исходного кода:

#include «first.h»
#include «second.h»

printf( «Main function. \n » );

printf( «First function. \n » );

printf( «Second function. \n » );

В общем имеем вот что:

Все это хозяйство можно скомпилировать в одну команду:

Только это не даст нам практически ни каких бонусов, ну за исключением более структурированного и удобочитаемого кода, разнесённого по нескольким файлам. Все перечисленные выше преимущества появятся в случае такого подхода к компиляции:

Что мы сделали? Из каждого исходного файла (компилируя с опцией -c ) получили объектный файл. Затем объектные файлы слинковали в итоговый исполняемый. Разумеется команд gcc стало больше, но в ручную ни кто проекты не собирает, для этого есть утилиты сборщики (самая популярная make). При использовании утилит сборщиков и проявятся все из перечисленных выше преимуществ раздельной компиляции.

Просмотреть таблицу символов можно с помощью утилиты nm.

Таблица символов прописывается не только в объектный, но и в исполняемый файл:

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

Библиотеки

С точки зрения операционной системы и прикладного программного обеспечения библиотеки бывают статическими и разделяемыми (динамическими).

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

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

Парадигма разделяемых библиотек предоставляет три существенных преимущества:

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

2. Код разделяемой библиотеки используемый несколькими приложениями храниться в оперативной памяти в одном экземпляре (на самом деле не всё так просто. ), в результате сокращается потребность системы в доступной оперативной памяти.

3. Отпадает необходимость пересобирать каждый исполняемый файл в случае внесения изменений в код общей для них библиотеки. Изменения и исправления кода динамической библиотеки автоматически отразятся на каждой из использующих её программ.

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

Теперь немного практики.

В начале создадим и используем статическую библиотеку.

Ну а теперь, введем следующую последовательность команд:

Для создания индекса архива существует специальная утилита ranlib. Библиотеку libhello.a можно было сотворить и так:

Впрочем библиотека будет прекрасно работать и без индекса архива.

Теперь воспользуемся нашей библиотекой:

Ну теперь комментарии. Появились две новые опции gcc:

Здесь необходимо сделать небольшое замечание. Дело в том, что для ряда опций gcc важен порядок их следования в командной строке. Так линковщик ищет код, соответствующий указанным в таблице символов файла именам в библиотеках, перечисленных в командной строке после имени этого файла. Содержимое библиотек перечисленных до имени файла линковщик игнорирует:

Такая особенность поведения gcc обусловлена желанием разработчиков предоставить пользователю возможность по разному комбинировать файлы с библиотеками, использовать пересекающие имена. На мой взгляд, если возможно, лучше этим не заморачиваться. В общем подключаемые библиотеки необходимо перечислять после имени ссылающегося на них файла.

Существует альтернативный способ указания местоположения библиотек в системе. В зависимости от дистрибутива, переменная окружения LD_LIBRARY_PATH или LIBRARY_PATH может хранить список разделенных знаком двоеточия каталогов, в которых линковщик должен искать библиотеки. Как правило, по умолчанию эта переменная вообще не определена, но ни чего не мешает её создать:

Теперь создадим и используем библиотеку динамическую.

Набор исходных файлов остается без изменения. Вводим команды, смотрим что получилось, читаем комментарии:

Что получили в результате?

gcc что это такое. Смотреть фото gcc что это такое. Смотреть картинку gcc что это такое. Картинка про gcc что это такое. Фото gcc что это такое

Убедимся, что заданная строка soname действительно прописана в файле нашей библиотеки. Воспользуемся мега утилитой objdump с опцией -p :

В приведенном примере создания библиотеки мы неотступно следовали принципам раздельной компиляции. Разумеется скомпилировать библиотеку можно было бы и вот так, одним вызовом gcc:

Теперь попытаемся воспользоваться получившейся библиотекой:

Линковщик ругается. Вспоминаем, что было сказано выше о символических ссылках. Создаем libhello.so и повторяем попытку:

Теперь все довольны. Запускаем созданный бинарник:

Создаем соответствующую ссылку и повторно запускаем приложение:

Заработало. Теперь комментарии по новым опциям gcc.

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

Узнать какие разделяемые библиотеки необходимы приложению можно и с помощью утилиты ldd:

В выводе ldd для каждой требуемой библиотеки указывается её soname и полный путь к файлу библиотеки, определённый в соответствии с настройками системы.

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

В соответствии с соглашениями FHS (Filesystem Hierarchy Standard) в системе должны быть два (как минимум) каталога для хранения файлов библиотек:

Загрузчик по умолчанию будет искать файлы библиотек в этих каталогах.

Убедимся в сказанном:

Ну и в конце поговорим о том как уживаются вместе статические и динамические версии библиотек. В чем собственно вопрос? Выше, когда обсуждались принятые имена и расположение файлов библиотек было сказано, что файлы статической и динамической версий библиотеки хранятся в одном и том же каталоге. Как же gcc узнает какой тип библиотеки мы хотим использовать? По умолчанию предпочтение отдается динамической библиотеки. Если линковщик находит файл динамической библиотеки, он не задумываясь цепляет его к исполняемому файлу программы:

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

Так как размер кода библиотеки libhello ничтожен,

размер получившегося исполняемого файла практически не отличается от размера файла созданного с использованием динамической линковки.

Ну вот пожалуй и все. Большое спасибо всем, кто закончил чтение на этом месте.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *