Javascript.RU

Использование внутренних опций и собственные флаги

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

Warning: статья частично устарела.

Следующая диаграмма иллюстрирует механизм инициализации и запуска компилятора.

Точкой входа является CompilerRunner (наследует AbstractCompilerRunner).

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

Класс Compiler осуществляет процесс компиляции и сжатия javascript. По умолчанию он использует GoogleCodingConvention - вспомогательный класс для чтения информации о коде из имен.

Для того, чтобы произвести компиляцию и оптимизацию, Google Closure Compiler получает информацию из трех основных источников:

  1. Собственно код javascript, на основе которого строится граф взаимодействий и синтаксическое дерево разбора.
  2. Аннотации к коду, например /** @const */. Парсер читает их и добавляет информацию в синтаксическое дерево к аннотированному объекту в виде специальной структуры JSDoc.
  3. Соглашения о коде. Например, константы пишутся большими буквами, экспортируемые (доступные извне) свойства начинаются с подчеркивания "_", приватные свойства заканчиваются подчеркиванием и
    т.п. (это в Google Coding Convention).

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

При создании компилятора AbstractCompilerRunner ставит ему ставится уровень логирования по флагу --logging_level. Для логирования используется стандартный java logger. При указании уровня
FINEST, будут выведены все стадии компиляции.

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

Чтобы установить глобальный уровень логирования, в код можно добавить соответствующую инициализацию LogManager.

Новые флаги можно добавлять в CompilerRunner аналогично уже описанным (см. FLAG_...).

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

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

В объекте опций компилятора CompilerOptions содержатся флаги (булевы переменные) - какие оптимизации делать, а какие нет.

Эти флаги ставятся непосредственно после создания объекта опций объектом класса CompilationLevel. Его метод setOptionsForCompilationLevel назначает набор опций, исходя из значения --compilation_level.

Вы можете поменять набор или адаптировать его к вашим требованиям.

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

Впрочем, для более удобной поддержки лучше будет модифицировать опции в наследнике CompilerRunner.

Добавим флаг debug_level, который будет устанавливать переопределяемую javascript-переменную DEBUG_LEVEL при компиляции в нужное значение.

Для этого нужно совершить следующие шаги.

Взять код компилятора можно из SVN:

svn co http://closure-compiler.googlecode.com/svn/trunk gc

Создадим рядом с CompilerRunner свой класс-наследник MyCompilerRunner.

Он может быть, например, таким:

package com.google.javascript.jscomp;

import com.google.common.flags.Flag;
import com.google.common.flags.FlagSpec;

import java.io.PrintStream;

public class MyCompilerRunner extends CompilerRunner {

    /* Определить новый флаг */
    @FlagSpec(help = "Debug level.")
    public static final Flag<Integer> FLAG_debug_level
            = Flag.value(5);

    /* всевозможные конструкторы */
    public MyCompilerRunner(String[] args) {
        super(args);
    }

    public MyCompilerRunner(String[] args, PrintStream out, PrintStream err) {
        super(args, out, err);
    }

    /* изменить опции, в соответствие с новым флагом */
    @Override
    protected CompilerOptions createOptions() {

        CompilerOptions options = super.createOptions();

        /* переопределение javascript-переменной в значение флага */
        options.setDefineToNumberLiteral("DEBUG_LEVEL", FLAG_debug_level.get());

        return options;
    }

    /* точка входа в компилятор */
    public static void main(String[] args) {
        (new MyCompilerRunner(args)).run();
    }

}

Положить этот файл необходимо в ту же директорию, где лежит CompilerRunner.java, то есть в src/com/google/javascript/jscomp.

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

Для сборки необходим установленный JDK 1.6 и ANT. И то и другое достаточно просто в установке.

На верхнем уровне исходных кодов компилятора, рядом с директорией src есть файл build.xml. Это файл сборки ANT.

Для того, чтобы точкой входа служил класс MyCompilerRunner, достаточно заменить в ant-файле build.xml слово CompilerRunner на MyCompilerRunner, и затем запустить ant в директории с build.xml.

После этого в директории build появится новый jar-файл компилятора, с новыми флагами и поциями.

Компиляция в IDE

Когда я только начинал разбираться с Google Closure Compiler - сразу же затащил его в проект IDEA. Компиляция и запуск прошла без сучка и задоринки, но новые флаги не работали.

Оказалось, в build.xml прописан процесс перегенерации файла флагов flags.xml. Поэтому при изменении флагов лучше пересобрать компилятор через ant, используя ant plugin или командную строку.

Процессор флагов описан в jar-файле, который доступен в SVN вместе с кодом компилятора. Однако, исходника для этого файла нет.

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

Расширение компилятора производится аналогично. Добавляется класс MyCompiler, наследующий от Compiler.

Например, включим в унаследованном компиляторе логирование на всю катушку без использования флага java.util.logging.config.file.

Для этого добавим чтение конфига в начало конструктора MyCompiler:

package com.google.javascript.jscomp;

import java.io.*;
import java.util.logging.LogManager;

public class MyCompiler extends Compiler {

    // есть и другие конструкторы, но при запуске в консоли используется этот
    public MyCompiler(PrintStream stream) {
        super(stream);
                      
        try {
            File f = new File("/tmp/logging.properties");
            InputStream in = new FileInputStream(f);
            BufferedInputStream bin = new BufferedInputStream(in);
            LogManager.getLogManager().readConfiguration(bin);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }  
    }
}

Файл logging.properties может быть, например, таким:

handlers= java.util.logging.ConsoleHandler
.level= ALL

java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

some.class.level = SEVERE

Чтобы задействовать новый класс компилятора, перекроем в MyCompilerRunner соответствующий фабричный метод:

/* фабричный метод для компилятора */
    @Override
    protected Compiler createCompiler() {
        return new MyCompiler(getErrorPrintStream());
    }

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

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

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

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

Примеры практического применения своих флагов и опций вы можете увидеть в статьях:

Многие опции пока недокументированы и даже недоступны в стандартной сборке. Почему - остается только гадать: работают они вполне эффективно. Видимо, это побочный эффект организации процесса разработки и того, что над Google Closure Compiler идет активная работа.

Следующий класс добавляет ряд опций в виде флагов компилятора.

package com.google.javascript.jscomp;

import com.google.common.flags.Flag;
import com.google.common.flags.FlagSpec;

import java.io.PrintStream;
import java.util.HashSet;
import java.util.List;

public class MyCompilerRunner extends CompilerRunner {

    @FlagSpec(help = "Specify stripTypes. You can include multiple.")
    public static final Flag<List<String>> FLAG_strip_types
            = Flag.stringCollector();

    @FlagSpec(help = "Specify stripTypePrefixes. You can include multiple.")
    public static final Flag<List<String>> FLAG_strip_type_prefixes = Flag.stringCollector();

    @FlagSpec(help = "Specify stripTypeSuffixes. You can include multiple.")
    public static final Flag<List<String>> FLAG_strip_name_suffixes
            = Flag.stringCollector();

    @FlagSpec(help = "Specify stripNamePrefixes. You can include multiple.")
    public static final Flag<List<String>> FLAG_strip_name_prefixes
            = Flag.stringCollector();

    @FlagSpec(help = "@export support.")
    public static final Flag<Boolean> FLAG_export_annotation
            = Flag.value(true);

    @FlagSpec(help = "Enables property renaming: HEURISTIC/AGGRESSIVE_HEURISTIC")
    public static final Flag<PropertyRenamingPolicy> FLAG_property_renaming_policy
            = Flag.value(PropertyRenamingPolicy.OFF);


    /* всевозможные конструкторы */
    public MyCompilerRunner(String[] args) {
        super(args);
    }

    public MyCompilerRunner(String[] args, PrintStream out, PrintStream err) {
        super(args, out, err);
    }

    /* изменить опции, в соответствие с новым флагом */
    @Override
    protected CompilerOptions createOptions() {

        CompilerOptions options = super.createOptions();

        options.stripTypes = new HashSet<String>(FLAG_strip_types.get());
        options.stripTypePrefixes = new HashSet<String>(FLAG_strip_type_prefixes.get());
        options.stripNameSuffixes = new HashSet<String>(FLAG_strip_name_suffixes.get());
        options.stripNamePrefixes = new HashSet<String>(FLAG_strip_name_prefixes.get());
        options.generateExports = FLAG_export_annotation.get();
        options.propertyRenaming = FLAG_property_renaming_policy.get();

        return options;
    }

    /* точка входа в компилятор */
    public static void main(String[] args) {
        (new MyCompilerRunner(args)).run();
    }

}

К этому классу, при необходимости, можно добавить свои флаги и опции: externExportsPath, goog.LOCALE, переопределения @define и т.п.


Автор: Гость (не зарегистрирован), дата: 6 мая, 2010 - 10:01
#permalink

Илья, пожалейте простых людей. Выложите готовый jar.


Автор: Гость (не зарегистрирован), дата: 7 мая, 2010 - 10:49
#permalink

В последних версиях класса CompilerRunner уже нет, статья теряет актуальность. Увы, соответственно, как и другие статьи про эвристическое переименование, ...


Автор: dmitryx (не зарегистрирован), дата: 17 февраля, 2011 - 16:19
#permalink

он есть, просто переименован.
(ver 119, 2/27/10):
Rename CompilerRunner -> CommandLineRunner.
I'll also do this for JSCompilerRunner, but it will be a much
bigger change. (Nick)


Автор: VAL (не зарегистрирован), дата: 24 февраля, 2011 - 14:43
#permalink

да, но не работает
import com.google.common.flags.Flag;


Автор: justicehwrknz807, дата: 10 января, 2022 - 10:23
#permalink

This article is well-written and very interesting. The author did an excellent job of keeping it interesting and to the point. Bathroom Remodel Tacoma Wa


Автор: junmalo (не зарегистрирован), дата: 24 января, 2022 - 09:22
#permalink

Thank you very much for these great cake recipes, I have learned a lot from your web blog atari breakout


Автор: antiguans2000, дата: 12 марта, 2022 - 13:55
#permalink

It would be better to modify the options in the CompilerRunner. https://www.prestige360.info


Автор: Гость (не зарегистрирован), дата: 15 апреля, 2022 - 23:51
#permalink

Автор: Mandy Dahlen (не зарегистрирован), дата: 1 июля, 2022 - 20:37
#permalink

Geile Nutten ist für die meisten Menschen der perfekte Ort, um miteinander zu chatten und zu interagieren. Sie haben eine einfache und leicht zu verstehende Schnittstelle. Keine Füller oder seltsamen Tools, sie bieten grundlegende, aber leistungsstarke Funktionen.


Автор: Claudia C. Sanderson (не зарегистрирован), дата: 18 июля, 2022 - 05:25
#permalink

awesome post thank you for sharing check my article here arieshemp


Автор: Jacomina Vlieger (не зарегистрирован), дата: 4 августа, 2022 - 20:37
#permalink

BDSM is de perfecte site om je BDSM-leven te verkennen! Kinky Sex geeft je de mogelijkheid om je smerigste, donkerste en soms meest vernederende fantasieën uit te leven. Het stelt je lichaam en geest in staat te ontspannen en te leven in een wereld van je dromen.


Автор: Camilla Eide (не зарегистрирован), дата: 1 сентября, 2022 - 20:38
#permalink

Shemale Escort ble spesielt utviklet for transsamfunnet og er en av de mest interessante transgender datingsidene på internett. Mange transpersoner anser det som den beste datingsiden for transpersoner. På denne siden kan du finne alle typer transkjønnede partnere for engasjement, forhold, vennskap, kjærlighet eller til og med ekteskap.


Автор: antiguans2000, дата: 2 сентября, 2022 - 09:51
#permalink

At the top level of the compiler source code, next to the directory src, there is a build.xml. This is an ANT assembly file.

basement wall repair


Автор: Elly Malestein (не зарегистрирован), дата: 2 сентября, 2022 - 20:38
#permalink

Geile chat , Hier vind je sexadvertenties van geile mannen en vrouwen die op zoek zijn naar meer spanning en passie in hun leven.


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
2 + 0 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum