/*
* 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.ModuleMetricsArtifact;
import com.google.gwt.core.ext.linker.PrecompilationMetricsArtifact;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
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.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationUnit;
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.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.ArgHandlerCompilerMetrics;
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.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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));
registerHandler(new ArgHandlerCompilerMetrics(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 isCompilerMetricsEnabled() {
return jjsOptions.isCompilerMetricsEnabled();
}
public boolean isDraftCompile() {
return jjsOptions.isDraftCompile();
}
public boolean isEnableAssertions() {
return jjsOptions.isEnableAssertions();
}
public boolean isEnabledGeneratingOnShards() {
return enableGeneratingOnShards;
}
public boolean isGeneratorResultCachingEnabled() {
return jjsOptions.isGeneratorResultCachingEnabled();
}
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 setCompilerMetricsEnabled(boolean enabled) {
jjsOptions.setCompilerMetricsEnabled(enabled);
}
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 setGeneratorResultCachingEnabled(boolean enabled) {
jjsOptions.setGeneratorResultCachingEnabled(enabled);
}
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;
}
}
/**
* 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);
}
@Override
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 max number of permutations output as plain text.
*/
static final String PERM_COUNT_FILENAME = "permCount.txt";
static final String PRECOMPILE_FILENAME = Precompile.PRECOMPILE_FILENAME_PREFIX
+ Precompile.PRECOMPILE_FILENAME_SUFFIX;
/**
* The file name for the serialized AST artifact from the Precompile step.
* Sometimes this file is overloaded and only contains a PrecompileOptions
* object to indicate that precompilation should run inside the CompilePerms
* step.
*/
static final String PRECOMPILE_FILENAME_PREFIX = "precompilation";
static final String PRECOMPILE_FILENAME_SUFFIX = ".ser";
/**
* 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, null);
return true;
} catch (UnableToCompleteException e) {
// Already logged.
return false;
} finally {
validateEvent.end();
}
}
/**
* Create a list of all possible permutations configured for this module after
* collapsing soft permutations.
*/
static List<PropertyPermutations> getCollapsedPermutations(ModuleDef module) {
PropertyPermutations allPermutations =
new PropertyPermutations(module.getProperties(), module.getActiveLinkerNames());
List<PropertyPermutations> collapsedPermutations = allPermutations.collapseProperties();
return collapsedPermutations;
}
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);
}
static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions, ModuleDef module,
int permutationBase, PropertyPermutations allPermutations, File genDir) {
return precompile(logger, jjsOptions, module, permutationBase, allPermutations, genDir,
ManagementFactory.getRuntimeMXBean().getStartTime());
}
static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions, ModuleDef module,
int permutationBase, PropertyPermutations allPermutations, File genDir,
long startTimeMilliseconds) {
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);
}
List<String> initialTypeOracleTypes = new ArrayList<String>();
if (jjsOptions.isCompilerMetricsEnabled()) {
for (JClassType type : compilationState.getTypeOracle().getTypes()) {
initialTypeOracleTypes.add(type.getPackage().getName() + "." + type.getName());
}
}
// Track information about the module load including initial type
// oracle build for diagnostic purposes.
long moduleLoadFinished = System.currentTimeMillis();
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;
PrecompilationMetricsArtifact precompilationMetrics =
jjsOptions.isCompilerMetricsEnabled()
? new PrecompilationMetricsArtifact(permutationBase) : null;
UnifiedAst unifiedAst =
getCompiler(module).precompile(logger, module, rpo, declEntryPts, null, jjsOptions,
rpo.getPermuationCount() == 1, precompilationMetrics);
if (jjsOptions.isCompilerMetricsEnabled()) {
ModuleMetricsArtifact moduleMetrics = new ModuleMetricsArtifact();
moduleMetrics.setSourceFiles(module.getAllSourceFiles());
// The initial type list has to be gathered before the call to
// precompile().
moduleMetrics.setInitialTypes(initialTypeOracleTypes);
// The elapsed time in ModuleMetricsArtifact represents time
// which could be done once for all permutations.
moduleMetrics.setElapsedMilliseconds(moduleLoadFinished - startTimeMilliseconds);
unifiedAst.setModuleMetrics(moduleMetrics);
}
// 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);
}
}
if (jjsOptions.isCompilerMetricsEnabled()) {
int[] ids = new int[allPermutations.size()];
for (int i = 0; i < allPermutations.size(); i++) {
ids[i] = permutationBase + i;
}
precompilationMetrics.setPermuationIds(ids);
// TODO(zundel): Right now this double counts module load and
// precompile time. It correctly counts the amount of time spent
// in this process. The elapsed time in ModuleMetricsArtifact
// represents time which could be done once for all permutations.
precompilationMetrics.setElapsedMilliseconds(System.currentTimeMillis()
- startTimeMilliseconds);
unifiedAst.setPrecompilationMetrics(precompilationMetrics);
}
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();
}
/**
* 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;
}
}