cleaning up Compiler, and finalizing release 0140 to include all the

changes
This commit is contained in:
benfry
2008-06-10 18:37:03 +00:00
parent 0ea5de77c7
commit f6022daacc
7 changed files with 125 additions and 509 deletions

View File

@@ -35,8 +35,6 @@ import java.util.zip.*;
import javax.swing.*;
//import com.oroinc.text.regex.*;
/**
* Stores information about files in the current sketch

View File

@@ -4,7 +4,7 @@
Compiler - default compiler class that connects to jikes
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,6 @@
package processing.app.debug;
import processing.app.Base;
import processing.app.Preferences;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.core.*;
@@ -35,86 +34,29 @@ import java.util.*;
import java.util.zip.*;
public class Compiler implements MessageConsumer {
static final String BUGS_URL =
"http://processing.org/bugs/";
static final String SUPER_BADNESS =
"Compiler error, please submit this code to " + BUGS_URL;
Sketch sketch;
String buildPath;
//String buildPath;
//String className;
//File includeFolder;
RunnerException exception;
//Editor editor;
/*
public Compiler(String buildPath, String className,
File includeFolder, Editor editor) {
this.buildPath = buildPath;
this.includeFolder = includeFolder;
this.className = className;
this.editor = editor;
}
public boolean compile(PrintStream leechErr) {
*/
public Compiler() { } // consider this a warning, you werkin soon.
public class Compiler {
/**
* Fire up 'ole javac based on
* <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javac.html#proginterface">this interface</a>.
* Fire up 'ole javac based on <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/javac.html#proginterface">this interface</a>.
*
* @param sketch
* @param buildPath
* @param sketch Sketch object to be compiled.
* @param buildPath Where the temporary files live and will be built from.
* @return
* @throws RunnerException
* @throws RunnerException Only if there's a problem. Only then.
*/
public boolean compile(Sketch sketch,
String buildPath) throws RunnerException {
// com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
// This will be filled in if anyone gets angry
RunnerException exception = null;
this.sketch = sketch;
this.buildPath = buildPath;
String baseCommand[] = new String[] {
// this doesn't help much.. also java 1.4 seems to not support
// -source 1.1 for javac, and jikes seems to also have dropped it.
// for versions of jikes that don't complain, "final int" inside
// a function doesn't throw an error, so it could just be a
// ms jvm error that this sort of thing doesn't work. blech.
//"-source",
//"1.1",
// necessary to make output classes compatible with 1.1
// i.e. so that exported applets can work with ms jvm on the web
// "-target",
// Preferences.get("preproc.jdk_version"), //"1.1",
// let the incompatibility headache begin
// for javac, we'll shut these off, and hope for the best so that ppl
// can use 1.5 code inside .java tabs
// used when run without a vm ("expert" mode)
// "-bootclasspath",
// calcBootClassPath(),
// with javac, let's try and trust the system to do the right thing
"-classpath", sketch.getClassPath(),
"-nowarn", // we're not currently interested in warnings
//"+E", // output errors in machine-parsable format
// @#$)(*@#$ why doesn't javac have this option?
"-d", buildPath // output the classes in the buildPath
//buildPath + File.separator + className + ".java" // file to compile
"-source", "1.5",
"-target", "1.5",
"-classpath", sketch.getClassPath(),
"-nowarn", // we're not currently interested in warnings (ignored?)
"-d", buildPath // output the classes in the buildPath
};
// PApplet.println(baseCommand);
//PApplet.println(baseCommand);
// make list of code files that need to be compiled
// (some files are skipped if they contain no class)
@@ -134,9 +76,6 @@ public class Compiler implements MessageConsumer {
}
//PApplet.println(command);
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
int result = -1; // needs to be set bad by default, in case hits IOE below
try {
@@ -225,42 +164,25 @@ public class Compiler implements MessageConsumer {
} else {
exception = new RunnerException(errorMessage);
}
if (exception != null) throw exception;
}
}
} catch (IOException e) {
String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
exception = new RunnerException(bigSigh);
e.printStackTrace();
result = 1;
}
// an error was queued up by message(), barf this back to build()
// which will barf it back to Editor. if you're having trouble
// discerning the imagery, consider how cows regurgitate their food
// to digest it, and the fact that they have five stomaches.
//
//System.out.println("throwing up " + exception);
// if (exception != null) throw exception;
// In case there was something else.
if (exception != null) throw exception;
// if the result isn't a known, expected value it means that something
// is fairly wrong, one possibility is that jikes has crashed.
//
// if (result != 0 && result != 1 ) {
// Base.openURL(BUGS_URL);
// throw new RunnerException(SUPER_BADNESS);
// }
// success would mean that 'result' is set to zero
return (result == 0); // ? true : false;
// Success means that 'result' is set to zero
return (result == 0);
}
/// tell-tale signs of code copied and pasted from the web
// detect classes BFont, BGraphics, BImage
// or methods framerate, push
// and variables LINE_LOOP and LINE_STRIP
// Tell-tale signs of old code copied and pasted from the web.
// Detect classes BFont, BGraphics, BImage; methods framerate, push;
// and variables LINE_LOOP and LINE_STRIP.
static HashMap crusties = new HashMap();
static {
crusties.put("BFont", new Object());
@@ -271,8 +193,8 @@ public class Compiler implements MessageConsumer {
crusties.put("LINE_LOOP", new Object());
crusties.put("LINE_STRIP", new Object());
}
void handleCannotFindSymbol(BufferedReader reader,
RunnerException rex) throws IOException {
String symbolLine = reader.readLine();
@@ -334,360 +256,9 @@ public class Compiler implements MessageConsumer {
protected int caretColumn(String caretLine) {
return caretLine.indexOf("^");
}
// protected RunnerException fillException(String message, String reportLine) {
// iterate through the project files to see who's causing the trouble
public boolean compileJikes(Sketch sketch, String buildPath)
throws RunnerException {
this.sketch = sketch;
this.buildPath = buildPath;
// the pms object isn't used for anything but storage
/*MessageStream pms =*/ //new MessageStream(this);
String baseCommand[] = new String[] {
// user.dir is folder containing P5 (and therefore jikes)
// macosx needs the extra path info. linux doesn't like it, though
// windows doesn't seem to care. write once, headache anywhere.
((!Base.isMacOS()) ? "jikes" :
System.getProperty("user.dir") + File.separator + "jikes"),
// this doesn't help much.. also java 1.4 seems to not support
// -source 1.1 for javac, and jikes seems to also have dropped it.
// for versions of jikes that don't complain, "final int" inside
// a function doesn't throw an error, so it could just be a
// ms jvm error that this sort of thing doesn't work. blech.
//"-source",
//"1.1",
// necessary to make output classes compatible with 1.1
// i.e. so that exported applets can work with ms jvm on the web
"-target",
Preferences.get("preproc.jdk_version"), //"1.1",
// let the incompatability headache begin
// used when run without a vm ("expert" mode)
"-bootclasspath",
calcBootClassPath(),
// needed for macosx so that the classpath is set properly
// also for windows because qtjava will most likely be here
// and for linux, it just doesn't hurt
"-classpath",
//calcClassPath(includeFolder), // removed sometime after 135?
sketch.getClassPath(),
//sketch.getClassPath() + File.pathSeparator + sketch.getLibraryPath(),
"-nowarn", // we're not currently interested in warnings
"+E", // output errors in machine-parsable format
"-d", buildPath // output the classes in the buildPath
//buildPath + File.separator + className + ".java" // file to compile
};
// PApplet.println(baseCommand);
// make list of code files that need to be compiled
// (some files are skipped if they contain no class)
String preprocNames[] = new String[sketch.getCodeCount()];
int preprocCount = 0;
for (int i = 0; i < sketch.getCodeCount(); i++) {
if (sketch.getCode(i).preprocName != null) {
preprocNames[preprocCount++] = sketch.getCode(i).preprocName;
}
}
String command[] = new String[baseCommand.length + preprocCount];
System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
// append each of the files to the command string
for (int i = 0; i < preprocCount; i++) {
command[baseCommand.length + i] =
buildPath + File.separator + preprocNames[i];
}
//PApplet.println(command);
/*
String command[] = new String[baseCommand.length + sketch.codeCount];
System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
// append each of the files to the command string
for (int i = 0; i < sketch.codeCount; i++) {
command[baseCommand.length + i] =
buildPath + File.separator + sketch.code[i].preprocName;
}
*/
//for (int i = 0; i < command.length; i++) {
//System.out.println("cmd " + i + " " + command[i]);
//}
firstErrorFound = false; // haven't found any errors yet
secondErrorFound = false;
int result = 0; // pre-initialized to quiet a bogus warning from jikes
try {
// execute the compiler, and create threads to deal
// with the input and error streams
//
Process process = Runtime.getRuntime().exec(command);
MessageSiphon msi = new MessageSiphon(process.getInputStream(), this);
MessageSiphon mse = new MessageSiphon(process.getErrorStream(), this);
msi.thread.start(); // this is getting reeeally ugly
mse.thread.start();
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
//
boolean compiling = true;
while (compiling) {
try {
result = process.waitFor();
//System.out.println("result is " + result);
compiling = false;
} catch (InterruptedException ignored) { }
}
} catch (Exception e) {
String msg = e.getMessage();
if ((msg != null) && (msg.indexOf("jikes: not found") != -1)) {
//System.err.println("jikes is missing");
Base.showWarning("Compiler error",
"Could not find the compiler.\n" +
"jikes is missing from your PATH,\n" +
"see the troubleshooting page for help.", null);
return false;
} else {
e.printStackTrace();
result = -1;
}
}
// an error was queued up by message(), barf this back to build()
// which will barf it back to Editor. if you're having trouble
// discerning the imagery, consider how cows regurgitate their food
// to digest it, and the fact that they have five stomaches.
//
//System.out.println("throwing up " + exception);
if (exception != null) throw exception;
// if the result isn't a known, expected value it means that something
// is fairly wrong, one possibility is that jikes has crashed.
//
if (result != 0 && result != 1 ) {
//exception = new RunnerException(SUPER_BADNESS);
//editor.error(exception); // this will instead be thrown
Base.openURL(BUGS_URL);
throw new RunnerException(SUPER_BADNESS);
}
// success would mean that 'result' is set to zero
return (result == 0); // ? true : false;
}
boolean firstErrorFound;
boolean secondErrorFound;
/**
* Part of the MessageConsumer interface, this is called
* whenever a piece (usually a line) of error message is spewed
* out from the compiler. The errors are parsed for their contents
* and line number, which is then reported back to Editor.
*/
public void message(String s) {
// This receives messages as full lines, so a newline needs
// to be added as they're printed to the console.
System.err.println(s);
// ignore cautions
if (s.indexOf("Caution") != -1) return;
// jikes always uses a forward slash character as its separator,
// so replace any platform-specific separator characters before
// attemping to compare
//
String buildPathSubst = buildPath.replace(File.separatorChar, '/') + "/";
String partialTempPath = null;
int partialStartIndex = -1; //s.indexOf(partialTempPath);
int fileIndex = -1; // use this to build a better exception
// iterate through the project files to see who's causing the trouble
for (int i = 0; i < sketch.getCodeCount(); i++) {
if (sketch.getCode(i).preprocName == null) continue;
partialTempPath = buildPathSubst + sketch.getCode(i).preprocName;
partialStartIndex = s.indexOf(partialTempPath);
if (partialStartIndex != -1) {
fileIndex = i;
//System.out.println("fileIndex is " + fileIndex);
break;
}
}
//+ className + ".java";
// if the partial temp path appears in the error message...
//
//int partialStartIndex = s.indexOf(partialTempPath);
if (partialStartIndex != -1) {
// skip past the path and parse the int after the first colon
//
String s1 = s.substring(partialStartIndex +
partialTempPath.length() + 1);
int colon = s1.indexOf(':');
int lineNumber = Integer.parseInt(s1.substring(0, colon));
//System.out.println("pde / line number: " + lineNumber);
if (fileIndex == 0) { // main class, figure out which tab
for (int i = 1; i < sketch.getCodeCount(); i++) {
if (sketch.getCode(i).flavor == Sketch.PDE) {
if (sketch.getCode(i).preprocOffset < lineNumber) {
fileIndex = i;
//System.out.println("i'm thinkin file " + i);
}
}
}
if (fileIndex != 0) { // if found another culprit
lineNumber -= sketch.getCode(fileIndex).preprocOffset;
//System.out.println("i'm sayin line " + lineNumber);
}
}
//String s2 = s1.substring(colon + 2);
int err = s1.indexOf("Error:");
if (err != -1) {
// if the first error has already been found, then this must be
// (at least) the second error found
if (firstErrorFound) {
secondErrorFound = true;
return;
}
// if executing at this point, this is *at least* the first error
firstErrorFound = true;
//err += "error:".length();
String description = s1.substring(err + "Error:".length());
description = description.trim();
/*
String hasLoop = "The method \"void loop();\" with default access";
if (description.indexOf(hasLoop) != -1) {
description =
"Rename loop() to draw() in Processing 0070 and higher";
}
*/
String[] oldCodeMessages = new String[] {
"Type \"BFont\" was not found",
"Type \"BGraphics\" was not found",
"Type \"BImage\" was not found",
"No method named \"framerate\"",
"No method named \"push\"",
"No accessible field named \"LINE_LOOP\"",
"No accessible field named \"LINE_STRIP\""
};
for (int i = 0; i < oldCodeMessages.length; i++) {
if (description.indexOf(oldCodeMessages[i]) != -1) {
description = "This code needs to be updated, " +
"please read the changes reference.";
Base.showReference("changes.html");
// only complain once, and break
break;
}
}
String constructorProblem =
"No applicable overload was found for a constructor of type";
if (description.indexOf(constructorProblem) != -1) {
//"simong.particles.ParticleSystem". Perhaps you wanted the overloaded version "ParticleSystem();" instead?
int nextSentence = description.indexOf("\".") + 3;
description = description.substring(nextSentence);
}
String overloadProblem = "No applicable overload";
if (description.indexOf(overloadProblem) != -1) {
int nextSentence = description.indexOf("\".") + 3;
description = description.substring(nextSentence);
}
// c:/fry/processing/build/windows/work/lib/build/Temporary_6858_2476.java:1:34:1:41: Semantic Error: You need to modify your classpath, sourcepath, bootclasspath, and/or extdirs setup. Package "poo/shoe" could not be found in:
String classpathProblem = "You need to modify your classpath";
if (description.indexOf(classpathProblem) != -1) {
if (description.indexOf("quicktime/std") != -1) {
// special case for the quicktime libraries
description =
"To run sketches that use the Processing video library, " +
"you must first install QuickTime for Java.";
} else {
// modified for 0136, why was this different? jikes msgs changed?
//int nextSentence = description.indexOf(". Package") + 2;
int nextSentence = description.indexOf("could not find ") + 1;
description = "C" +
//description.substring(nextSentence, description.indexOf(':')) +
description.substring(nextSentence, description.lastIndexOf('\"') + 1) +
" in the code folder or in any libraries.";
}
}
if ((description.indexOf("\";\" inserted " +
"to complete BlockStatement") != -1) ||
(description.indexOf("; expected instead of this token") != -1)) {
System.err.println(description);
description = "Compiler error, maybe a missing semicolon?";
}
//System.out.println("description = " + description);
//System.out.println("creating exception " + exception);
exception =
new RunnerException(description, fileIndex, lineNumber-1, -1);
// NOTE!! major change here, this exception will be queued
// here to be thrown by the compile() function
//editor.error(exception);
} else {
System.err.println("i suck: " + s);
}
} else {
// this isn't the start of an error line, so don't attempt to parse
// a line number out of it.
// if the second error hasn't been discovered yet, these lines
// are probably associated with the first error message,
// which is already in the status bar, and are likely to be
// of interest to the user, so spit them to the console.
//
if (!secondErrorFound) {
System.err.println(s);
}
}
}
static String bootClassPath;
static public String calcBootClassPath() {
if (bootClassPath == null) {
String additional = "";
if (Base.isMacOS()) {
additional =
contentsToClassPath(new File("/System/Library/Java/Extensions/"));
}
bootClassPath = System.getProperty("sun.boot.class.path") + additional;
}
return bootClassPath;
}
///
/////////////////////////////////////////////////////////////////////////////
/**
@@ -851,31 +422,5 @@ public class Compiler implements MessageConsumer {
}
}
}
//return importCount;
}
/*
static public int magicImportsRecursive(File dir, String sofar,
Hashtable table) {
//String imports[],
//int importCount) {
System.err.println("checking dir '" + dir + "'");
String files[] = dir.list();
for (int i = 0; i < files.length; i++) {
if (files[i].equals(".") || files[i].equals("..")) continue;
File sub = new File(dir, files[i]);
if (sub.isDirectory()) {
String nowfar = (sofar == null) ?
files[i] : (sofar + "." + files[i]);
//System.out.println(nowfar);
imports[importCount++] = nowfar;
importCount = magicImportsRecursive(sub, nowfar,
imports, importCount);
}
}
return importCount;
}
*/
}

View File

@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify

View File

@@ -3,7 +3,7 @@
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2004-08 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
package processing.app.debug;
/**
* An exception with a line number attached that occurs
* during either compile time or run time.
@@ -44,23 +45,6 @@ public class RunnerException extends Exception {
}
/*
public RunnerException(String message, int line) {
//super(massage(message));
this.message = message;
this.line = line;
}
public RunnerException(String message, int line, int column) {
//super(massage(message));
this.message = message;
this.line = line;
this.column = column;
}
*/
public RunnerException(String message, int file, int line, int column) {
//super(massage(message));
this.message = message;
@@ -75,6 +59,10 @@ public class RunnerException extends Exception {
}
/**
* Override getMessage() in Throwable, so that I can set
* the message text outside the constructor.
*/
public String getMessage() {
return message;
}
@@ -97,6 +85,7 @@ public class RunnerException extends Exception {
* This function must be static to be used with super()
* in each of the constructors above.
*/
/*
static public final String massage(String msg) {
if (msg.indexOf("java.lang.") == 0) {
//int dot = msg.lastIndexOf('.');
@@ -105,6 +94,7 @@ public class RunnerException extends Exception {
return msg;
//return (dot == -1) ? msg : msg.substring(dot+1);
}
*/
public void printStackTrace() {

View File

@@ -7,6 +7,87 @@ releases will be super crusty.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ABOUT REV 0140 - 10 June 2008
Major changes (some might say improvements) to compilation and
platform-specific support. As with all releases later than 0135,
this is essentially an alpha-quality release. We won't be making
them the default download until the series stabilizes. Please help
us out by testing this releases, and filing bugs in the bugs
database if you run into problems.
If this is your first release since 0135, be sure to read *ALL*
the releases notes in this file since that release. A lot has
changed, and there are several known issues.
[ jikes/javac ]
+ Jikes has been removed, and we are using Javac as the compiler.
The negative side of this is that compilation is a little slower,
because Javac is kind of a dog. But that's outweighed by:
- better compatability (avoiding quirky Jikes bugs)
- ability to support Java 1.5 syntax (only in tabs that end in .java!)
- no more Jikes binary problems on Linux (or elsewhere)
- removing a binary from the download (less moving parts)
+ Error messages from Javac are very different, and it's quite
likely that some aren't being handled properly. If you run into
this situation (on error messages--not warnings), please file
a bug report, so that we can provide a better message to the
user about what's going on.
+ It is still not possible to use Java 1.5 syntax in Processing code
from within the environment. You won't be able to use 1.5 syntax
until someone rewrites the preprocessor, which is a significant
undertaking. We want to do it soon, but it's a lot of work.
http://dev.processing.org/bugs/show_bug.cgi?id=598
What has changed in release 0140 is that if you give a tab a name
ending in ".java", you'll be able to use 1.5 syntax, because that
tab will not be run through the preprocessor. However, you'll also
lose all Processing-specific syntax, and you'll have to pass the
PApplet object to any such class in order to use Processing API.
(This is described in Help -> Getting Started.) And no, you cannot
make the main tab a .java file. You can always use Eclipse to do
that, or better yet, give us a hand fixing Bug #598.
[ platform classes ]
+ Platform-specific code has been moved to separate sections of the
codebase. This simplifies how we connect to Mac OS X, Windows,
and Linux. You no longer need the Apple support stubs to compile on
Windows and Linux, for one.
+ Windows registry calls are now handled using JNA, which is behaving
far better than the old JNI Registry code that we had been using.
This should also help internationalization significantly (the old
code didn't properly handle Unicode, or multi-byte characters).
+ I have added Windows Vista and Ubuntu 8.04 on AMD64 to my testing
routine. The apartment is really starting to look ridiculous,
and dinner guests probably won't be happening this Summer.
[ features/changes/fixes ]
+ With any luck we may have fixed the long-standing bug that prevents
Processing from running on non-English systems with user accounts
that contain non-ASCII characters. This is the target
http://dev.processing.org/bugs/show_bug.cgi?id=49
However this has not yet been verified. Please test!
+ Added a static version of loadBytes() that reads from a File object.
+ Slightly clearer error messages when OpenGL stuff is missing.
+ Removed sketchbook.fallback and settings.fallback from preferences.
These cause more confusion/chaos/trouble than necessary.
+ Avoid an occasional division by zero when using the Create Font tool.
http://dev.processing.org/bugs/show_bug.cgi?id=777
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ABOUT REV 0139 - 4 June 2008
Stuck on a couple larger problems, this is an interim release to

View File

@@ -1,4 +1,6 @@
0140 core
X add static version of loadBytes() that reads from a File object
X slightly clearer error messages when OpenGL stuff is missing
_ pdf not rendering unicode (though it renders to screen)

View File

@@ -8,8 +8,8 @@ o vista disables aero theme when p5 is run
o http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1196016889
X can't seem to verify this
X occasional division by zero on windows
_ http://dev.processing.org/bugs/show_bug.cgi?id=777
_ should be fixed, but need to verify once a release candidate is ready
X http://dev.processing.org/bugs/show_bug.cgi?id=777
X should be fixed, but need to verify once a release candidate is ready
X two fixes for readBytesUntil() and bufferUntil()
X also not calling serialEvent()
X http://dev.processing.org/bugs/show_bug.cgi?id=96
@@ -50,12 +50,11 @@ X http://dev.processing.org/bugs/show_bug.cgi?id=723
X or move to jna for registry?
X https://jna.dev.java.net/source/browse/jna/trunk/jnalib/contrib/ntservice/src/jnacontrib/win32/Registry.java?rev=293&view=markup
X remove libs from build/shared that are in app/lib
_ update scripts to copy from app/lib
_ since adding tools.jar, jikes can be removed
_ properly handle non-ascii chars in p5 folder name
X update scripts to copy from app/lib
X since adding tools.jar, jikes can be removed
X switch to javac (in code)
X re-wire error handling to handle javac error messages
_ seem to be primarily 2 kinds?
o seem to be primarily 2 kinds?
X finish osx build script to make the libraries
X make.sh creating work/lib dirs.. no longer necessary?
@@ -86,6 +85,7 @@ _ arduino uses .c, .cpp, .h instead of .java
_ http://dev.processing.org/bugs/show_bug.cgi?id=807
_ check to see whether this bug is fixed once 0140 is released
_ properly handle non-ascii chars in p5 folder name
_ http://dev.processing.org/bugs/show_bug.cgi?id=49
_ (could also just warn user to install elsewhere)
o perhaps the get around this by building into sketch folder