Коллекция компиляторов GNU - GNU Compiler Collection

Коллекция компиляторов GNU
Коллекция компиляторов GNU logo.svg
GCC 10.2 Коллекция компиляторов GNU self-compilation.png
Снимок экрана GCC 10.2, компилирующего собственный исходный код
Автор (ы) оригинала Ричард Столмен
Разработчики) Проект GNU
Первый выпуск 23 мая 1987 г . ; 34 года назад ( 1987-05-23 )
Стабильный выпуск
11.2 / 27 июля 2021 г . ; 2 месяца назад ( 2021-07-27 )
Предварительный выпуск
11.2.0-RC / 21 июля 2021 г . ; 2 месяца назад ( 2021-07-21 )
Репозиторий
Написано в C , C ++
Операционная система Кроссплатформенность
Платформа GNU и многие другие
Размер ~ 15 миллионов LOC
Тип Компилятор
Лицензия GPLv3 + с исключением библиотеки времени выполнения GCC
Веб-сайт gcc .gnu .org

GNU Compiler Collection ( GCC ) является оптимизирующий компилятор , вырабатываемые Проект GNU поддерживает различные языки программирования , аппаратных архитектур и операционных систем . Фонд свободного программного обеспечения (FSF) распространяет GCC как бесплатное программное обеспечение под Стандартной общественной лицензией GNU (GNU GPL). GCC - ключевой компонент инструментальной цепочки GNU и стандартный компилятор для большинства проектов, связанных с GNU и ядром Linux . GCC, насчитывающий примерно 15 миллионов строк кода в 2019 году, является одной из крупнейших существующих бесплатных программ. Он сыграл важную роль в росте свободного программного обеспечения как инструмент и как пример.

Когда он был впервые выпущен в 1987 году Ричард Столлман , GCC 1.0 был назван GNU C Compiler , так как он только обработал язык программирования Си . В декабре того же года он был расширен для компиляции C ++ . Внешние интерфейсы были позже разработаны для Objective-C , Objective-C ++ , Fortran , Ada , D и Go , среди других. Спецификации OpenMP и OpenACC также поддерживаются компиляторами C и C ++.

GCC был перенесен на большее количество платформ и архитектур наборов команд, чем любой другой компилятор, и широко используется в качестве инструмента для разработки как бесплатного, так и проприетарного программного обеспечения . GCC также доступен для многих встраиваемых систем , включая чипы на базе ARM и Power ISA .

Помимо того , что GCC является официальным компилятором операционной системы GNU , он был принят в качестве стандартного компилятора во многих других современных Unix-подобных компьютерных операционных системах , включая большинство дистрибутивов Linux . Большинство операционных систем семейства BSD также перешли на GCC вскоре после его выпуска, хотя с тех пор FreeBSD , OpenBSD и Apple macOS перешли на компилятор Clang , в основном по причинам лицензирования. GCC также может компилировать код для Windows , Android , iOS , Solaris , HP-UX , AIX и DOS.

История

В конце 1983 года в попытке используется при загрузке в GNU операционной системы, Ричард Столлман спросил Таненбаум , автор Amsterdam Compiler Kit (также известный как Свободный университет Compiler Kit ) для получения разрешения на использование этого программного обеспечения для GNU. Когда Таненбаум сообщил ему, что компилятор не является бесплатным и что свободен только университет, Столлман решил работать над другим компилятором. Его первоначальный план состоял в том, чтобы переписать существующий компилятор из Ливерморской национальной лаборатории Лоуренса с Pastel на C с некоторой помощью Лена Тауэра и других. Столлман написал новый интерфейс C для компилятора Livermore, но затем понял, что для этого требуются мегабайты стекового пространства, что невозможно в системе 68000 Unix с 64 КБ, и пришел к выводу, что ему придется написать новый компилятор с нуля. Ни один из кодов компилятора Pastel не попал в GCC, хотя Столлман действительно использовал написанный им интерфейс на C.

GCC впервые был выпущен 22 марта 1987 года, доступный по FTP из MIT . Столлман был указан как автор, но процитировал других за их вклад, в том числе Джека Дэвидсона и Кристофера Фрейзера за идею использования RTL в качестве промежуточного языка, Пола Рубина за написание большей части препроцессора и Леонарда Тауэра за «части парсера, RTL». генератор, определения RTL и описание машины Vax ". Компилятор GNU, описанный Питером Х. Салусом как «первый хит свободного программного обеспечения» , появился как раз в то время, когда Sun Microsystems отделяла свои инструменты разработки от своей операционной системы , продавая их отдельно по более высокой совокупной цене, чем предыдущий комплект, который заставили многих пользователей Sun купить или загрузить GCC вместо инструментов поставщика. В то время как Столлман считал GNU Emacs своим основным проектом, к 1990 году GCC поддерживал тринадцать компьютерных архитектур, превосходил по производительности компиляторы нескольких поставщиков и коммерчески использовался несколькими компаниями.

Вилка EGCS

Поскольку GCC был лицензирован под GPL, программисты, желающие работать в других направлениях - особенно те, которые пишут интерфейсы для языков, отличных от C, - могли свободно разрабатывать свою собственную вилку компилятора, при условии, что они соответствуют условиям GPL, включая ее требования по распространению исходного кода. код . Однако множественные форки оказались неэффективными и громоздкими, а сложность принятия работы официальным проектом GCC сильно расстраивала многих, поскольку в проекте стабильность была важнее новых функций. FSF так строго контролировал то, что было добавлено к официальной версии GCC 2.x (разрабатываемой с 1992 г.), что GCC использовался в качестве одного из примеров модели развития «кафедрального собора» в эссе Эрика С. Раймонда « Собор и здание». Базар .

В 1997 году группа разработчиков сформировала Experimental / Enhanced GNU Compiler System (EGCS), чтобы объединить несколько экспериментальных форков в один проект. Основой слияния послужил моментальный снимок разработки GCC (сделанный примерно в версии 2.7.2, а затем в версии 2.8.1). Слияния включены g77 (Fortran), PGCC ( P5 Pentium -Оптимизация GCC), многие C ++ улучшений, а также множество новых архитектур и операционных систем вариантов.

В то время как оба проекта внимательно следили за изменениями друг друга, разработка EGCS оказалась значительно более активной, настолько, что FSF официально остановила разработку своего компилятора GCC 2.x, одобрила EGCS в качестве официальной версии GCC и назначила проект EGCS в качестве GCC. сопровождающих в апреле 1999 года. С выпуском GCC 2.95 в июле 1999 года два проекта снова были объединены. С тех пор GCC поддерживается разнообразной группой программистов со всего мира под руководством руководящего комитета.

GCC 3 (2002) удалил интерфейс для CHILL из-за отсутствия поддержки.

До версии 4.0 интерфейс Fortran g77поддерживал только FORTRAN 77 , но позже был заменен новым интерфейсом GNU Fortran, который поддерживает Fortran 95, а также большую часть Fortran 2003 и Fortran 2008 .

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

Поддержка Cilk Plus существовала с GCC 5 до GCC 7.

GCC был перенесен на широкий спектр архитектур с набором команд и широко используется в качестве инструмента для разработки как бесплатного, так и проприетарного программного обеспечения . GCC также доступен для многих встраиваемых систем , включая Symbian (называемый gcce ), чипы на базе ARM и Power ISA . Компилятор может работать с широким спектром платформ, включая игровые консоли, такие как PlayStation 2 , Cell SPE для PlayStation 3 и Dreamcast . Он был перенесен на большее количество процессоров и операционных систем, чем любой другой компилятор.

Поддерживаемые языки

По состоянию на май 2021 года последняя версия GCC 11.1 включает интерфейсы для языков программирования C ( gcc), C ++ ( g++), Objective-C , Fortran ( gfortran), Ada ( GNAT ), Go ( gccgo) и D ( gdcначиная с версии 9.1) с в OpenMP и OpenACC расширения параллельного языка поддерживается , так как GCC 5.1. Версии до GCC 7 также поддерживали Java ( gcj), что позволяло компилировать Java в собственный машинный код.

Что касается поддержки языковых версий для C ++ и C, так как GCC 11.1 целью по умолчанию является gnu ++ 17 , надмножество C ++ 17 , и gnu11 , надмножество C11 , также доступна строгая стандартная поддержка. GCC также обеспечивает экспериментальную поддержку C ++ 20 и предстоящего C ++ 23 .

Сторонние интерфейсы существуют для многих языков, таких как Pascal ( gpc), Modula-2 , Modula-3 , PL / I и VHDL ( GHDL). Существует несколько экспериментальных веток для поддержки дополнительных языков, таких как компилятор GCC UPC для Unified Parallel C или Rust .

Дизайн

Обзор расширенного конвейера компиляции GCC, включая специализированные программы, такие как препроцессор , ассемблер и компоновщик .
GCC следует трехступенчатой ​​архитектуре, типичной для многоязычных и многопроцессорных компиляторов . Все программы дерева преобразуются в общее абстрактное представление на «средний конце», что позволяет оптимизация коды и двоичный код объекты генерации , которые будут общими для всех языков.

Внешний интерфейс GCC следует соглашениям Unix . Пользователи вызывают программу драйвера gccдля конкретного языка ( для C, g++для C ++ и т. Д.), Которая интерпретирует аргументы команды , вызывает фактический компилятор, запускает ассемблер на выходе, а затем, при необходимости, запускает компоновщик для создания полного исполняемого двоичного файла .

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

При необходимости они преобразуются во входное представление среднего конца, называемое ОБЩЕЙ формой; средний конец затем постепенно трансформирует программу в ее окончательную форму. К коду применяются оптимизации компилятора и методы статического анализа кода (такие как FORTIFY_SOURCE, директива компилятора, которая пытается обнаружить некоторые переполнения буфера ). Они работают с несколькими представлениями, в основном с архитектурно-независимым представлением GIMPLE и архитектурно-зависимым RTL- представлением. Наконец, машинный код создается с использованием зависящего от архитектуры сопоставления с образцом, первоначально основанного на алгоритме Джека Дэвидсона и Криса Фрейзера.

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

GCC использует множество стандартных инструментов в своей сборке, включая Perl , Flex , Bison и другие распространенные инструменты. Кроме того, в настоящее время для сборки требуется наличие трех дополнительных библиотек: GMP , MPC и MPFR .

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

В августе 2012 года руководящий комитет GCC объявил, что GCC теперь использует C ++ в качестве языка реализации. Это означает, что для сборки GCC из исходников требуется компилятор C ++, который понимает стандарт ISO / IEC C ++ 03 .

18 мая 2020 года GCC перешел от стандарта ISO / IEC C ++ 03 к стандарту ISO / IEC C ++ 11 (т.е. необходим для компиляции, начальной загрузки самого компилятора; однако по умолчанию он компилирует более поздние версии C ++).

Передние концы

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

Каждый интерфейс использует синтаксический анализатор для создания абстрактного синтаксического дерева данного исходного файла . Благодаря абстракции синтаксического дерева исходные файлы на любом из различных поддерживаемых языков могут обрабатываться одной и той же серверной частью . GCC начал использовать парсеры LALR, созданные с помощью Bison , но постепенно переключился на написанные вручную парсеры с рекурсивным спуском для C ++ в 2004 году и для C и Objective-C в 2006 году. С 2021 года все интерфейсы используют написанные вручную парсеры с рекурсивным спуском. .

До GCC 4.0 древовидное представление программы не было полностью независимым от целевого процессора. Значение дерева несколько отличалось для различных языковых интерфейсов, и внешние интерфейсы могли предоставлять свои собственные древовидные коды. Это было упрощено с появлением GENERIC и GIMPLE, двух новых форм не зависящих от языка деревьев, которые были представлены с появлением GCC 4.0. GENERIC более сложен и основан на промежуточном представлении интерфейса Java GCC 3.x. GIMPLE является упрощенным РОДОВЫМ, в котором различные конструкции опускают на несколько инструкций GIMPLE. В C , C ++ и Java передние концы производят GENERIC непосредственно в передней части. Вместо этого другие интерфейсы имеют другие промежуточные представления после синтаксического анализа и преобразования их в GENERIC.

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

GENERIC и GIMPLE

GENERIC - это язык промежуточного представления, используемый в качестве « промежуточного звена » при компиляции исходного кода в исполняемые двоичные файлы . Подмножество, называемое GIMPLE , предназначено для всех интерфейсов GCC.

Средний этап GCC выполняет весь анализ и оптимизацию кода , работая независимо как от скомпилированного языка, так и от целевой архитектуры, начиная с представления GENERIC и расширяя его до языка передачи регистров (RTL). Представление GENERIC содержит только подмножество конструкций императивного программирования, оптимизированных средним концом.

При преобразовании исходного кода в GIMPLE сложные выражения разбиваются на трехадресный код с использованием временных переменных . Это представление было вдохновлено представлением SIMPLE предложенного в компиляторе McCAT по Laurie J. Hendren для упрощения анализа и оптимизации в императивных программах .

Оптимизация

Оптимизация может происходить на любом этапе компиляции; однако основная часть оптимизаций выполняется после синтаксического и семантического анализа внешнего интерфейса и перед генерацией кода серверной части; таким образом, обычное, хотя и несколько противоречивое, название этой части компилятора - "средний конец".

Точный набор оптимизаций GCC варьируется от выпуска к выпуску по мере его разработки, но включает стандартные алгоритмы, такие как оптимизация цикла , многопоточность перехода , исключение общих подвыражений , планирование инструкций и т. Д. В RTL оптимизации имеют меньшее значение , с добавлением глобальных оптимизации ССА основе на GIMPLE деревьев, так как RTL оптимизации имеют гораздо более ограниченный объем, и имеют меньший объем информации на высоком уровне.

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

Бэк-энд

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

Файл описания компьютера содержит шаблоны RTL, а также ограничения операндов и фрагменты кода для вывода окончательной сборки. Ограничения указывают на то, что конкретный шаблон RTL может применяться (например) только к определенным аппаратным регистрам или (например) разрешать немедленные смещения операндов только ограниченного размера (например, 12, 16, 24, ... битовые смещения и т. Д.) ). Во время генерации RTL проверяются ограничения для данной целевой архитектуры. Чтобы выдать данный фрагмент RTL, он должен соответствовать одному (или нескольким) шаблонам RTL в файле описания машины и удовлетворять ограничениям для этого шаблона; в противном случае было бы невозможно преобразовать окончательный RTL в машинный код.

К концу компиляции действительный RTL сводится к строгой форме, в которой каждая инструкция ссылается на регистры реальной машины и образец из файла описания целевой машины. Формирование строгого RTL - сложная задача; важным шагом является выделение регистров , при котором выбираются реальные аппаратные регистры для замены изначально назначенных псевдорегистров. Затем следует фаза «перезагрузки»; любые псевдорегистры, которым не был назначен реальный аппаратный регистр, «переливаются» в стек, и генерируется RTL для выполнения этого сброса. Точно так же смещения, которые слишком велики для размещения в реальной инструкции, должны быть разбиты и заменены последовательностями RTL, которые будут подчиняться ограничениям смещения.

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

Стандартная библиотека C ++ (libstdc ++)

Проект GCC включает реализацию стандартной библиотеки C ++, называемой libstdc ++, под лицензией GPLv3 License, за исключением связывания приложений с закрытым исходным кодом, когда источники создаются с помощью GCC. Текущая версия - 11.

Другие особенности

Некоторые особенности GCC включают:

Оптимизация времени компоновки
Оптимизация времени компоновки оптимизирует границы объектного файла, чтобы напрямую улучшить связанный двоичный файл. Оптимизация времени компоновки полагается на промежуточный файл, содержащий сериализацию некоторого представления Gimple, включенного в объектный файл. Файл создается вместе с объектным файлом во время компиляции исходного кода. Каждая исходная компиляция создает отдельный объектный файл и вспомогательный файл времени компоновки. Когда объектные файлы связаны, компилятор запускается снова и использует вспомогательные файлы для оптимизации кода в отдельно скомпилированных объектных файлах.
Плагины
Плагины напрямую расширяют компилятор GCC. Плагины позволяют адаптировать стандартный компилятор к конкретным потребностям с помощью внешнего кода, загружаемого в виде плагинов. Например, плагины могут добавлять, заменять или даже удалять промежуточные проходы, работающие с представлениями Gimple . Уже опубликовано несколько плагинов GCC, в частности:
  • Плагин Python, который ссылается на libpython и позволяет вызывать произвольные сценарии Python изнутри компилятора. Цель состоит в том, чтобы позволить писать плагины GCC на Python.
  • Плагин MELT предоставляет Lisp- подобный язык высокого уровня для расширения GCC.
Поддержка плагинов когда-то была спорным вопросом в 2007 году.
Транзакционная память C ++
В языке C ++ есть активное предложение по транзакционной памяти. Его можно включить в GCC 6 и новее при компиляции с -fgnu-tm.
Идентификаторы Unicode
Хотя для языка C ++ требуется поддержка символов Unicode, отличных от ASCII, в идентификаторах , эта функция поддерживается только с GCC 10. Как и при существующей обработке строковых литералов, предполагается, что исходный файл имеет кодировку UTF-8 . Эта функция не является обязательной в C, но после этого изменения она также стала доступной.

Архитектура

GCC компилирует Hello World в Windows

Семейства целевых процессоров GCC, начиная с версии 11.1, включают:

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

Дополнительные процессоры поддерживаются версиями GCC, поддерживаемыми отдельно от версии FSF:

GCJ компилятор Java может выбрать либо родной язык архитектуры машины или виртуальной машины Java «s Java байткод . При перенацеливании GCC на новую платформу часто используется самозагрузка . Motorola 68000, Zilog Z80 и другие процессоры также используются в версиях GCC, разработанных для различных программируемых графических калькуляторов Texas Instruments, Hewlett Packard, Sharp и Casio.

Лицензия

GCC находится под лицензией GNU General Public License версии 3. Исключение времени выполнения GCC позволяет компилировать проприетарные программы (в дополнение к бесплатному программному обеспечению) с GCC. Это не влияет на условия лицензии исходного кода GCC.

Смотрите также

использованная литература

дальнейшее чтение

внешние ссылки

Официальный

Другой