- PVSM.RU - https://www.pvsm.ru -

Привет, %habra_user%!
Решил в продолжение цикла статей о Flex-компиляторе перевести хорошую статью автора сего творения о том, какие же процессы происходят внутри компилятора при сборке приложения. Датируется она 2008м годом, но при этом в русскоязычном сообществе (да и в других особо тоже) замечена не была. А так как ближайшее время именно этот компилятор остаётся актуальным для сборки подавляющего большинства Flash-проектов, то я решил продолжить цикл статей о его расширении.
Как обычно всех, кто не устал дочитав до этой строчки — прошу под кат!
Во-первых, считаю уместным привести ссылки на другие статьи из цикла:
Во-вторых, мне пришлось довольно таки хорошо погуглить чтобы найти актуальную (в связи с передачей Flex-а апачам) ссылку на код ветки 4.6, и чтобы сэкономить Ваше время я просто оставлю её тут:
opensource.adobe.com/svn//opensource/flex/sdk/branches/4.y/ [3]
Я (как и автор оригинальной статьи) настоятельно рекомендую скачать исходники для лучшего понимания материала статьи. Материал статьи актуален для обеих (Apache & Adobe) версий компилятора.
Вообще, Flex компилятор поддерживает разные языки программирования. Компилируются они набором специфичных для каждого языка компиляторами. Если посмотреть список классов проекта с именем Compiler, можно увидеть некоторые из них:

При этом нельзя утверждать, что все языки могут быть скомпилированы в один этап. Например, компилятор MXML может использовать использовать зависимости, написанные на AS3. Поэтому прежде чем скомпилировать MXML компонент в байткод, компилятор обязан выявить, какие AS3 классы ему нужны и проверить, что вызываемый из MXML код на AS3 корректен.
Так же разумно предполагать, что разным компиляторам требуется разное количество этапов. Например, MXML компилятор требует вдвое большее количество шагов чем AS3.
В Flex, все компиляторы языков реализуют один и тот же интерфейс — flex2.compiler.SubCompiler:
public interface SubCompiler
{
String getName();
boolean isSupported(String mimeType);
String[] getSupportedMimeTypes();
Source preprocess(Source source);
CompilationUnit parse1(Source source, SymbolTable symbolTable);
void parse2(CompilationUnit unit, SymbolTable symbolTable);
void analyze1(CompilationUnit unit, SymbolTable symbolTable);
void analyze2(CompilationUnit unit, SymbolTable symbolTable);
void analyze3(CompilationUnit unit, SymbolTable symbolTable);
void analyze4(CompilationUnit unit, SymbolTable symbolTable);
void generate(CompilationUnit unit, SymbolTable symbolTable);
void postprocess(CompilationUnit unit, SymbolTable symbolTable);
void initBenchmarks();
PerformanceData[] getBenchmarks();
PerformanceData[] getEmbeddedBenchmarks();
void logBenchmarks(Logger logger);
}
Из не относящихся к процессу компиляции методов можно выделить:
String getName() — как можно понять из названия, метод возвращает имя компилятора;
isSupported и getSupportedMimeTypes — служат для определения типа файлов, которые данный компилятор может обрататывать;
benchmarks методы, относящиеся к замеру производительности компиляции.
Как Вы могли заметить, процесс компиляции состоит из 9 этапов. Главный Flex-компилятор выступает в роли координатора и отвечает за вызов экземпляров компиляторов, которые ожидают примерно такого порядка:
Помимо вызова этих методов, главный Flex-компилятор делает ряд вещей:
Для того чтобы управлять всем и вся, главный компилятор заставляет экземпляры кооперироваться. В основном, он требует следовать определённому набору правил:
Процесс компиляции продолжается до того момента как:
Как было сказано ранее, процесс компиляции состоит из вызова этих 9 методов. Но не смотря на то, что порядок вызова этих методов определён довольно-таки точно, главный компилятор всё равно может вызывать их по-разному. По сути дела, существуют 2 алгоритма: Один (flex2.compiler.API.batch1()) структурированный, другой (flex2.compiler.API.batch2()) условно-патогенный. Рассмотрим их по отдельности:
API.batch1() — консервативный и более структированный алгоритм. Его суть заключается в том, что он гарантирует наступление одной фазы для каждого файла прежде чем перейти на другую фазу. Например, analyze1() будет вызвана для всех файлов прежде чем перейти к analyze2().
API.batch2() — условно-патогенный алгоритм, его главная цель — минимизировать потребление памяти. В отличие от API.batch1(), исходные файлы с меньшим количеством зависимостей могут дойти до этапа generate гораздо раньше чем файлы с бОльшим количеством зависимостей дойдут до фазы analyze3(). Идея в том, чтобы ресурсы, выделенные для файла, могли быть освобождены сразу как файл будет скомпилирован в байткод.
Что ж, теперь Вы знаете гораздо больше о внутренней работе Flex компилятора! Давайте подытожим:
Описанное Выше актуально для всех версий утилит (mxmlc, compc, asdoc), входящих в состав Flex Framework.
Просьба найденные грамматические ошибки и неточности отправлять личным сообщением, дабы не увеличивать количество полупрозрачных комментариев;)
P.S. Вообще, изначально идея была написать статью о Flex Compiler Extension-ах, которые позволяют расширять компилятор не меняя его код (подключатся через flex-config.xml в виде jar-ок), но одумавшись я решил сначала сделать эту статью, которая описывает всю подноготную.
P.S.S. Учитывая темпы развития ASC2.0, я считаю, что Flex Compiler будет актуальным ещё как минимум год, а то и больше, поэтому не бойтесь изучать и ковырять его, тем более, что это бесценный опыт!
P.S.S.S. Да, да, мёртв. Да, Adobe отказались от плеера. Да, отдали Apache. Бла-бла-бла…
Автор: bsideup
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/flash/34611
Ссылки в тексте:
[1] Добавляем в Flex-компилятор MXML параметры конструктора: http://habrahabr.ru/post/128703/
[2] MXML компилятор. Часть 2. Не строковые инициализаторы параметров: http://habrahabr.ru/post/131434/
[3] opensource.adobe.com/svn//opensource/flex/sdk/branches/4.y/: http://opensource.adobe.com/svn//opensource/flex/sdk/branches/4.y/
[4] Источник: http://habrahabr.ru/post/180139/
Нажмите здесь для печати.