8-900-374-94-44
[email protected]
Slide Image
Меню

Компиляция с: Компиляция программы на языке C

Содержание

1.4.1. Компиляция с включением отладочной информации. Программирование для Linux. Профессиональный подход

1.4.1. Компиляция с включением отладочной информации. Программирование для Linux. Профессиональный подход

ВикиЧтение

Программирование для Linux. Профессиональный подход
Митчелл Марк

Содержание

1.4.1. Компиляция с включением отладочной информации

Чтобы можно было воспользоваться GNU-отладчиком, необходимо скомпилировать программу с включением в нее отладочной информации. Этой цели служит опция -g компилятора. Если имеется описанный выше файл Makefile, достаточно задать переменную CFLAGS равной -g при запуске утилиты make:

% make CFLAGS=-g

gcc -g -с main.c

g++ -g -c reciprocal.cpp

g++ -g -о reciprocal main.o reciprocal.o

Встречая в командной строке флаг -g, компилятор включает дополнительную информацию в объектные и исполняемые файлы. Благодаря этой информации отладчик узнает, какие адреса соответствуют тем или иным строкам в том или ином исходном файле, как отобразить значение локальной переменной, и т.д.

Компиляция

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

3.8.3. Компиляция ядра

3.8.3. Компиляция ядра При установке из RPM-пакета мы получаем модульное ядро, в котором драйверы устройств могут быть как скомпилированы в одно целое с ядром, так и загружаться отдельно. Такое ядро медленнее в работе, но позволяет обновлять драйверы простой заменой

Компиляция ядра

Компиляция ядра После того как вы сконфигурировали ядро системы, выполнив make xconfig или другую команду, приведенную в начале данной главы, вы должны скомпилировать ядро и установить его модули. Для этого необходимо выполнить следующие команды:# make dep# make bzImage# make modules# make

20.5. Компиляция ядра

20.5. Компиляция ядра 20.5.1. Зачем обновлять ядро? Linux развивается быстрее любой другой операционной системы. Регулярно появляются новые версии ядра, реализующие новые функции. Например, едва успел выйти дистрибутив Fedora Core 4 на ядре 2.6.11, а на www.kernel.org уже лежит стабильная

3.4.3. Компиляция

3.4.3. Компиляция Как правило, исходные коды программ распространяются в виде архива с «двойным расширением» -.tar.gz. Исходный код принято распаковывать в каталог /usr/src. Поэтому для распаковки архива вам нужно выполнить следующие команды:sucd /usr/srcgunzip архив.tar.gztar xvf

Компиляция программ

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

Условная компиляция

Условная компиляция Другой пакет директив препроцессора (#if, #elif, #else, #endif) позволяет выполнить компиляцию блока программного кода по условию, базируясь на предварительно заданных символах. Классическим вариантом использования этих директив является идентификация блока

Почему компиляция?

Почему компиляция? Читатели, пользовавшиеся языком Бейсик, могут удивиться, зачем столько шагов для того, чтобы выполнить программу. Кажется, что такой способ компиляции требует больше времени (и в некоторых случаях это может быть действительно так). Но, поскольку в

12.2. Запись информации в файлы и считывание информации из файлов

12. 2. Запись информации в файлы и считывание информации из файлов Постановка задачи Требуется сохранить на диске информацию (например, текст, данные, изображения и

10.5.1. Модель компиляции с включением

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

16.8.1. Модель компиляции с включением

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

1.

1.2 Компиляция

1.1.2 Компиляция Откуда появились выходной поток cout и код, реализующий операцию вывода ««? Для получения выполняемого кода написанная на С++ программа должна быть скомпилирована. По своей сути процесс компиляции такой же, как и для С, и в нем участвует большая часть входящих

1.2. Понятие информации. Общая характеристика процессов сбора, передачи, обработки и накопления информации

1.2. Понятие информации. Общая характеристика процессов сбора, передачи, обработки и накопления информации Вся жизнь человека так или иначе связана с накоплением и обработкой информации, которую он получает из окружающего мира, используя пять органов чувств – зрение,

Анализ поправок, принятых Госдумой, к закону «Об информации, информационных технологиях и о защите информации» Сергей Голубицкий

Анализ поправок, принятых Госдумой, к закону «Об информации, информационных технологиях и о защите информации» Сергей Голубицкий Опубликовано 26 июня 2013 21 июня Государственная Дума РФ приняла сразу во втором и третьем чтении Федеральный Закон «О

что это такое и как применяется в программировании

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

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

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

Для чего нужен компилятор

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

Без компилятора любой код на компилируемом языке программирования будет для компьютера просто текстом — он не распознает команды и не сможет их выполнить. Поэтому компилятор нужен, чтобы программы могли выполняться. Без него ничего не будет работать.

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

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

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

Интерпретатор — это тоже программа, которая «переводит» текст на высокоуровневом языке программирования, но делает это иначе. Она не собирает весь код в один исполняемый файл для последующего запуска, а исполняет код сразу, построчно. Это чуть медленнее, но иногда удобнее. Языки, использующие интерпретаторы, называются интерпретируемыми.

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

В каких языках используются компиляторы

Среди популярных сегодня языков компилируемыми являются Swift и Go, а также C / C++ и Objective-C. Другие примеры — Visual Basic, Haskell, Pascal / Delphi, Rust, а также Lisp, Prolog и прочие менее известные языки. Разумеется, компилируемым является и язык ассемблера — очень низкоуровневый и написанный напрямую на машинных кодах.

Отдельно можно выделить языки, которые трансформируются в байт-код — это тоже своего рода компиляция. К ним относятся Java, Scala и Kotlin, а также C# и языки платформы .NET.

На каких языках пишут компиляторы

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

Например, один из компиляторов языка Go частично написан на C++, самый первый компилятор C++ — на ассемблере, а уже ассемблер — на машинных кодах.

Тот же язык. Написать компилятор для языка программирования можно на других версиях того же языка — такой подход разрешен и активно используется в разработке. Это нужно, чтобы компиляторы были более гибкими и «умными» и могли поддерживать больше возможностей, — ассемблер довольно примитивен и не решает всех задач.

Выглядит это так:

  • первый, более простой компилятор пишется на ассемблере;
  • второй пишется уже на нужном языке и компилируется первым компилятором;
  • переведенный в машинные коды второй компилятор компилирует свои же исходники — получается более новая и мощная версия его же.

Например, большинство современных компиляторов для C / C++ написано на C / C++. Такие компиляторы называют самокомпилируемыми.

Почему у одного языка может быть несколько компиляторов

У большинства языков программирования несколько компиляторов. Их еще называют реализациями. Изначальную реализацию пишет создатель языка, потом со временем появляются альтернативные. Зачем это делается? Цели могут быть разными:

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

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

Какими бывают компиляторы

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

Один компилятор может «знать» несколько языков программирования. Яркий пример такого решения — GCC, или GNU Compiler Collection, кросс-компилятор для нескольких операционных систем и языков, полностью бесплатный и свободный. На нем написано программное обеспечение GNU.

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

Как устроены и работают компиляторы

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

Сама компиляция может быть:

  • построчной — в машинный код по очереди переводится каждая строка, что похоже на интерпретацию, но отличается технически;
  • пакетной — код разбивается на блоки, или пакеты, и компилируется поблочно;
  • условной — особенности компиляции зависят от условий, которые прописаны в исходном коде компилируемой программы.

Сначала компилятор разбирает, что написано, потом анализирует команды, а потом генерирует машинные коды. Он не запускает программу, запуск — это отдельное действие.

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

Недостатки компилируемых языков
  • В отличие от интерпретируемых языков, компилируемые не выполняют код сразу — его сначала нужно собрать, а это лишний шаг и лишнее время.
  • Код сложнее в отладке: приходится заново компилировать его при каждом, даже небольшом изменении. Сам процесс поиска и устранения ошибок бывает довольно неочевидным.
  • Машинный код жестко связан с архитектурой платформы и различается в зависимости от системы. Поэтому компилируемые языки — по умолчанию не кроссплатформенные. Для переноса языка на другую операционную систему понадобится писать новый компилятор. Правда, есть исключения в виде универсальных кросс-компиляторов, работающих под разными платформами, но они подходят не для всего.
  • Для новичков проблема еще и в том, что компилируемые языки часто сложнее, чем интерпретируемые. Изучать их с нуля может быть тяжело, хотя и тут есть исключения.

Как пользоваться компилятором

Начинающий разработчик редко взаимодействует с компилятором напрямую. Он скачивает язык программирования, в том числе его компилятор, а потом работает в редакторе кода или IDE. Среда разработки сама запускает компилятор каждый раз, когда пользователь кликает на кнопку сборки или выполнения программы. Для этого его не нужно вызывать вручную. Иногда среда может сама включать в себя несколько компиляторов и выбирать подходящий в каждом случае.

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

У любого ПО есть документация, так что, если вы хотите узнать больше о компиляторе, которым пользуетесь, можете прочитать ее.

Узнайте больше об устройстве и работе языков программирования на курсах — получите новую профессию и станьте востребованным IT-специалистом.

Fatal error: Allowed memory size of 2147483648 bytes exhausted (tried to allocate 13732440 bytes) in /var/www/u1306671/data/www/blog.skillfactory.ru/wp-includes/class-wpdb.php on line 2432

WordPress › Ошибка

На сайте возникла критическая ошибка.

Узнайте больше про решение проблем с WordPress.

Компиляция Определение и значение — Merriam-Webster

компиляция ˌkäm-pə-lā-shən 

 также -ˌpī-

1

: действие или процесс составления

ежегодный сборник данных

2

: что-то составленное

сборник хитов

сборник отчетов о дорожно-транспортных происшествиях

Синонимы

9002 6
  • альбом
  • антология
  • коллекционный
  • сборник
  • флорилегия
  • разное
  • читатель
  • Просмотреть все синонимы и антонимы в тезаурусе 

    Примеры предложений

    CD представляет собой компиляций лучших хитов. медленный компиляция данных

    Недавние примеры в Интернете Выпущенная в июне 2020 года как часть сборника Mexican Summer , эта песня стала началом совершенно нового звучания Уильямсона. — Энджи Марточчио, Rolling Stone , 28 марта 2023 г. Джейсон внес значительный вклад в данные

    компиляция , анализ и написание этой статьи. — Рэнди Уоттс, Forbes , 26 января 2023 г. Деми Ловато, которая была основным персонажем на канале Disney в конце 2000-х благодаря телешоу, таким как Sonny With a Chance и фильмы Camp Rock, отсутствовала в сборнике ID . — Рания Анифтос, Billboard , 7 апреля 2023 г. Красный/Синий 9Компиляции 0047 закрепили наследие Битлз для будущих поклонников. — Роб Шеффилд, Rolling Stone , 2 апреля 2023 г. Расширенная компиляция шейдеров шагов и заикание в игре преследовали многие недавние игры для ПК, и разработчики все чаще обращаются к их компиляции при первой загрузке игры, чтобы избежать заиканий в будущем. — Том Уоррен,
    Грань
    , 29 лет.март 2023 г. Эти компиляции полезны не только в чрезвычайных ситуациях: каждый, независимо от состояния здоровья, может извлечь пользу из составления файла здоровья. — Марк Хэй, SELF , 29 марта 2023 г. Определенно, компиляция Скотта была бы очень первой в моем списке. — Лиза Лентини, SPIN , 24 марта 2023 г. Но как-то эта изменчивая сборник шоу кажется устаревшим. — Питер Маркс, Washington Post , 24 марта 2023 г. Узнать больше

    Эти примеры программно скомпилированы из различных онлайн-источников, чтобы проиллюстрировать текущее использование слова «компиляция». Любые мнения, выраженные в примерах, не отражают точку зрения Merriam-Webster или ее редакторов. Отправьте нам отзыв об этих примерах.

    История слов

    Этимология

    см. компиляцию

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

    15 век, в значении, определенном в смысле 1

    Путешественник во времени

    Первое известное использование компиляции было в 15 веке

    Посмотреть другие слова того же века

    Словарные статьи Около

    компиляция

    Компьень

    компиляция

    компилятор

    Посмотреть другие записи поблизости

    Процитировать эту запись «Сборник».

    Словарь Merriam-Webster.com , Merriam-Webster, https://www.merriam-webster.com/dictionary/compilation. Просмотрено 29Апрель 2023 г.

    Копия цитирования

    Kids Definition

    сборник

    существительное

    компиляция ˌkäm-pə-lā-shən 

    1

    : действие или процесс компиляции

    2

    : нечто скомпилированное

    специально : сборник материалов, собранных из других книг

    Legal Definition

    компиляция

    существительное

    компиляция ˌkäm-pə-lā-shən 

    : собрание ранее существовавших материалов и данных, организованных таким образом, чтобы создать новое оригинальное произведение в соответствии с законом об авторском праве

    Еще от Merriam-Webster о компиляции

    Английский: Перевод компиляции для говорящих на испанском языке

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

    Britannica. com: Энциклопедическая статья о компиляции

    Последнее обновление: — Обновлены примеры предложений

    Подпишитесь на крупнейший словарь Америки и получите тысячи дополнительных определений и расширенный поиск без рекламы!

    Merriam-Webster без сокращений

    Переосмысление компиляции приложений для Android с помощью Buck

    Каждый день инженеры Facebook вносят тысячи изменений в код и часто повторяют цикл разработки «редактирование-компиляция-запуск». Несколько лет назад мы создали и открыли исходный код Buck, инструмент сборки, разработанный с нуля для быстрой итерации, позволяющий инженерам быстро компилировать и запускать изменения.

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

    Мы сделали шаг назад и подвергли сомнению некоторые из этих основных предположений, что привело нас к глубокому пониманию нюансов языка Java и внутреннего устройства компилятора Java. В конце концов, мы полностью переосмыслили способ, которым Бак компилирует Java-код, обеспечив прирост производительности, недостижимый за счет постепенных улучшений. Сегодня мы открываем новую функцию в Buck, которая принесет эти улучшения производительности инженерам Android во всем мире.

    Самая быстрая сборка — та, которую вам не нужно делать.

    Архитектура Buck оптимизирована для быстрых инкрементных сборок, даже с компиляторами, не имеющими встроенной поддержки инкрементов.

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

    Рис. 1. График зависимостей для части собственной сборки Бака, рассчитанный без каких-либо новых функций, описанных в этой статье. Узлы, оканчивающиеся на #class-abi, представляют работу по созданию JAR-заглушек путем удаления деталей реализации из соответствующих полных JAR-файлов.

    Графики сборки, подобные приведенному выше изображению, помогают ускорить сборку. Buck кэширует выходные данные каждого правила, и когда он обнаруживает изменение в выходных данных правила, он идентифицирует и перестраивает только зависимые правила. Передовой опыт Buck рекомендует сохранять правила небольшими — это не только способствует более модульной архитектуре приложений, но также уменьшает объем кода, который необходимо перестроить для любого конкретного изменения, что ускоряет инкрементные сборки.

    В некоторых случаях Buck делает больше, чем наивно обнаруживает изменения в выводе, например, когда правила компилируют код Java. Результатом правила Java является файл JAR (Java ARchive, по сути, . zip под другим именем, содержащим байт-код Java). Есть много изменений, которые вы можете внести в исходный код Java, которые приведут к другому файлу JAR, но не повлияют на зависимые правила, однако, если бы Buck выполнял базовое сравнение вывода, он все равно перестроил бы их. Например, закрытые члены и содержимое тел методов не могут влиять на зависимые правила. Итак, после создания JAR-файла Бак создает «заглушку JAR», удаляя все эти элементы, а затем компилирует зависимые правила на основе изменений в нем вместо полного JAR-файла.

    Игнорирование неиспользуемых классов

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

    Включение этой функции в Facebook уменьшило количество правил, перестраиваемых Баком, на 35%. Теперь он включен по умолчанию в версии Buck с открытым исходным кодом.

    Сокращение узких мест с помощью конвейерной обработки правил

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

    В то время как стандартный способ создания JAR-заглушки состоит в том, чтобы сначала построить полный JAR, а затем удалить тела методов и закрытые члены, компилятор Java фактически имеет всю информацию, необходимую для создания JAR-заглушки примерно на полпути его выполнения. Воспользовавшись этим, Buck теперь может позволить зависимым правилам начать компиляцию, в то время как компилятор все еще завершает их зависимости, очень похоже на конвейерную обработку инструкций в ЦП. Это позволяет нам получить немного больше параллелизма и сократить узкие места, вызванные большими правилами сборки.

    На высоком уровне компилятор Java работает с кодом в два этапа: «анализ+ввод» и «анализ+генерация». Фаза «анализ+ввод» анализирует исходный код и вычисляет имена и сигнатуры всех типов и членов, определенных в нем. Фаза «анализ+генерация» анализирует тела методов и генерирует для них байт-код — байт-код, который входит только в полный JAR. Мы добавили подключаемый модуль компилятора, который запускается после «parse+enter», используя модель кода компилятора для создания JAR-заглушки. Затем зависимые правила начинают создаваться раньше, используя JAR-заглушку, в то время как компилятор все еще выполняет «анализ + создание» для полного JAR. Другие инструменты создают JAR-файлы-заглушки из исходного кода в качестве отдельного шага с использованием пользовательского синтаксического анализатора. Выполняя это изнутри компилятора, Buck использует работу, которую уже выполняет компилятор.

    Рисунок 2: График построения одного из тестов Бака до и после внедрения конвейерной обработки правил. Без конвейерной обработки Buck должен полностью завершить компиляцию библиотечного правила в (1), прежде чем он сможет начать компиляцию тестового правила в (2). При конвейерной обработке Бак быстро создает JAR-заглушку библиотеки в (3) и может начать компиляцию теста в (4), параллельно завершая компиляцию библиотечного правила.

    В Facebook внедрение конвейерной обработки правил сократило время сборки на 10%. Эта функция также доступна в Buck с открытым исходным кодом, но по умолчанию она еще не включена. Чтобы принять участие, добавьте abi_generation_mode = source в раздел [java] вашего файла .buckconfig .

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

    Внимание к использованию классов позволило Buck выполнять меньше работы, а создание заглушек JAR внутри компилятора позволило немного увеличить параллелизм. Хотя эти изменения не были тривиальными, они носили постепенный характер. Чтобы действительно изменить кривую производительности, нам нужно было подвергнуть сомнению наши основные предположения о создании программного обеспечения и фундаментально переосмыслить компиляцию Java.

    Есть одно предположение: прежде чем Buck сможет создать какое-либо правило, ему необходимо получить JAR-файлы-заглушки для всех своих зависимостей. А для их сборки нужны JAR-заглушки их зависимостей, и так далее до конца графа сборки.

    А если нет?

    Для заданного числа узлов в графе более плоские графы обеспечивают более быстрое построение как из-за увеличения параллелизма, так и из-за того, что пути, которые необходимо проверять на наличие изменений, короче. Если бы Баку не нужно было сначала строить зависимости, график сборки был бы резко сглажен. Дальше так и останется. Граф зависимостей, как его представляют себе разработчики, имеет тенденцию становиться глубже по мере роста приложения. Если зависимости на самом деле не нужны для сборки, граф зависимостей с точки зрения Бака может оставаться на более или менее постоянной глубине перед лицом роста приложения.

    Рисунок 3: График зависимостей для части Buck с рисунка 1, за исключением того, что на этот раз JAR-файлы-заглушки создаются непосредственно из исходного кода (узлы #source-abi) без учета зависимостей. Сравните это с графиком на рис. 1. Этот график в два раза меньше по высоте, с большим параллелизмом. (Он также может полностью избежать компиляции некоторых узлов, но это случайность конструкции этого конкретного модуля, а не то, чего можно ожидать все время.) Эффект еще более поразителен в менее тривиальных графах.

    Сначала казалось нелепым подвергать сомнению основное предположение о том, как строится код Java. Оказывается, это не так. Почти вся информация в файле-заглушке .class присутствует в его исходном файле .java . Люди могут понять интерфейс модуля, просто взглянув на исходный код самого модуля. Сделав несколько предположений, Бак теперь может сделать то же самое с помощью новой функции, которую мы называем генерацией заглушек только для исходного кода. Вот как мы это сделали.

    В рамках нашей работы по устранению узких мест, описанных выше, мы уже написали генератор заглушек JAR, который мог генерировать заглушки после фазы «анализ+ввод» компилятора Java. Компилятор Java с радостью выполнит «parse+enter» с отсутствующими зависимостями, а его API предоставят заполнители для отсутствующих типов. Мы решили расширить наш генератор заглушек JAR, чтобы обрабатывать эти заполнители, когда они появляются.

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

    Что в имени?

    Вот простой пример:

     import com.example.base.Bar; 

    Существует ли этот тип? Мы не можем этого знать, но при создании заглушки JAR мы предполагаем, что это так. Если этого не произойдет, когда Бак соберется скомпилировать полный JAR-файл, код не скомпилируется.

    Является ли com.example.base пакетом или классом? Мы не можем этого знать, но почти универсальное соглашение в Java — начинать имена классов с прописных букв, а имена пакетов — со строчных, так что мы пойдем с этим. Если мы находим существенные исключения из соглашения, мы можем создать способ их указать.

    Конечно, Java позволяет вам говорить о классах более кратко:

     
    пакет com.example;
        
    импортировать com.example.base.Bar;
    импортировать com.example.helper.*;
    импортировать com.example.interfaces.Baz;
        
    открытый класс Foo расширяет Bar, реализует Baz {
      Компилятор с;
    }
     
     

    Какое полное имя типа Compiler ? Есть бесконечные возможности. (Из этого фрагмента кода можно сделать 5 конкретных предположений.) Мы предположили, что это com.example.Компилятор . Если инженеру нужны какие-либо другие случаи, он должен написать что-то однозначное, например Bar.Compiler или com.example.helper.Compiler .

    Константы Java также представляли собой проблему:

     
    импортировать com.example.base.Bar;
        
    открытый класс Foo {
      public static final int SOME_CONSTANT = Bar.SOME_OTHER_CONSTANT;
    }
     
     

    Каково значение SOME_CONSTANT ? Мы не можем знать, если у нас нет доступа к Bar , поэтому мы предполагаем, что это не константа времени компиляции. При компиляции зависимостей этого правила компилятор не сможет встроить константу, как обычно (небольшая неэффективность, которую можно исправить, запустив Redex или ProGuard). Это также может вызвать сбои сборки, если вы используете SOME_CONSTANT в расположении, для которого требуется константа времени компиляции, например switch оператор case метка или параметр аннотации. В этом случае мы позволили инженерам попросить Бака убедиться, что Bar доступен при создании JAR-заглушки для Foo .

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

    Но процессоры аннотаций!

    Обработчики аннотаций — это написанные пользователем плагины к компилятору Java, которые могут генерировать новый код Java в ответ на аннотации, присутствующие в компилируемом коде. Они становятся все более популярными как способ уменьшить количество шаблонов, перенести повторяющуюся логику из среды выполнения во время компиляции или расширить возможности анализа компилятора. Их существование является одной из причин, по которой компилятор помещает заполнители для отсутствующих типов (что было ключевым фактором реализации этой функции), но они также создавали уникальные проблемы. Если код, который они генерируют, будет виден зависимым, их необходимо запускать при создании JAR-файлов-заглушек.

    В предыдущем разделе мы научили наш генератор заглушек угадывать необходимую информацию на основе типов заполнителей компилятора. Нам нужно было сделать то же самое для процессоров аннотаций. К счастью, API-интерфейсы компилятора таковы, что процессоры аннотаций почти полностью взаимодействуют с компилятором через интерфейсы, такие как javax.lang.model.util.Elements , а не через конкретные классы, и Бак уже отвечал за создание экземпляров процессоров аннотаций. Это позволило нам обернуть процессоры аннотаций и предоставить собственную реализацию этих интерфейсов. Мы должны были убедиться, что сами аннотации были доступны во время генерации заглушки JAR, поэтому мы добавили несколько (небольших) правил, которые нужно было создать, прежде чем массивный параллелизм вступил в игру.

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

    Сборка Instagram послужила тестовой площадкой для этой функции. Для этой сборки генерация заглушек только из исходного кода уменьшила глубину графа на 77 % и сократила выборку кэша на 50 %, что в совокупности сократило время сборки на 30 %. Мы ожидаем дальнейших улучшений в будущем, поскольку мы удалим некоторые возможности отказа, и мы работаем над развертыванием этой функции в других наших приложениях для Android.

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

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