blob: 5b1187062c3150101c090309ccee933bc266cd95 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev;
import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
import com.google.gwt.dev.cfg.BindingProperty;
import com.google.gwt.dev.cfg.ConfigurationProperty;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.PropertyPermutations;
import com.google.gwt.dev.cfg.Rules;
import com.google.gwt.dev.cfg.StaticPropertyOracle;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.javac.StandardGeneratorContext;
import com.google.gwt.dev.jdt.RebindOracle;
import com.google.gwt.dev.jdt.RebindPermutationOracle;
import com.google.gwt.dev.jjs.AbstractCompiler;
import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.JJSOptionsImpl;
import com.google.gwt.dev.jjs.JavaScriptCompiler;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.shell.StandardRebindOracle;
import com.google.gwt.dev.util.CollapsedPropertyKey;
import com.google.gwt.dev.util.Memory;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerCompileReport;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
import com.google.gwt.dev.util.arg.ArgHandlerDisableCastChecking;
import com.google.gwt.dev.util.arg.ArgHandlerDisableClassMetadata;
import com.google.gwt.dev.util.arg.ArgHandlerDisableGeneratingOnShards;
import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
import com.google.gwt.dev.util.arg.ArgHandlerDisableUpdateCheck;
import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
import com.google.gwt.dev.util.arg.ArgHandlerDumpSignatures;
import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
import com.google.gwt.dev.util.arg.ArgHandlerMaxPermsPerPrecompile;
import com.google.gwt.dev.util.arg.ArgHandlerOptimize;
import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
import com.google.gwt.dev.util.arg.ArgHandlerSoyc;
import com.google.gwt.dev.util.arg.ArgHandlerSoycDetailed;
import com.google.gwt.dev.util.arg.ArgHandlerStrict;
import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag;
import com.google.gwt.dev.util.arg.OptionDisableUpdateCheck;
import com.google.gwt.dev.util.arg.OptionEnableGeneratingOnShards;
import com.google.gwt.dev.util.arg.OptionGenDir;
import com.google.gwt.dev.util.arg.OptionMaxPermsPerPrecompile;
import com.google.gwt.dev.util.arg.OptionValidateOnly;
import com.google.gwt.dev.util.collect.Lists;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.concurrent.FutureTask;
/**
* Performs the first phase of compilation, generating the set of permutations
* to compile, and a ready-to-compile AST.
*/
public class Precompile {
/**
* The set of options for the precompiler.
*/
public interface PrecompileOptions extends JJSOptions, CompileTaskOptions,
OptionGenDir, OptionValidateOnly, OptionDisableUpdateCheck,
OptionEnableGeneratingOnShards, OptionMaxPermsPerPrecompile,
PrecompilationResult {
}
static class ArgProcessor extends CompileArgProcessor {
public ArgProcessor(PrecompileOptions options) {
super(options);
registerHandler(new ArgHandlerGenDir(options));
registerHandler(new ArgHandlerScriptStyle(options));
registerHandler(new ArgHandlerEnableAssertions(options));
registerHandler(new ArgHandlerDisableGeneratingOnShards(options));
registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
registerHandler(new ArgHandlerDisableClassMetadata(options));
registerHandler(new ArgHandlerDisableCastChecking(options));
registerHandler(new ArgHandlerValidateOnlyFlag(options));
registerHandler(new ArgHandlerDisableRunAsync(options));
registerHandler(new ArgHandlerDraftCompile(options));
registerHandler(new ArgHandlerDisableUpdateCheck(options));
registerHandler(new ArgHandlerDumpSignatures());
registerHandler(new ArgHandlerMaxPermsPerPrecompile(options));
registerHandler(new ArgHandlerOptimize(options));
registerHandler(new ArgHandlerCompileReport(options));
registerHandler(new ArgHandlerSoyc(options));
registerHandler(new ArgHandlerSoycDetailed(options));
registerHandler(new ArgHandlerStrict(options));
}
@Override
protected String getName() {
return Precompile.class.getName();
}
}
static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements
PrecompileOptions, Serializable {
private boolean disableUpdateCheck;
private boolean enableGeneratingOnShards = true;
private File genDir;
private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
private int maxPermsPerPrecompile;
private boolean validateOnly;
public PrecompileOptionsImpl() {
}
public PrecompileOptionsImpl(PrecompileOptions other) {
copyFrom(other);
}
public void copyFrom(PrecompileOptions other) {
super.copyFrom(other);
jjsOptions.copyFrom(other);
setDisableUpdateCheck(other.isUpdateCheckDisabled());
setGenDir(other.getGenDir());
setMaxPermsPerPrecompile(other.getMaxPermsPerPrecompile());
setValidateOnly(other.isValidateOnly());
setEnabledGeneratingOnShards(other.isEnabledGeneratingOnShards());
}
public File getGenDir() {
return genDir;
}
public int getMaxPermsPerPrecompile() {
return maxPermsPerPrecompile;
}
public int getOptimizationLevel() {
return jjsOptions.getOptimizationLevel();
}
public JsOutputOption getOutput() {
return jjsOptions.getOutput();
}
public boolean isAggressivelyOptimize() {
return jjsOptions.isAggressivelyOptimize();
}
public boolean isCastCheckingDisabled() {
return jjsOptions.isCastCheckingDisabled();
}
public boolean isClassMetadataDisabled() {
return jjsOptions.isClassMetadataDisabled();
}
public boolean isDraftCompile() {
return jjsOptions.isDraftCompile();
}
public boolean isEnableAssertions() {
return jjsOptions.isEnableAssertions();
}
public boolean isEnabledGeneratingOnShards() {
return enableGeneratingOnShards;
}
public boolean isOptimizePrecompile() {
return jjsOptions.isOptimizePrecompile();
}
public boolean isRunAsyncEnabled() {
return jjsOptions.isRunAsyncEnabled();
}
public boolean isSoycEnabled() {
return jjsOptions.isSoycEnabled();
}
public boolean isSoycExtra() {
return jjsOptions.isSoycExtra();
}
public boolean isStrict() {
return jjsOptions.isStrict();
}
public boolean isUpdateCheckDisabled() {
return disableUpdateCheck;
}
public boolean isValidateOnly() {
return validateOnly;
}
public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
jjsOptions.setAggressivelyOptimize(aggressivelyOptimize);
}
public void setCastCheckingDisabled(boolean disabled) {
jjsOptions.setCastCheckingDisabled(disabled);
}
public void setClassMetadataDisabled(boolean disabled) {
jjsOptions.setClassMetadataDisabled(disabled);
}
public void setDisableUpdateCheck(boolean disabled) {
disableUpdateCheck = disabled;
}
public void setEnableAssertions(boolean enableAssertions) {
jjsOptions.setEnableAssertions(enableAssertions);
}
public void setEnabledGeneratingOnShards(boolean enabled) {
enableGeneratingOnShards = enabled;
}
public void setGenDir(File genDir) {
this.genDir = genDir;
}
public void setMaxPermsPerPrecompile(int maxPermsPerPrecompile) {
this.maxPermsPerPrecompile = maxPermsPerPrecompile;
}
public void setOptimizationLevel(int level) {
jjsOptions.setOptimizationLevel(level);
}
public void setOptimizePrecompile(boolean optimize) {
jjsOptions.setOptimizePrecompile(optimize);
}
public void setOutput(JsOutputOption output) {
jjsOptions.setOutput(output);
}
public void setRunAsyncEnabled(boolean enabled) {
jjsOptions.setRunAsyncEnabled(enabled);
}
public void setSoycEnabled(boolean enabled) {
jjsOptions.setSoycEnabled(enabled);
}
public void setSoycExtra(boolean soycExtra) {
jjsOptions.setSoycExtra(soycExtra);
}
public void setStrict(boolean strict) {
jjsOptions.setStrict(strict);
}
public void setValidateOnly(boolean validateOnly) {
this.validateOnly = validateOnly;
}
}
private static class DistillerRebindPermutationOracle implements
RebindPermutationOracle {
private CompilationState compilationState;
private StandardGeneratorContext generatorContext;
private final Permutation[] permutations;
private final StaticPropertyOracle[] propertyOracles;
private final RebindOracle[] rebindOracles;
public DistillerRebindPermutationOracle(ModuleDef module,
CompilationState compilationState, ArtifactSet generatorArtifacts,
PropertyPermutations perms, File genDir) {
this.compilationState = compilationState;
permutations = new Permutation[perms.size()];
propertyOracles = new StaticPropertyOracle[perms.size()];
rebindOracles = new RebindOracle[perms.size()];
generatorContext = new StandardGeneratorContext(compilationState, module,
genDir, generatorArtifacts);
BindingProperty[] orderedProps = perms.getOrderedProperties();
SortedSet<ConfigurationProperty> configPropSet = module.getProperties().getConfigurationProperties();
ConfigurationProperty[] configProps = configPropSet.toArray(new ConfigurationProperty[configPropSet.size()]);
Rules rules = module.getRules();
for (int i = 0; i < rebindOracles.length; ++i) {
String[] orderedPropValues = perms.getOrderedPropertyValues(i);
propertyOracles[i] = new StaticPropertyOracle(orderedProps,
orderedPropValues, configProps);
rebindOracles[i] = new StandardRebindOracle(propertyOracles[i], rules,
generatorContext);
permutations[i] = new Permutation(i, propertyOracles[i]);
}
}
public void clear() {
generatorContext.clear();
compilationState = null;
generatorContext = null;
}
public String[] getAllPossibleRebindAnswers(TreeLogger logger,
String requestTypeName) throws UnableToCompleteException {
String msg = "Computing all possible rebind results for '"
+ requestTypeName + "'";
logger = logger.branch(TreeLogger.DEBUG, msg, null);
Set<String> answers = new HashSet<String>();
Event getAllRebindsEvent = SpeedTracerLogger.start(CompilerEventType.GET_ALL_REBINDS);
for (int i = 0; i < getPermuationCount(); ++i) {
String resultTypeName = rebindOracles[i].rebind(logger, requestTypeName);
answers.add(resultTypeName);
// Record the correct answer into each permutation.
permutations[i].putRebindAnswer(requestTypeName, resultTypeName);
}
String[] result = Util.toArray(String.class, answers);
getAllRebindsEvent.end();
return result;
}
public CompilationState getCompilationState() {
return compilationState;
}
public StandardGeneratorContext getGeneratorContext() {
return generatorContext;
}
public int getPermuationCount() {
return rebindOracles.length;
}
public Permutation[] getPermutations() {
return permutations;
}
public StaticPropertyOracle getPropertyOracle(int permNumber) {
return propertyOracles[permNumber];
}
public RebindOracle getRebindOracle(int permNumber) {
return rebindOracles[permNumber];
}
}
/**
* Creates a Graphics2D context in a thread in order to go ahead and get first
* time initialization out of the way. Delays ranging from 200ms to 6s have
* been observed when initializing the library.
*/
private static class GraphicsInitThread extends Thread {
public GraphicsInitThread() {
// We don't care if the program finishes before the initialization ends.
setDaemon(true);
}
public void run() {
SpeedTracerLogger.Event createGraphicsEvent = SpeedTracerLogger.start(
CompilerEventType.GRAPHICS_INIT, "java.awt.headless",
System.getProperty("java.awt.headless"));
GraphicsEnvironment.getLocalGraphicsEnvironment();
createGraphicsEvent.end();
}
};
/**
* The file name for the result of Precompile.
*/
public static final String PRECOMPILE_FILENAME = "precompilation.ser";
static final String PERM_COUNT_FILENAME = "permCount.txt";
/**
* Performs a command-line precompile.
*/
public static void main(String[] args) {
Memory.initialize();
SpeedTracerLogger.init();
Event precompileEvent = SpeedTracerLogger.start(CompilerEventType.PRECOMPILE);
if (System.getProperty("gwt.jjs.dumpAst") != null) {
System.out.println("Will dump AST to: "
+ System.getProperty("gwt.jjs.dumpAst"));
}
/*
* NOTE: main always exits with a call to System.exit to terminate any
* non-daemon threads that were started in Generators. Typically, this is to
* shutdown AWT related threads, since the contract for their termination is
* still implementation-dependent.
*/
final PrecompileOptions options = new PrecompileOptionsImpl();
boolean success = false;
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
public boolean run(TreeLogger logger) throws UnableToCompleteException {
FutureTask<UpdateResult> updater = null;
if (!options.isUpdateCheckDisabled()) {
updater = CheckForUpdates.checkForUpdatesInBackgroundThread(logger,
CheckForUpdates.ONE_DAY);
}
boolean success = new Precompile(options).run(logger);
if (success) {
CheckForUpdates.logUpdateAvailable(logger, updater);
}
return success;
}
};
if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
// Exit w/ success code.
success = true;
}
}
precompileEvent.end();
System.exit(success ? 0 : 1);
}
/**
* Precompiles the given module.
*
* @param logger a logger to use
* @param jjsOptions a set of compiler options
* @param module the module to compile
* @param genDir optional directory to dump generated source, may be
* <code>null</code>
* @return the precompilation
*/
public static Precompilation precompile(TreeLogger logger,
JJSOptions jjsOptions, ModuleDef module, File genDir) {
PropertyPermutations allPermutations = new PropertyPermutations(
module.getProperties(), module.getActiveLinkerNames());
return precompile(logger, jjsOptions, module, 0, allPermutations, genDir);
}
/**
* Validates the given module can be compiled.
*
* @param logger a logger to use
* @param jjsOptions a set of compiler options
* @param module the module to compile
* @param genDir optional directory to dump generated source, may be
* <code>null</code>
*/
public static boolean validate(TreeLogger logger, JJSOptions jjsOptions,
ModuleDef module, File genDir) {
Event validateEvent = SpeedTracerLogger.start(CompilerEventType.VALIDATE);
try {
CompilationState compilationState = module.getCompilationState(logger);
if (jjsOptions.isStrict() && compilationState.hasErrors()) {
abortDueToStrictMode(logger);
}
String[] declEntryPts = module.getEntryPointTypeNames();
String[] additionalRootTypes = null;
if (declEntryPts.length == 0) {
// No declared entry points, just validate all visible classes.
Collection<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
additionalRootTypes = new String[compilationUnits.size()];
int i = 0;
for (CompilationUnit unit : compilationUnits) {
additionalRootTypes[i++] = unit.getTypeName();
}
}
ArtifactSet generatorArtifacts = new ArtifactSet();
DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
module, compilationState, generatorArtifacts,
new PropertyPermutations(module.getProperties(),
module.getActiveLinkerNames()), genDir);
// Allow GC later.
compilationState = null;
// Never optimize on a validation run.
jjsOptions.setOptimizePrecompile(false);
getCompiler(module).precompile(logger, module, rpo, declEntryPts,
additionalRootTypes, jjsOptions, true);
return true;
} catch (UnableToCompleteException e) {
// Already logged.
return false;
} finally {
validateEvent.end();
}
}
static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions,
ModuleDef module, int permutationBase,
PropertyPermutations allPermutations, File genDir) {
Event precompileEvent = SpeedTracerLogger.start(CompilerEventType.PRECOMPILE);
// This initializes the Java2D library in a thread so that the main program
// doesn't block when the library is accessed for the first time.
new GraphicsInitThread().start();
try {
CompilationState compilationState = module.getCompilationState(logger);
if (jjsOptions.isStrict() && compilationState.hasErrors()) {
abortDueToStrictMode(logger);
}
String[] declEntryPts = module.getEntryPointTypeNames();
if (declEntryPts.length == 0) {
logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
throw new UnableToCompleteException();
}
ArtifactSet generatedArtifacts = new ArtifactSet();
DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
module, compilationState, generatedArtifacts, allPermutations, genDir);
// Allow GC later.
compilationState = null;
UnifiedAst unifiedAst = getCompiler(module).precompile(logger, module,
rpo, declEntryPts, null, jjsOptions, rpo.getPermuationCount() == 1);
// Merge all identical permutations together.
List<Permutation> permutations = new ArrayList<Permutation>(
Arrays.asList(rpo.getPermutations()));
mergeCollapsedPermutations(permutations);
// Sort the permutations by an ordered key to ensure determinism.
SortedMap<RebindAnswersPermutationKey, Permutation> merged = new TreeMap<RebindAnswersPermutationKey, Permutation>();
SortedSet<String> liveRebindRequests = unifiedAst.getRebindRequests();
for (Permutation permutation : permutations) {
// Construct a key for the live rebind answers.
RebindAnswersPermutationKey key = new RebindAnswersPermutationKey(
permutation, liveRebindRequests);
if (merged.containsKey(key)) {
Permutation existing = merged.get(key);
existing.mergeFrom(permutation, liveRebindRequests);
} else {
merged.put(key, permutation);
}
}
return new Precompilation(unifiedAst, merged.values(), permutationBase,
generatedArtifacts);
} catch (UnableToCompleteException e) {
// We intentionally don't pass in the exception here since the real
// cause has been logged.
return null;
} finally {
precompileEvent.end();
}
}
private static void abortDueToStrictMode(TreeLogger logger)
throws UnableToCompleteException {
logger.log(TreeLogger.ERROR,
"Aborting compile due to errors in some input files");
throw new UnableToCompleteException();
}
private static AbstractCompiler getCompiler(ModuleDef module) {
ConfigurationProperty compilerClassProp = module.getProperties().createConfiguration(
"x.compiler.class", false);
String compilerClassName = compilerClassProp.getValue();
if (compilerClassName == null || compilerClassName.length() == 0) {
return new JavaScriptCompiler();
}
Throwable caught;
try {
Class<?> compilerClass = Class.forName(compilerClassName);
return (AbstractCompiler) compilerClass.newInstance();
} catch (ClassNotFoundException e) {
caught = e;
} catch (InstantiationException e) {
caught = e;
} catch (IllegalAccessException e) {
caught = e;
}
throw new RuntimeException("Unable to instantiate compiler class '"
+ compilerClassName + "'", caught);
}
/**
* This merges Permutations that can be considered equivalent by considering
* their collapsed properties. The list passed into this method may have
* elements removed from it.
*/
private static void mergeCollapsedPermutations(List<Permutation> permutations) {
if (permutations.size() < 2) {
return;
}
// See the doc for CollapsedPropertyKey
SortedMap<CollapsedPropertyKey, List<Permutation>> mergedByCollapsedProperties = new TreeMap<CollapsedPropertyKey, List<Permutation>>();
// This loop creates the equivalence sets
for (Iterator<Permutation> it = permutations.iterator(); it.hasNext();) {
Permutation entry = it.next();
CollapsedPropertyKey key = new CollapsedPropertyKey(entry);
List<Permutation> equivalenceSet = mergedByCollapsedProperties.get(key);
if (equivalenceSet == null) {
equivalenceSet = Lists.create();
} else {
// Mutate list
it.remove();
equivalenceSet = Lists.add(equivalenceSet, entry);
}
mergedByCollapsedProperties.put(key, equivalenceSet);
}
// This loop merges the Permutations together
for (Map.Entry<CollapsedPropertyKey, List<Permutation>> entry : mergedByCollapsedProperties.entrySet()) {
Permutation mergeInto = entry.getKey().getPermutation();
/*
* Merge the deferred-binding properties once we no longer need the
* PropertyOracle data from the extra permutations.
*/
for (Permutation mergeFrom : entry.getValue()) {
mergeInto.mergeRebindsFromCollapsed(mergeFrom);
}
}
// Renumber the Permutations
for (int i = 0, j = permutations.size(); i < j; i++) {
permutations.set(i, new Permutation(i, permutations.get(i)));
}
}
private final PrecompileOptionsImpl options;
public Precompile(PrecompileOptions options) {
this.options = new PrecompileOptionsImpl(options);
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
// Avoid early optimizations since permutation compiles will run separately.
options.setOptimizePrecompile(false);
for (String moduleName : options.getModuleNames()) {
File compilerWorkDir = options.getCompilerWorkDir(moduleName);
Util.recursiveDelete(compilerWorkDir, true);
// No need to check mkdirs result because an IOException will occur anyway
compilerWorkDir.mkdirs();
File precompilationFile = new File(compilerWorkDir, PRECOMPILE_FILENAME);
ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);
StandardLinkerContext linkerContext = new StandardLinkerContext(
TreeLogger.NULL, module, options);
boolean generateOnShards = true;
if (!options.isEnabledGeneratingOnShards()) {
logger.log(TreeLogger.INFO, "Precompiling on the start node");
generateOnShards = false;
} else if (!linkerContext.allLinkersAreShardable()) {
TreeLogger legacyLinkersLogger = logger.branch(TreeLogger.INFO,
"Precompiling on the start node, because some linkers are not updated");
for (Linker linker : linkerContext.findUnshardableLinkers()) {
legacyLinkersLogger.log(TreeLogger.INFO, "Linker"
+ linker.getClass().getCanonicalName() + " is not updated");
}
generateOnShards = false;
} else if (options.isValidateOnly()) {
// Don't bother running on shards for just a validation run
generateOnShards = false;
}
if (generateOnShards) {
/*
* Pre-precompile. Count the permutations and plan to do a real
* precompile in the CompilePerms shards.
*/
TreeLogger branch = logger.branch(TreeLogger.INFO,
"Precompiling (minimal) module " + module.getName());
Util.writeObjectAsFile(logger, precompilationFile, options);
int numPermutations = new PropertyPermutations(module.getProperties(),
module.getActiveLinkerNames()).collapseProperties().size();
Util.writeStringAsFile(logger, new File(compilerWorkDir,
PERM_COUNT_FILENAME), String.valueOf(numPermutations));
branch.log(TreeLogger.INFO,
"Precompilation (minimal) succeeded, number of permutations: "
+ numPermutations);
} else {
if (options.isValidateOnly()) {
TreeLogger branch = logger.branch(TreeLogger.INFO,
"Validating compilation " + module.getName());
if (!validate(branch, options, module, options.getGenDir())) {
branch.log(TreeLogger.ERROR, "Validation failed");
return false;
}
branch.log(TreeLogger.INFO, "Validation succeeded");
} else {
TreeLogger branch = logger.branch(TreeLogger.INFO,
"Precompiling module " + module.getName());
Precompilation precompilation = precompile(branch, options, module,
options.getGenDir());
if (precompilation == null) {
branch.log(TreeLogger.ERROR, "Precompilation failed");
return false;
}
Util.writeObjectAsFile(logger, precompilationFile, precompilation);
int permsPrecompiled = precompilation.getPermutations().length;
Util.writeStringAsFile(logger, new File(compilerWorkDir,
PERM_COUNT_FILENAME), String.valueOf(permsPrecompiled));
branch.log(TreeLogger.INFO,
"Precompilation succeeded, number of permutations: "
+ permsPrecompiled);
}
}
}
return true;
}
}