Moved the sketch building code from Sketch to Compiler.

This commit is contained in:
Claudio Indellicati 2014-08-22 15:22:12 +02:00 committed by Cristian Maglie
parent b7d1846eb9
commit afbbe77752
2 changed files with 181 additions and 174 deletions

View File

@ -26,13 +26,12 @@ package processing.app;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.UploaderAndMonitorFactory;
import cc.arduino.packages.Uploader;
import processing.app.debug.*;
import processing.app.debug.Compiler;
import processing.app.debug.Compiler.ProgressListener;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform;
import processing.app.forms.PasswordAuthorizationDialog;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.FileUtils;
import processing.app.packages.Library;
import static processing.app.I18n._;
@ -61,12 +60,6 @@ public class Sketch {
/** Class name for the PApplet, as determined by the preprocessor. */
private String appletClassName;
/**
* File inside the build directory that contains the build options
* used for the last build.
*/
static final String BUILD_PREFS_FILE = "buildprefs.txt";
/**
* path is location of the main .pde file, because this is also
* simplest to use when opening the file from the finder/explorer.
@ -1017,48 +1010,6 @@ public class Sketch {
}
/**
* Cleanup temporary files used during a build/run.
*/
protected void cleanup(boolean force) {
// if the java runtime is holding onto any files in the build dir, we
// won't be able to delete them, so we need to force a gc here
System.gc();
if (force) {
// delete the entire directory and all contents
// when we know something changed and all objects
// need to be recompiled, or if the board does not
// use setting build.dependency
//Base.removeDir(tempBuildFolder);
// note that we can't remove the builddir itself, otherwise
// the next time we start up, internal runs using Runner won't
// work because the build dir won't exist at startup, so the classloader
// will ignore the fact that that dir is in the CLASSPATH in run.sh
Base.removeDescendants(tempBuildFolder);
} else {
// delete only stale source files, from the previously
// compiled sketch. This allows multiple windows to be
// used. Keep everything else, which might be reusable
if (tempBuildFolder.exists()) {
String files[] = tempBuildFolder.list();
for (String file : files) {
if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".s")) {
File deleteMe = new File(tempBuildFolder, file);
if (!deleteMe.delete()) {
System.err.println("Could not delete " + deleteMe);
}
}
}
}
}
// Create a fresh applet folder (needed before preproc is run below)
//tempBuildFolder.mkdirs();
}
/**
* Preprocess, Compile, and Run the current code.
* <P>
@ -1180,47 +1131,6 @@ public class Sketch {
return build(tempBuildFolder.getAbsolutePath(), verbose);
}
/**
* Check if the build preferences used on the previous build in
* buildPath match the ones given.
*/
protected boolean buildPreferencesChanged(File buildPrefsFile, String newBuildPrefs) {
// No previous build, so no match
if (!buildPrefsFile.exists())
return true;
String previousPrefs;
try {
previousPrefs = FileUtils.readFileToString(buildPrefsFile);
} catch (IOException e) {
System.err.println(_("Could not read prevous build preferences file, rebuilding all"));
return true;
}
if (!previousPrefs.equals(newBuildPrefs)) {
System.out.println(_("Build options changed, rebuilding all"));
return true;
} else {
return false;
}
}
/**
* Returns the build preferences of the given compiler as a string.
* Only includes build-specific preferences, to make sure unrelated
* preferences don't cause a rebuild (in particular preferences that
* change on every start, like last.ide.xxx.daterun). */
protected String buildPrefsString(Compiler compiler) {
PreferencesMap buildPrefs = compiler.getBuildPreferences();
String res = "";
SortedSet<String> treeSet = new TreeSet<String>(buildPrefs.keySet());
for (String k : treeSet) {
if (k.startsWith("build.") || k.startsWith("compiler.") || k.startsWith("recipes."))
res += k + " = " + buildPrefs.get(k) + "\n";
}
return res;
}
/**
* Preprocess and compile all the code for this sketch.
*
@ -1231,45 +1141,19 @@ public class Sketch {
* @return null if compilation failed, main class name if not
*/
public String build(String buildPath, boolean verbose) throws RunnerException {
String primaryClassName = data.getName() + ".cpp";
Compiler compiler = new Compiler(data, buildPath, primaryClassName);
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
String newBuildPrefs = buildPrefsString(compiler);
// Do a forced cleanup (throw everything away) if the previous
// build settings do not match the previous ones
boolean prefsChanged = buildPreferencesChanged(buildPrefsFile, newBuildPrefs);
cleanup(prefsChanged);
if (prefsChanged) {
try {
PrintWriter out = new PrintWriter(buildPrefsFile);
out.print(newBuildPrefs);
out.close();
} catch (IOException e) {
System.err.println(_("Could not write build preferences file"));
}
}
// run the preprocessor
editor.status.progressUpdate(20);
ensureExistence();
compiler.setProgressListener(new ProgressListener() {
ProgressListener pl = new ProgressListener() {
@Override
public void progress(int percent) {
editor.status.progressUpdate(percent);
}
});
};
// compile the program. errors will happen as a RunnerException
// that will bubble up to whomever called build().
if (compiler.compile(verbose)) {
size(compiler.getBuildPreferences());
return primaryClassName;
}
return null;
return Compiler.build(data, buildPath, tempBuildFolder, pl, verbose);
}
protected boolean exportApplet(boolean usingProgrammer) throws Exception {
@ -1307,58 +1191,6 @@ public class Sketch {
}
protected void size(PreferencesMap prefs) throws RunnerException {
String maxTextSizeString = prefs.get("upload.maximum_size");
String maxDataSizeString = prefs.get("upload.maximum_data_size");
if (maxTextSizeString == null)
return;
long maxTextSize = Integer.parseInt(maxTextSizeString);
long maxDataSize = -1;
if (maxDataSizeString != null)
maxDataSize = Integer.parseInt(maxDataSizeString);
Sizer sizer = new Sizer(prefs);
long[] sizes;
try {
sizes = sizer.computeSize();
} catch (RunnerException e) {
System.err.println(I18n.format(_("Couldn't determine program size: {0}"),
e.getMessage()));
return;
}
long textSize = sizes[0];
long dataSize = sizes[1];
System.out.println();
System.out.println(I18n
.format(_("Sketch uses {0} bytes ({2}%%) of program storage space. Maximum is {1} bytes."),
textSize, maxTextSize, textSize * 100 / maxTextSize));
if (dataSize >= 0) {
if (maxDataSize > 0) {
System.out
.println(I18n
.format(
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
maxDataSize - dataSize));
} else {
System.out.println(I18n
.format(_("Global variables use {0} bytes of dynamic memory."), dataSize));
}
}
if (textSize > maxTextSize)
throw new RunnerException(
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
if (maxDataSize > 0 && dataSize > maxDataSize)
throw new RunnerException(
_("Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint."));
int warnDataPercentage = Integer.parseInt(prefs.get("build.warn_data_percentage"));
if (maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100)
System.err.println(_("Low memory available, stability problems may occur."));
}
protected boolean upload(String buildPath, String suggestedClassName, boolean usingProgrammer) throws Exception {
TargetPlatform target = Base.getTargetPlatform();

View File

@ -31,10 +31,13 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import processing.app.Base;
import processing.app.BaseNoGui;
@ -54,6 +57,12 @@ import processing.app.legacy.PApplet;
public class Compiler implements MessageConsumer {
/**
* File inside the build directory that contains the build options
* used for the last build.
*/
static final public String BUILD_PREFS_FILE = "buildprefs.txt";
private SketchData sketch;
private PreferencesMap prefs;
private boolean verbose;
@ -73,6 +82,38 @@ public class Compiler implements MessageConsumer {
private ProgressListener progressListener;
static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose) throws RunnerException {
String primaryClassName = data.getName() + ".cpp";
Compiler compiler = new Compiler(data, buildPath, primaryClassName);
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
String newBuildPrefs = compiler.buildPrefsString();
// Do a forced cleanup (throw everything away) if the previous
// build settings do not match the previous ones
boolean prefsChanged = compiler.buildPreferencesChanged(buildPrefsFile, newBuildPrefs);
compiler.cleanup(prefsChanged, tempBuildFolder);
if (prefsChanged) {
try {
PrintWriter out = new PrintWriter(buildPrefsFile);
out.print(newBuildPrefs);
out.close();
} catch (IOException e) {
System.err.println(_("Could not write build preferences file"));
}
}
compiler.setProgressListener(progListener);
// compile the program. errors will happen as a RunnerException
// that will bubble up to whomever called build().
if (compiler.compile(verbose)) {
compiler.size(compiler.getBuildPreferences());
return primaryClassName;
}
return null;
}
/**
* Create a new Compiler
* @param _sketch Sketch object to be compiled.
@ -92,10 +133,144 @@ public class Compiler implements MessageConsumer {
};
}
public void setProgressListener(ProgressListener _progressListener) {
/**
* Check if the build preferences used on the previous build in
* buildPath match the ones given.
*/
protected boolean buildPreferencesChanged(File buildPrefsFile, String newBuildPrefs) {
// No previous build, so no match
if (!buildPrefsFile.exists())
return true;
String previousPrefs;
try {
previousPrefs = FileUtils.readFileToString(buildPrefsFile);
} catch (IOException e) {
System.err.println(_("Could not read prevous build preferences file, rebuilding all"));
return true;
}
if (!previousPrefs.equals(newBuildPrefs)) {
System.out.println(_("Build options changed, rebuilding all"));
return true;
} else {
return false;
}
}
/**
* Returns the build preferences of the given compiler as a string.
* Only includes build-specific preferences, to make sure unrelated
* preferences don't cause a rebuild (in particular preferences that
* change on every start, like last.ide.xxx.daterun). */
protected String buildPrefsString() {
PreferencesMap buildPrefs = getBuildPreferences();
String res = "";
SortedSet<String> treeSet = new TreeSet<String>(buildPrefs.keySet());
for (String k : treeSet) {
if (k.startsWith("build.") || k.startsWith("compiler.") || k.startsWith("recipes."))
res += k + " = " + buildPrefs.get(k) + "\n";
}
return res;
}
protected void setProgressListener(ProgressListener _progressListener) {
progressListener = _progressListener;
}
/**
* Cleanup temporary files used during a build/run.
*/
protected void cleanup(boolean force, File tempBuildFolder) {
// if the java runtime is holding onto any files in the build dir, we
// won't be able to delete them, so we need to force a gc here
System.gc();
if (force) {
// delete the entire directory and all contents
// when we know something changed and all objects
// need to be recompiled, or if the board does not
// use setting build.dependency
//Base.removeDir(tempBuildFolder);
// note that we can't remove the builddir itself, otherwise
// the next time we start up, internal runs using Runner won't
// work because the build dir won't exist at startup, so the classloader
// will ignore the fact that that dir is in the CLASSPATH in run.sh
Base.removeDescendants(tempBuildFolder);
} else {
// delete only stale source files, from the previously
// compiled sketch. This allows multiple windows to be
// used. Keep everything else, which might be reusable
if (tempBuildFolder.exists()) {
String files[] = tempBuildFolder.list();
for (String file : files) {
if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".s")) {
File deleteMe = new File(tempBuildFolder, file);
if (!deleteMe.delete()) {
System.err.println("Could not delete " + deleteMe);
}
}
}
}
}
// Create a fresh applet folder (needed before preproc is run below)
//tempBuildFolder.mkdirs();
}
protected void size(PreferencesMap prefs) throws RunnerException {
String maxTextSizeString = prefs.get("upload.maximum_size");
String maxDataSizeString = prefs.get("upload.maximum_data_size");
if (maxTextSizeString == null)
return;
long maxTextSize = Integer.parseInt(maxTextSizeString);
long maxDataSize = -1;
if (maxDataSizeString != null)
maxDataSize = Integer.parseInt(maxDataSizeString);
Sizer sizer = new Sizer(prefs);
long[] sizes;
try {
sizes = sizer.computeSize();
} catch (RunnerException e) {
System.err.println(I18n.format(_("Couldn't determine program size: {0}"),
e.getMessage()));
return;
}
long textSize = sizes[0];
long dataSize = sizes[1];
System.out.println();
System.out.println(I18n
.format(_("Sketch uses {0} bytes ({2}%%) of program storage space. Maximum is {1} bytes."),
textSize, maxTextSize, textSize * 100 / maxTextSize));
if (dataSize >= 0) {
if (maxDataSize > 0) {
System.out
.println(I18n
.format(
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
maxDataSize - dataSize));
} else {
System.out.println(I18n
.format(_("Global variables use {0} bytes of dynamic memory."), dataSize));
}
}
if (textSize > maxTextSize)
throw new RunnerException(
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
if (maxDataSize > 0 && dataSize > maxDataSize)
throw new RunnerException(
_("Not enough memory; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing your footprint."));
int warnDataPercentage = Integer.parseInt(prefs.get("build.warn_data_percentage"));
if (maxDataSize > 0 && dataSize > maxDataSize*warnDataPercentage/100)
System.err.println(_("Low memory available, stability problems may occur."));
}
/**
* Compile sketch.
* @param buildPath