Использование внутренних опций и собственные флаги
В этой статье мы разберем, как устроен общий цикл работы Google Closure Compiler, научимся добавлять новые флаги и устанавливать при их помощи внутренние, недокументированные опции компилятора.
Warning: статья частично устарела.
Следующая диаграмма иллюстрирует механизм инициализации и запуска компилятора.
Точкой входа является CompilerRunner (наследует AbstractCompilerRunner ).
Именно в этом классе (преимущественно, в коде родителя) происходит создание основных объектов, чтение флагов, указанных в командной строке и задание опций.
Класс Compiler осуществляет процесс компиляции и сжатия javascript. По умолчанию он использует GoogleCodingConvention - вспомогательный класс для чтения информации о коде из имен.
Для того, чтобы произвести компиляцию и оптимизацию, Google Closure Compiler получает информацию из трех основных источников:
- Собственно код javascript, на основе которого строится граф взаимодействий и синтаксическое дерево разбора.
- Аннотации к коду, например
/** @const */ . Парсер читает их и добавляет информацию в синтаксическое дерево к аннотированному объекту в виде специальной структуры JSDoc .
- Соглашения о коде. Например, константы пишутся большими буквами, экспортируемые (доступные извне) свойства начинаются с подчеркивания "_", приватные свойства заканчиваются подчеркиванием и
т.п. (это в 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 и т.п.
|
Илья, пожалейте простых людей. Выложите готовый jar.
В последних версиях класса CompilerRunner уже нет, статья теряет актуальность. Увы, соответственно, как и другие статьи про эвристическое переименование, ...
он есть, просто переименован.
(ver 119, 2/27/10):
Rename CompilerRunner -> CommandLineRunner.
I'll also do this for JSCompilerRunner, but it will be a much
bigger change. (Nick)
да, но не работает
import com.google.common.flags.Flag;
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
Thank you very much for these great cake recipes, I have learned a lot from your web blog atari breakout
It would be better to modify the options in the CompilerRunner. https://www.prestige360.info
Roksa grodzisk maz
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.
awesome post thank you for sharing check my article here arieshemp
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.
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.
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
Geile chat , Hier vind je sexadvertenties van geile mannen en vrouwen die op zoek zijn naar meer spanning en passie in hun leven.
dordle game is a new more challenging word game that could be your next addiction. Let's explore together!
I believe that playing games help us have a better mental health, for example, playing puzzle games, like bloxorz. It can also help u have a good state to study and work. And of course, play the game properly in terms of times, keeping balance between gaming and other activities.
On hot summer days, there's nothing better than settling in with a good game at home. My utmost recommendation is that free games
Важно то, что она сопровождает синтаксическое дерево кода и поэтому всегда доступна. drywall services White Rock Valley
The subway surfers uniqueness of the information presented here is a refreshing departure from the ordinary. This article is a shining example of how to bring fresh, distinctive insights to readers.
This article is a shining example of how to dordle bring fresh, distinctive insights to readers.
What matters is that it is always available and goes along with the code's syntax tree. | retaining walls gold coast
One of the highlights of A Small World Cup is the inclusion of various national teams, allowing players to represent their favorite countries on the miniature pitch.
The compiler code and a jar file describing the flag processor are both accessible in SVN. Try to check retaining wall cost for future reference..
Please send my heartfelt appreciation for the insightful and valuable contributions you have made to your website. I am writing to offer my heartfelt appreciation for the work you have made. quordle today
bandle is more than just a word game—it's a thrilling adventure that will test your word-finding skills and keep you entertained for hours on end. With its engaging gameplay, challenging levels, and social features, Bandle offers endless fun for players of all ages.
Отправить комментарий
Приветствуются комментарии:Для остальных вопросов и обсуждений есть форум.