mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-26 20:54:22 +01:00
Make Compiler independent from Sketch.
Create a class SketchData to store all relevant data for a sketch (trying to keep GUI stuff out of the way). Moved preprocessing code from Sketch to Compiler.
This commit is contained in:
parent
e6563cfebf
commit
79ab98fef9
@ -105,7 +105,7 @@ public class Base {
|
|||||||
static private LibraryList libraries;
|
static private LibraryList libraries;
|
||||||
|
|
||||||
// maps #included files to their library folder
|
// maps #included files to their library folder
|
||||||
static Map<String, Library> importToLibraryTable;
|
public static Map<String, Library> importToLibraryTable;
|
||||||
|
|
||||||
// classpath for all known libraries for p5
|
// classpath for all known libraries for p5
|
||||||
// (both those in the p5/libs folder and those with lib subfolders
|
// (both those in the p5/libs folder and those with lib subfolders
|
||||||
|
@ -29,13 +29,11 @@ import cc.arduino.packages.UploaderAndMonitorFactory;
|
|||||||
import cc.arduino.packages.Uploader;
|
import cc.arduino.packages.Uploader;
|
||||||
import processing.app.debug.*;
|
import processing.app.debug.*;
|
||||||
import processing.app.debug.Compiler;
|
import processing.app.debug.Compiler;
|
||||||
|
import processing.app.debug.Compiler.ProgressListener;
|
||||||
import processing.app.forms.PasswordAuthorizationDialog;
|
import processing.app.forms.PasswordAuthorizationDialog;
|
||||||
import processing.app.helpers.PreferencesMap;
|
import processing.app.helpers.PreferencesMap;
|
||||||
import processing.app.helpers.FileUtils;
|
import processing.app.helpers.FileUtils;
|
||||||
import processing.app.packages.Library;
|
import processing.app.packages.Library;
|
||||||
import processing.app.packages.LibraryList;
|
|
||||||
import processing.app.preproc.*;
|
|
||||||
import processing.core.*;
|
|
||||||
import static processing.app.I18n._;
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -55,12 +53,6 @@ public class Sketch {
|
|||||||
/** main pde file for this sketch. */
|
/** main pde file for this sketch. */
|
||||||
private File primaryFile;
|
private File primaryFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of sketch, which is the name of main file
|
|
||||||
* (without .pde or .java extension)
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/** true if any of the files have been modified. */
|
/** true if any of the files have been modified. */
|
||||||
private boolean modified;
|
private boolean modified;
|
||||||
|
|
||||||
@ -77,25 +69,10 @@ public class Sketch {
|
|||||||
private SketchCodeDocument currentCodeDoc;
|
private SketchCodeDocument currentCodeDoc;
|
||||||
private int currentIndex;
|
private int currentIndex;
|
||||||
|
|
||||||
/**
|
private SketchData data;
|
||||||
* Number of sketchCode objects (tabs) in the current sketch. Note that this
|
|
||||||
* will be the same as code.length, because the getCode() method returns
|
|
||||||
* just the code[] array, rather than a copy of it, or an array that's been
|
|
||||||
* resized to just the relevant files themselves.
|
|
||||||
* http://dev.processing.org/bugs/show_bug.cgi?id=940
|
|
||||||
*/
|
|
||||||
private int codeCount;
|
|
||||||
private SketchCodeDocument[] codeDocs;
|
|
||||||
|
|
||||||
/** Class name for the PApplet, as determined by the preprocessor. */
|
/** Class name for the PApplet, as determined by the preprocessor. */
|
||||||
private String appletClassName;
|
private String appletClassName;
|
||||||
/** Class path determined during build. */
|
|
||||||
private String classPath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of library folders.
|
|
||||||
*/
|
|
||||||
private LibraryList importedLibraries;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File inside the build directory that contains the build options
|
* File inside the build directory that contains the build options
|
||||||
@ -107,16 +84,16 @@ public class Sketch {
|
|||||||
* path is location of the main .pde file, because this is also
|
* path is location of the main .pde file, because this is also
|
||||||
* simplest to use when opening the file from the finder/explorer.
|
* simplest to use when opening the file from the finder/explorer.
|
||||||
*/
|
*/
|
||||||
public Sketch(Editor editor, File file) throws IOException {
|
public Sketch(Editor _editor, File file) throws IOException {
|
||||||
this.editor = editor;
|
editor = _editor;
|
||||||
|
data = new SketchData();
|
||||||
primaryFile = file;
|
primaryFile = file;
|
||||||
|
|
||||||
// get the name of the sketch by chopping .pde or .java
|
// get the name of the sketch by chopping .pde or .java
|
||||||
// off of the main file name
|
// off of the main file name
|
||||||
String mainFilename = primaryFile.getName();
|
String mainFilename = primaryFile.getName();
|
||||||
int suffixLength = getDefaultExtension().length() + 1;
|
int suffixLength = getDefaultExtension().length() + 1;
|
||||||
name = mainFilename.substring(0, mainFilename.length() - suffixLength);
|
data.setName(mainFilename.substring(0, mainFilename.length() - suffixLength));
|
||||||
|
|
||||||
// lib/build must exist when the application is started
|
// lib/build must exist when the application is started
|
||||||
// it is added to the CLASSPATH by default, but if it doesn't
|
// it is added to the CLASSPATH by default, but if it doesn't
|
||||||
@ -167,9 +144,7 @@ public class Sketch {
|
|||||||
|
|
||||||
// reset these because load() may be called after an
|
// reset these because load() may be called after an
|
||||||
// external editor event. (fix for 0099)
|
// external editor event. (fix for 0099)
|
||||||
codeCount = 0;
|
data.clearCodeDocs();
|
||||||
|
|
||||||
codeDocs = new SketchCodeDocument[list.length];
|
|
||||||
|
|
||||||
List<String> extensions = getExtensions();
|
List<String> extensions = getExtensions();
|
||||||
|
|
||||||
@ -192,8 +167,7 @@ public class Sketch {
|
|||||||
// Don't allow people to use files with invalid names, since on load,
|
// Don't allow people to use files with invalid names, since on load,
|
||||||
// it would be otherwise possible to sneak in nasty filenames. [0116]
|
// it would be otherwise possible to sneak in nasty filenames. [0116]
|
||||||
if (Sketch.isSanitaryName(base)) {
|
if (Sketch.isSanitaryName(base)) {
|
||||||
codeDocs[codeCount++] =
|
data.addCodeDoc(new SketchCodeDocument(new File(folder, filename)));
|
||||||
new SketchCodeDocument(new File(folder, filename));
|
|
||||||
} else {
|
} else {
|
||||||
System.err.println(I18n.format("File name {0} is invalid: ignored", filename));
|
System.err.println(I18n.format("File name {0} is invalid: ignored", filename));
|
||||||
}
|
}
|
||||||
@ -201,26 +175,21 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeCount == 0)
|
if (data.getCodeCount() == 0)
|
||||||
throw new IOException(_("No valid code files found"));
|
throw new IOException(_("No valid code files found"));
|
||||||
|
|
||||||
// Remove any code that wasn't proper
|
|
||||||
codeDocs = (SketchCodeDocument[]) PApplet.subset(codeDocs, 0, codeCount);
|
|
||||||
|
|
||||||
// move the main class to the first tab
|
// move the main class to the first tab
|
||||||
// start at 1, if it's at zero, don't bother
|
// start at 1, if it's at zero, don't bother
|
||||||
for (int i = 1; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
//if (code[i].file.getName().equals(mainFilename)) {
|
//if (code[i].file.getName().equals(mainFilename)) {
|
||||||
if (codeDocs[i].getCode().getFile().equals(primaryFile)) {
|
if (codeDoc.getCode().getFile().equals(primaryFile)) {
|
||||||
SketchCodeDocument temp = codeDocs[0];
|
data.moveCodeDocToFront(codeDoc);
|
||||||
codeDocs[0] = codeDocs[i];
|
|
||||||
codeDocs[i] = temp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort the entries at the top
|
// sort the entries at the top
|
||||||
sortCode();
|
data.sortCode();
|
||||||
|
|
||||||
// set the main file to be the current tab
|
// set the main file to be the current tab
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
@ -229,47 +198,6 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void replaceCode(SketchCode newCode) {
|
|
||||||
for (int i = 0; i < codeCount; i++) {
|
|
||||||
if (codeDocs[i].getCode().getFileName().equals(newCode.getFileName())) {
|
|
||||||
codeDocs[i].setCode(newCode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void insertCode(SketchCode newCode) {
|
|
||||||
// make sure the user didn't hide the sketch folder
|
|
||||||
ensureExistence();
|
|
||||||
|
|
||||||
// add file to the code/codeCount list, resort the list
|
|
||||||
//if (codeCount == code.length) {
|
|
||||||
codeDocs = (SketchCodeDocument[]) PApplet.append(codeDocs, newCode);
|
|
||||||
codeCount++;
|
|
||||||
//}
|
|
||||||
//code[codeCount++] = newCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void sortCode() {
|
|
||||||
// cheap-ass sort of the rest of the files
|
|
||||||
// it's a dumb, slow sort, but there shouldn't be more than ~5 files
|
|
||||||
for (int i = 1; i < codeCount; i++) {
|
|
||||||
int who = i;
|
|
||||||
for (int j = i + 1; j < codeCount; j++) {
|
|
||||||
if (codeDocs[j].getCode().getFileName().compareTo(codeDocs[who].getCode().getFileName()) < 0) {
|
|
||||||
who = j; // this guy is earlier in the alphabet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (who != i) { // swap with someone if changes made
|
|
||||||
SketchCodeDocument temp = codeDocs[who];
|
|
||||||
codeDocs[who] = codeDocs[i];
|
|
||||||
codeDocs[i] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean renamingCode;
|
boolean renamingCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -380,7 +308,7 @@ public class Sketch {
|
|||||||
// Don't let the user create the main tab as a .java file instead of .pde
|
// Don't let the user create the main tab as a .java file instead of .pde
|
||||||
if (!isDefaultExtension(newExtension)) {
|
if (!isDefaultExtension(newExtension)) {
|
||||||
if (renamingCode) { // If creating a new tab, don't show this error
|
if (renamingCode) { // If creating a new tab, don't show this error
|
||||||
if (current == codeDocs[0].getCode()) { // If this is the main tab, disallow
|
if (current == data.getCodeDoc(0).getCode()) { // If this is the main tab, disallow
|
||||||
Base.showWarning(_("Problem with rename"),
|
Base.showWarning(_("Problem with rename"),
|
||||||
_("The main file can't use an extension.\n" +
|
_("The main file can't use an extension.\n" +
|
||||||
"(It may be time for your to graduate to a\n" +
|
"(It may be time for your to graduate to a\n" +
|
||||||
@ -402,7 +330,7 @@ public class Sketch {
|
|||||||
// In Arduino, we want to allow files with the same name but different
|
// In Arduino, we want to allow files with the same name but different
|
||||||
// extensions, so compare the full names (including extensions). This
|
// extensions, so compare the full names (including extensions). This
|
||||||
// might cause problems: http://dev.processing.org/bugs/show_bug.cgi?id=543
|
// might cause problems: http://dev.processing.org/bugs/show_bug.cgi?id=543
|
||||||
for (SketchCodeDocument c : codeDocs) {
|
for (SketchCodeDocument c : data.getCodeDocs()) {
|
||||||
if (newName.equalsIgnoreCase(c.getCode().getFileName())) {
|
if (newName.equalsIgnoreCase(c.getCode().getFileName())) {
|
||||||
Base.showMessage(_("Nope"),
|
Base.showMessage(_("Nope"),
|
||||||
I18n.format(
|
I18n.format(
|
||||||
@ -424,9 +352,9 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (renamingCode && currentIndex == 0) {
|
if (renamingCode && currentIndex == 0) {
|
||||||
for (int i = 1; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (sanitaryName.equalsIgnoreCase(codeDocs[i].getCode().getPrettyName()) &&
|
if (sanitaryName.equalsIgnoreCase(codeDoc.getCode().getPrettyName()) &&
|
||||||
codeDocs[i].getCode().isExtension("cpp")) {
|
codeDoc.getCode().isExtension("cpp")) {
|
||||||
Base.showMessage(_("Nope"),
|
Base.showMessage(_("Nope"),
|
||||||
I18n.format(
|
I18n.format(
|
||||||
_("You can't rename the sketch to \"{0}\"\n" +
|
_("You can't rename the sketch to \"{0}\"\n" +
|
||||||
@ -500,8 +428,8 @@ public class Sketch {
|
|||||||
|
|
||||||
// save each of the other tabs because this is gonna be re-opened
|
// save each of the other tabs because this is gonna be re-opened
|
||||||
try {
|
try {
|
||||||
for (int i = 1; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
codeDocs[i].getCode().save();
|
codeDoc.getCode().save();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Base.showWarning(_("Error"), _("Could not rename the sketch. (1)"), e);
|
Base.showWarning(_("Error"), _("Could not rename the sketch. (1)"), e);
|
||||||
@ -560,11 +488,12 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
SketchCode newCode = new SketchCode(newFile);
|
SketchCode newCode = new SketchCode(newFile);
|
||||||
//System.out.println("new code is named " + newCode.getPrettyName() + " " + newCode.getFile());
|
//System.out.println("new code is named " + newCode.getPrettyName() + " " + newCode.getFile());
|
||||||
insertCode(newCode);
|
ensureExistence();
|
||||||
|
data.insertCode(newCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort the entries
|
// sort the entries
|
||||||
sortCode();
|
data.sortCode();
|
||||||
|
|
||||||
// set the new guy as current
|
// set the new guy as current
|
||||||
setCurrentCode(newName);
|
setCurrentCode(newName);
|
||||||
@ -629,7 +558,7 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove code from the list
|
// remove code from the list
|
||||||
removeCode(current);
|
data.removeCode(current);
|
||||||
|
|
||||||
// just set current tab to the main tab
|
// just set current tab to the main tab
|
||||||
setCurrentCode(0);
|
setCurrentCode(0);
|
||||||
@ -641,29 +570,12 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void removeCode(SketchCode which) {
|
|
||||||
// remove it from the internal list of files
|
|
||||||
// resort internal list of files
|
|
||||||
for (int i = 0; i < codeCount; i++) {
|
|
||||||
if (codeDocs[i].getCode() == which) {
|
|
||||||
for (int j = i; j < codeCount-1; j++) {
|
|
||||||
codeDocs[j] = codeDocs[j+1];
|
|
||||||
}
|
|
||||||
codeCount--;
|
|
||||||
codeDocs = (SketchCodeDocument[]) PApplet.shorten(codeDocs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.err.println(_("removeCode: internal error.. could not find code"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move to the previous tab.
|
* Move to the previous tab.
|
||||||
*/
|
*/
|
||||||
public void handlePrevCode() {
|
public void handlePrevCode() {
|
||||||
int prev = currentIndex - 1;
|
int prev = currentIndex - 1;
|
||||||
if (prev < 0) prev = codeCount-1;
|
if (prev < 0) prev = data.getCodeCount()-1;
|
||||||
setCurrentCode(prev);
|
setCurrentCode(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,7 +584,7 @@ public class Sketch {
|
|||||||
* Move to the next tab.
|
* Move to the next tab.
|
||||||
*/
|
*/
|
||||||
public void handleNextCode() {
|
public void handleNextCode() {
|
||||||
setCurrentCode((currentIndex + 1) % codeCount);
|
setCurrentCode((currentIndex + 1) % data.getCodeCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -689,8 +601,8 @@ public class Sketch {
|
|||||||
|
|
||||||
protected void calcModified() {
|
protected void calcModified() {
|
||||||
modified = false;
|
modified = false;
|
||||||
for (int i = 0; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (codeDocs[i].getCode().isModified()) {
|
if (codeDoc.getCode().isModified()) {
|
||||||
modified = true;
|
modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -773,9 +685,9 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (codeDocs[i].getCode().isModified())
|
if (codeDoc.getCode().isModified())
|
||||||
codeDocs[i].getCode().save();
|
codeDoc.getCode().save();
|
||||||
}
|
}
|
||||||
calcModified();
|
calcModified();
|
||||||
return true;
|
return true;
|
||||||
@ -783,7 +695,7 @@ public class Sketch {
|
|||||||
|
|
||||||
|
|
||||||
protected boolean renameCodeToInoExtension(File pdeFile) {
|
protected boolean renameCodeToInoExtension(File pdeFile) {
|
||||||
for (SketchCodeDocument c : codeDocs) {
|
for (SketchCodeDocument c : data.getCodeDocs()) {
|
||||||
if (!c.getCode().getFile().equals(pdeFile))
|
if (!c.getCode().getFile().equals(pdeFile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -834,9 +746,9 @@ public class Sketch {
|
|||||||
// make sure there doesn't exist a .cpp file with that name already
|
// make sure there doesn't exist a .cpp file with that name already
|
||||||
// but ignore this situation for the first tab, since it's probably being
|
// but ignore this situation for the first tab, since it's probably being
|
||||||
// resaved (with the same name) to another location/folder.
|
// resaved (with the same name) to another location/folder.
|
||||||
for (int i = 1; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (newName.equalsIgnoreCase(codeDocs[i].getCode().getPrettyName()) &&
|
if (newName.equalsIgnoreCase(codeDoc.getCode().getPrettyName()) &&
|
||||||
codeDocs[i].getCode().isExtension("cpp")) {
|
codeDoc.getCode().isExtension("cpp")) {
|
||||||
Base.showMessage(_("Nope"),
|
Base.showMessage(_("Nope"),
|
||||||
I18n.format(
|
I18n.format(
|
||||||
_("You can't save the sketch as \"{0}\"\n" +
|
_("You can't save the sketch as \"{0}\"\n" +
|
||||||
@ -886,9 +798,10 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save the other tabs to their new location
|
// save the other tabs to their new location
|
||||||
for (int i = 1; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
File newFile = new File(newFolder, codeDocs[i].getCode().getFileName());
|
if (data.indexOfCodeDoc(codeDoc) == 0) continue;
|
||||||
codeDocs[i].getCode().saveAs(newFile);
|
File newFile = new File(newFolder, codeDoc.getCode().getFileName());
|
||||||
|
codeDoc.getCode().saveAs(newFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// re-copy the data folder (this may take a while.. add progress bar?)
|
// re-copy the data folder (this may take a while.. add progress bar?)
|
||||||
@ -913,7 +826,7 @@ public class Sketch {
|
|||||||
|
|
||||||
// save the main tab with its new name
|
// save the main tab with its new name
|
||||||
File newFile = new File(newFolder, newName + ".ino");
|
File newFile = new File(newFolder, newName + ".ino");
|
||||||
codeDocs[0].getCode().saveAs(newFile);
|
data.getCodeDoc(0).getCode().saveAs(newFile);
|
||||||
|
|
||||||
editor.handleOpenUnchecked(newFile,
|
editor.handleOpenUnchecked(newFile,
|
||||||
currentIndex,
|
currentIndex,
|
||||||
@ -1079,11 +992,12 @@ public class Sketch {
|
|||||||
SketchCode newCode = new SketchCode(destFile);
|
SketchCode newCode = new SketchCode(destFile);
|
||||||
|
|
||||||
if (replacement) {
|
if (replacement) {
|
||||||
replaceCode(newCode);
|
data.replaceCode(newCode);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
insertCode(newCode);
|
ensureExistence();
|
||||||
sortCode();
|
data.insertCode(newCode);
|
||||||
|
data.sortCode();
|
||||||
}
|
}
|
||||||
setCurrentCode(filename);
|
setCurrentCode(filename);
|
||||||
editor.header.repaint();
|
editor.header.repaint();
|
||||||
@ -1096,7 +1010,7 @@ public class Sketch {
|
|||||||
if (editor.untitled) { // TODO probably not necessary? problematic?
|
if (editor.untitled) { // TODO probably not necessary? problematic?
|
||||||
// If a file has been added, mark the main code as modified so
|
// If a file has been added, mark the main code as modified so
|
||||||
// that the sketch is properly saved.
|
// that the sketch is properly saved.
|
||||||
codeDocs[0].getCode().setModified(true);
|
data.getCodeDoc(0).getCode().setModified(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1162,7 +1076,7 @@ public class Sketch {
|
|||||||
currentCodeDoc.setScrollPosition(editor.getScrollPosition());
|
currentCodeDoc.setScrollPosition(editor.getScrollPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCodeDoc = codeDocs[which];
|
currentCodeDoc = data.getCodeDoc(which);
|
||||||
current = currentCodeDoc.getCode();
|
current = currentCodeDoc.getCode();
|
||||||
currentIndex = which;
|
currentIndex = which;
|
||||||
|
|
||||||
@ -1177,10 +1091,10 @@ public class Sketch {
|
|||||||
* @param findName the file name (not pretty name) to be shown
|
* @param findName the file name (not pretty name) to be shown
|
||||||
*/
|
*/
|
||||||
protected void setCurrentCode(String findName) {
|
protected void setCurrentCode(String findName) {
|
||||||
for (int i = 0; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (findName.equals(codeDocs[i].getCode().getFileName()) ||
|
if (findName.equals(codeDoc.getCode().getFileName()) ||
|
||||||
findName.equals(codeDocs[i].getCode().getPrettyName())) {
|
findName.equals(codeDoc.getCode().getPrettyName())) {
|
||||||
setCurrentCode(i);
|
setCurrentCode(data.indexOfCodeDoc(codeDoc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1290,144 +1204,6 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build all the code for this sketch.
|
|
||||||
*
|
|
||||||
* In an advanced program, the returned class name could be different,
|
|
||||||
* which is why the className is set based on the return value.
|
|
||||||
* A compilation error will burp up a RunnerException.
|
|
||||||
*
|
|
||||||
* Setting purty to 'true' will cause exception line numbers to be incorrect.
|
|
||||||
* Unless you know the code compiles, you should first run the preprocessor
|
|
||||||
* with purty set to false to make sure there are no errors, then once
|
|
||||||
* successful, re-export with purty set to true.
|
|
||||||
*
|
|
||||||
* @param buildPath Location to copy all the .java files
|
|
||||||
* @return null if compilation failed, main class name if not
|
|
||||||
*/
|
|
||||||
public void preprocess(String buildPath) throws RunnerException {
|
|
||||||
preprocess(buildPath, new PdePreprocessor());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void preprocess(String buildPath, PdePreprocessor preprocessor) throws RunnerException {
|
|
||||||
// make sure the user didn't hide the sketch folder
|
|
||||||
ensureExistence();
|
|
||||||
|
|
||||||
classPath = buildPath;
|
|
||||||
|
|
||||||
// // figure out the contents of the code folder to see if there
|
|
||||||
// // are files that need to be added to the imports
|
|
||||||
// if (codeFolder.exists()) {
|
|
||||||
// libraryPath = codeFolder.getAbsolutePath();
|
|
||||||
//
|
|
||||||
// // get a list of .jar files in the "code" folder
|
|
||||||
// // (class files in subfolders should also be picked up)
|
|
||||||
// String codeFolderClassPath =
|
|
||||||
// Compiler.contentsToClassPath(codeFolder);
|
|
||||||
// // append the jar files in the code folder to the class path
|
|
||||||
// classPath += File.pathSeparator + codeFolderClassPath;
|
|
||||||
// // get list of packages found in those jars
|
|
||||||
// codeFolderPackages =
|
|
||||||
// Compiler.packageListFromClassPath(codeFolderClassPath);
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// libraryPath = "";
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 1. concatenate all .pde files to the 'main' pde
|
|
||||||
// store line number for starting point of each code bit
|
|
||||||
|
|
||||||
StringBuffer bigCode = new StringBuffer();
|
|
||||||
int bigCount = 0;
|
|
||||||
for (SketchCodeDocument scd : codeDocs) {
|
|
||||||
SketchCode sc = scd.getCode();
|
|
||||||
if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
|
||||||
sc.setPreprocOffset(bigCount);
|
|
||||||
// These #line directives help the compiler report errors with
|
|
||||||
// correct the filename and line number (issue 281 & 907)
|
|
||||||
bigCode.append("#line 1 \"" + sc.getFileName() + "\"\n");
|
|
||||||
bigCode.append(sc.getProgram());
|
|
||||||
bigCode.append('\n');
|
|
||||||
bigCount += sc.getLineCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that the headerOffset isn't applied until compile and run, because
|
|
||||||
// it only applies to the code after it's been written to the .java file.
|
|
||||||
int headerOffset = 0;
|
|
||||||
try {
|
|
||||||
headerOffset = preprocessor.writePrefix(bigCode.toString());
|
|
||||||
} catch (FileNotFoundException fnfe) {
|
|
||||||
fnfe.printStackTrace();
|
|
||||||
String msg = _("Build folder disappeared or could not be written");
|
|
||||||
throw new RunnerException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. run preproc on that code using the sugg class name
|
|
||||||
// to create a single .java file and write to buildpath
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Output file
|
|
||||||
File streamFile = new File(buildPath, name + ".cpp");
|
|
||||||
FileOutputStream outputStream = new FileOutputStream(streamFile);
|
|
||||||
preprocessor.write(outputStream);
|
|
||||||
outputStream.close();
|
|
||||||
} catch (FileNotFoundException fnfe) {
|
|
||||||
fnfe.printStackTrace();
|
|
||||||
String msg = _("Build folder disappeared or could not be written");
|
|
||||||
throw new RunnerException(msg);
|
|
||||||
} catch (RunnerException pe) {
|
|
||||||
// RunnerExceptions are caught here and re-thrown, so that they don't
|
|
||||||
// get lost in the more general "Exception" handler below.
|
|
||||||
throw pe;
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// TODO better method for handling this?
|
|
||||||
System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass()));
|
|
||||||
ex.printStackTrace();
|
|
||||||
throw new RunnerException(ex.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab the imports from the code just preproc'd
|
|
||||||
|
|
||||||
importedLibraries = new LibraryList();
|
|
||||||
for (String item : preprocessor.getExtraImports()) {
|
|
||||||
Library lib = Base.importToLibraryTable.get(item);
|
|
||||||
if (lib != null && !importedLibraries.contains(lib)) {
|
|
||||||
importedLibraries.add(lib);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. then loop over the code[] and save each .java file
|
|
||||||
|
|
||||||
for (SketchCodeDocument scd : codeDocs) {
|
|
||||||
SketchCode sc = scd.getCode();
|
|
||||||
if (sc.isExtension("c") || sc.isExtension("cpp") || sc.isExtension("h")) {
|
|
||||||
// no pre-processing services necessary for java files
|
|
||||||
// just write the the contents of 'program' to a .java file
|
|
||||||
// into the build directory. uses byte stream and reader/writer
|
|
||||||
// shtuff so that unicode bunk is properly handled
|
|
||||||
String filename = sc.getFileName(); //code[i].name + ".java";
|
|
||||||
try {
|
|
||||||
Base.saveFile(sc.getProgram(), new File(buildPath, filename));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RunnerException(I18n.format(_("Problem moving {0} to the build folder"), filename));
|
|
||||||
}
|
|
||||||
// sc.setPreprocName(filename);
|
|
||||||
|
|
||||||
} else if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
|
||||||
// The compiler and runner will need this to have a proper offset
|
|
||||||
sc.addPreprocOffset(headerOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public LibraryList getImportedLibraries() {
|
|
||||||
return importedLibraries;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map an error from a set of processed .java files back to its location
|
* Map an error from a set of processed .java files back to its location
|
||||||
@ -1479,31 +1255,6 @@ public class Sketch {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map an error from a set of processed .java files back to its location
|
|
||||||
* in the actual sketch.
|
|
||||||
* @param message The error message.
|
|
||||||
* @param dotJavaFilename The .java file where the exception was found.
|
|
||||||
* @param dotJavaLine Line number of the .java file for the exception (0-indexed!)
|
|
||||||
* @return A RunnerException to be sent to the editor, or null if it wasn't
|
|
||||||
* possible to place the exception to the sketch code.
|
|
||||||
*/
|
|
||||||
public RunnerException placeException(String message,
|
|
||||||
String dotJavaFilename,
|
|
||||||
int dotJavaLine) {
|
|
||||||
// Placing errors is simple, because we inserted #line directives
|
|
||||||
// into the preprocessed source. The compiler gives us correct
|
|
||||||
// the file name and line number. :-)
|
|
||||||
for (int codeIndex = 0; codeIndex < getCodeCount(); codeIndex++) {
|
|
||||||
SketchCode code = getCode(codeIndex);
|
|
||||||
if (dotJavaFilename.equals(code.getFileName())) {
|
|
||||||
return new RunnerException(message, codeIndex, dotJavaLine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the build inside the temporary build folder.
|
* Run the build inside the temporary build folder.
|
||||||
* @return null if compilation failed, main class name if not
|
* @return null if compilation failed, main class name if not
|
||||||
@ -1564,8 +1315,8 @@ public class Sketch {
|
|||||||
* @return null if compilation failed, main class name if not
|
* @return null if compilation failed, main class name if not
|
||||||
*/
|
*/
|
||||||
public String build(String buildPath, boolean verbose) throws RunnerException {
|
public String build(String buildPath, boolean verbose) throws RunnerException {
|
||||||
String primaryClassName = name + ".cpp";
|
String primaryClassName = data.getName() + ".cpp";
|
||||||
Compiler compiler = new Compiler(this, buildPath, primaryClassName);
|
Compiler compiler = new Compiler(data, buildPath, primaryClassName);
|
||||||
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
|
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
|
||||||
String newBuildPrefs = buildPrefsString(compiler);
|
String newBuildPrefs = buildPrefsString(compiler);
|
||||||
|
|
||||||
@ -1586,8 +1337,16 @@ public class Sketch {
|
|||||||
|
|
||||||
// run the preprocessor
|
// run the preprocessor
|
||||||
editor.status.progressUpdate(20);
|
editor.status.progressUpdate(20);
|
||||||
preprocess(buildPath);
|
|
||||||
|
|
||||||
|
ensureExistence();
|
||||||
|
|
||||||
|
compiler.setProgressListener(new ProgressListener() {
|
||||||
|
@Override
|
||||||
|
public void progress(int percent) {
|
||||||
|
editor.status.progressUpdate(percent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// compile the program. errors will happen as a RunnerException
|
// compile the program. errors will happen as a RunnerException
|
||||||
// that will bubble up to whomever called build().
|
// that will bubble up to whomever called build().
|
||||||
if (compiler.compile(verbose)) {
|
if (compiler.compile(verbose)) {
|
||||||
@ -1632,11 +1391,6 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setCompilingProgress(int percent) {
|
|
||||||
editor.status.progressUpdate(percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void size(PreferencesMap prefs) throws RunnerException {
|
protected void size(PreferencesMap prefs) throws RunnerException {
|
||||||
String maxTextSizeString = prefs.get("upload.maximum_size");
|
String maxTextSizeString = prefs.get("upload.maximum_size");
|
||||||
String maxDataSizeString = prefs.get("upload.maximum_data_size");
|
String maxDataSizeString = prefs.get("upload.maximum_data_size");
|
||||||
@ -1773,8 +1527,8 @@ public class Sketch {
|
|||||||
folder.mkdirs();
|
folder.mkdirs();
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|
||||||
for (int i = 0; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
codeDocs[i].getCode().save(); // this will force a save
|
codeDoc.getCode().save(); // this will force a save
|
||||||
}
|
}
|
||||||
calcModified();
|
calcModified();
|
||||||
|
|
||||||
@ -1808,9 +1562,9 @@ public class Sketch {
|
|||||||
// } else if (!folder.canWrite()) {
|
// } else if (!folder.canWrite()) {
|
||||||
|
|
||||||
// check to see if each modified code file can be written to
|
// check to see if each modified code file can be written to
|
||||||
for (int i = 0; i < codeCount; i++) {
|
for (SketchCodeDocument codeDoc : data.getCodeDocs()) {
|
||||||
if (codeDocs[i].getCode().isModified() && codeDocs[i].getCode().fileReadOnly() &&
|
if (codeDoc.getCode().isModified() && codeDoc.getCode().fileReadOnly() &&
|
||||||
codeDocs[i].getCode().fileExists()) {
|
codeDoc.getCode().fileExists()) {
|
||||||
// System.err.println("found a read-only file " + code[i].file);
|
// System.err.println("found a read-only file " + code[i].file);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1879,7 +1633,7 @@ public class Sketch {
|
|||||||
* Returns the name of this sketch. (The pretty name of the main tab.)
|
* Returns the name of this sketch. (The pretty name of the main tab.)
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return data.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1948,33 +1702,23 @@ public class Sketch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getClassPath() {
|
|
||||||
return classPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public SketchCodeDocument[] getCodeDocs() {
|
public SketchCodeDocument[] getCodeDocs() {
|
||||||
return codeDocs;
|
return data.getCodeDocs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getCodeCount() {
|
public int getCodeCount() {
|
||||||
return codeCount;
|
return data.getCodeCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public SketchCode getCode(int index) {
|
public SketchCode getCode(int index) {
|
||||||
return codeDocs[index].getCode();
|
return data.getCodeDoc(index).getCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getCodeIndex(SketchCode who) {
|
public int getCodeIndex(SketchCode who) {
|
||||||
for (int i = 0; i < codeCount; i++) {
|
return data.indexOfCode(who);
|
||||||
if (who == codeDocs[i].getCode()) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SketchCode - data class for a single file inside a sketch
|
SketchCode - data class for a single file inside a sketch
|
||||||
Part of the Processing project - http://processing.org
|
Part of the Processing project - http://processing.org
|
||||||
@ -31,11 +29,11 @@ import java.util.Arrays;
|
|||||||
import static processing.app.I18n._;
|
import static processing.app.I18n._;
|
||||||
import processing.app.helpers.FileUtils;
|
import processing.app.helpers.FileUtils;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single tab of a sketch.
|
* Represents a single tab of a sketch.
|
||||||
*/
|
*/
|
||||||
public class SketchCode {
|
public class SketchCode {
|
||||||
|
|
||||||
/** Pretty name (no extension), not the full file name */
|
/** Pretty name (no extension), not the full file name */
|
||||||
private String prettyName;
|
private String prettyName;
|
||||||
|
|
||||||
@ -47,8 +45,6 @@ public class SketchCode {
|
|||||||
|
|
||||||
private boolean modified;
|
private boolean modified;
|
||||||
|
|
||||||
/** name of .java file after preproc */
|
|
||||||
// private String preprocName;
|
|
||||||
/** where this code starts relative to the concat'd code */
|
/** where this code starts relative to the concat'd code */
|
||||||
private int preprocOffset;
|
private int preprocOffset;
|
||||||
|
|
||||||
|
108
app/src/processing/app/SketchData.java
Normal file
108
app/src/processing/app/SketchData.java
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
package processing.app;
|
||||||
|
|
||||||
|
import static processing.app.I18n._;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SketchData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of sketch, which is the name of main file (without .pde or .java
|
||||||
|
* extension)
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private List<SketchCodeDocument> codeDocs = new ArrayList<SketchCodeDocument>();
|
||||||
|
|
||||||
|
private static final Comparator<SketchCodeDocument> CODE_DOCS_COMPARATOR = new Comparator<SketchCodeDocument>() {
|
||||||
|
@Override
|
||||||
|
public int compare(SketchCodeDocument cd1, SketchCodeDocument cd2) {
|
||||||
|
return cd1.getCode().getFileName().compareTo(cd2.getCode().getFileName());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public int getCodeCount() {
|
||||||
|
return codeDocs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SketchCodeDocument[] getCodeDocs() {
|
||||||
|
return codeDocs.toArray(new SketchCodeDocument[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCodeDoc(SketchCodeDocument sketchCodeDoc) {
|
||||||
|
codeDocs.add(sketchCodeDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveCodeDocToFront(SketchCodeDocument codeDoc) {
|
||||||
|
codeDocs.remove(codeDoc);
|
||||||
|
codeDocs.add(0, codeDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void replaceCode(SketchCode newCode) {
|
||||||
|
for (SketchCodeDocument codeDoc : codeDocs) {
|
||||||
|
if (codeDoc.getCode().getFileName().equals(newCode.getFileName())) {
|
||||||
|
codeDoc.setCode(newCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void insertCode(SketchCode sketchCode) {
|
||||||
|
addCodeDoc(new SketchCodeDocument(sketchCode, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sortCode() {
|
||||||
|
if (codeDocs.size() < 2)
|
||||||
|
return;
|
||||||
|
SketchCodeDocument first = codeDocs.remove(0);
|
||||||
|
Collections.sort(codeDocs, CODE_DOCS_COMPARATOR);
|
||||||
|
codeDocs.add(0, first);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SketchCodeDocument getCodeDoc(int i) {
|
||||||
|
return codeDocs.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SketchCode getCode(int i) {
|
||||||
|
return codeDocs.get(i).getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void removeCode(SketchCode which) {
|
||||||
|
for (SketchCodeDocument codeDoc : codeDocs) {
|
||||||
|
if (codeDoc.getCode() == which) {
|
||||||
|
codeDocs.remove(codeDoc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.err.println(_("removeCode: internal error.. could not find code"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexOfCodeDoc(SketchCodeDocument codeDoc) {
|
||||||
|
return codeDocs.indexOf(codeDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int indexOfCode(SketchCode who) {
|
||||||
|
for (SketchCodeDocument codeDoc : codeDocs) {
|
||||||
|
if (codeDoc.getCode() == who) {
|
||||||
|
return codeDocs.indexOf(codeDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCodeDocs() {
|
||||||
|
codeDocs.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,8 @@ import static processing.app.I18n._;
|
|||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -37,59 +39,84 @@ import java.util.Map;
|
|||||||
import processing.app.Base;
|
import processing.app.Base;
|
||||||
import processing.app.I18n;
|
import processing.app.I18n;
|
||||||
import processing.app.Preferences;
|
import processing.app.Preferences;
|
||||||
import processing.app.Sketch;
|
|
||||||
import processing.app.SketchCode;
|
import processing.app.SketchCode;
|
||||||
|
import processing.app.SketchCodeDocument;
|
||||||
|
import processing.app.SketchData;
|
||||||
import processing.app.helpers.FileUtils;
|
import processing.app.helpers.FileUtils;
|
||||||
import processing.app.helpers.PreferencesMap;
|
import processing.app.helpers.PreferencesMap;
|
||||||
import processing.app.helpers.ProcessUtils;
|
import processing.app.helpers.ProcessUtils;
|
||||||
import processing.app.helpers.StringReplacer;
|
import processing.app.helpers.StringReplacer;
|
||||||
import processing.app.helpers.filefilters.OnlyDirs;
|
import processing.app.helpers.filefilters.OnlyDirs;
|
||||||
import processing.app.packages.Library;
|
import processing.app.packages.Library;
|
||||||
|
import processing.app.packages.LibraryList;
|
||||||
|
import processing.app.preproc.PdePreprocessor;
|
||||||
import processing.core.PApplet;
|
import processing.core.PApplet;
|
||||||
|
|
||||||
public class Compiler implements MessageConsumer {
|
public class Compiler implements MessageConsumer {
|
||||||
|
|
||||||
private Sketch sketch;
|
private SketchData sketch;
|
||||||
|
private PreferencesMap prefs;
|
||||||
|
private boolean verbose;
|
||||||
|
|
||||||
private List<File> objectFiles;
|
private List<File> objectFiles;
|
||||||
|
|
||||||
private PreferencesMap prefs;
|
|
||||||
private boolean verbose;
|
|
||||||
private boolean sketchIsCompiled;
|
private boolean sketchIsCompiled;
|
||||||
private String targetArch;
|
|
||||||
|
|
||||||
private RunnerException exception;
|
private RunnerException exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener interface for progress update on the GUI
|
||||||
|
*/
|
||||||
|
public interface ProgressListener {
|
||||||
|
public void progress(int percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProgressListener progressListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Compiler
|
* Create a new Compiler
|
||||||
* @param _sketch Sketch object to be compiled.
|
* @param _sketch Sketch object to be compiled.
|
||||||
* @param _buildPath Where the temporary files live and will be built from.
|
* @param _buildPath Where the temporary files live and will be built from.
|
||||||
* @param _primaryClassName the name of the combined sketch file w/ extension
|
* @param _primaryClassName the name of the combined sketch file w/ extension
|
||||||
*/
|
*/
|
||||||
public Compiler(Sketch _sketch, String _buildPath, String _primaryClassName)
|
public Compiler(SketchData _sketch, String _buildPath, String _primaryClassName)
|
||||||
throws RunnerException {
|
throws RunnerException {
|
||||||
sketch = _sketch;
|
sketch = _sketch;
|
||||||
prefs = createBuildPreferences(_buildPath, _primaryClassName);
|
prefs = createBuildPreferences(_buildPath, _primaryClassName);
|
||||||
|
|
||||||
|
// Start with an empty progress listener
|
||||||
|
progressListener = new ProgressListener() {
|
||||||
|
@Override
|
||||||
|
public void progress(int percent) {
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProgressListener(ProgressListener _progressListener) {
|
||||||
|
progressListener = _progressListener;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compile sketch.
|
* Compile sketch.
|
||||||
|
* @param buildPath
|
||||||
*
|
*
|
||||||
* @return true if successful.
|
* @return true if successful.
|
||||||
* @throws RunnerException Only if there's a problem. Only then.
|
* @throws RunnerException Only if there's a problem. Only then.
|
||||||
*/
|
*/
|
||||||
public boolean compile(boolean _verbose) throws RunnerException {
|
public boolean compile(boolean _verbose) throws RunnerException {
|
||||||
|
preprocess(prefs.get("build.path"));
|
||||||
|
|
||||||
verbose = _verbose || Preferences.getBoolean("build.verbose");
|
verbose = _verbose || Preferences.getBoolean("build.verbose");
|
||||||
sketchIsCompiled = false;
|
sketchIsCompiled = false;
|
||||||
objectFiles = new ArrayList<File>();
|
objectFiles = new ArrayList<File>();
|
||||||
|
|
||||||
// 0. include paths for core + all libraries
|
// 0. include paths for core + all libraries
|
||||||
sketch.setCompilingProgress(20);
|
progressListener.progress(20);
|
||||||
List<File> includeFolders = new ArrayList<File>();
|
List<File> includeFolders = new ArrayList<File>();
|
||||||
includeFolders.add(prefs.getFile("build.core.path"));
|
includeFolders.add(prefs.getFile("build.core.path"));
|
||||||
if (prefs.getFile("build.variant.path") != null)
|
if (prefs.getFile("build.variant.path") != null)
|
||||||
includeFolders.add(prefs.getFile("build.variant.path"));
|
includeFolders.add(prefs.getFile("build.variant.path"));
|
||||||
for (Library lib : sketch.getImportedLibraries()) {
|
for (Library lib : importedLibraries) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
System.out.println(I18n
|
System.out.println(I18n
|
||||||
.format(_("Using library {0} in folder: {1} {2}"), lib.getName(),
|
.format(_("Using library {0} in folder: {1} {2}"), lib.getName(),
|
||||||
@ -105,7 +132,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
String[] overrides = prefs.get("architecture.override_check").split(",");
|
String[] overrides = prefs.get("architecture.override_check").split(",");
|
||||||
archs.addAll(Arrays.asList(overrides));
|
archs.addAll(Arrays.asList(overrides));
|
||||||
}
|
}
|
||||||
for (Library lib : sketch.getImportedLibraries()) {
|
for (Library lib : importedLibraries) {
|
||||||
if (!lib.supportsArchitecture(archs)) {
|
if (!lib.supportsArchitecture(archs)) {
|
||||||
System.err.println(I18n
|
System.err.println(I18n
|
||||||
.format(_("WARNING: library {0} claims to run on {1} "
|
.format(_("WARNING: library {0} claims to run on {1} "
|
||||||
@ -117,33 +144,33 @@ public class Compiler implements MessageConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. compile the sketch (already in the buildPath)
|
// 1. compile the sketch (already in the buildPath)
|
||||||
sketch.setCompilingProgress(30);
|
progressListener.progress(30);
|
||||||
compileSketch(includeFolders);
|
compileSketch(includeFolders);
|
||||||
sketchIsCompiled = true;
|
sketchIsCompiled = true;
|
||||||
|
|
||||||
// 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
|
// 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
|
||||||
// Doesn't really use configPreferences
|
// Doesn't really use configPreferences
|
||||||
sketch.setCompilingProgress(40);
|
progressListener.progress(40);
|
||||||
compileLibraries(includeFolders);
|
compileLibraries(includeFolders);
|
||||||
|
|
||||||
// 3. compile the core, outputting .o files to <buildPath> and then
|
// 3. compile the core, outputting .o files to <buildPath> and then
|
||||||
// collecting them into the core.a library file.
|
// collecting them into the core.a library file.
|
||||||
sketch.setCompilingProgress(50);
|
progressListener.progress(50);
|
||||||
compileCore();
|
compileCore();
|
||||||
|
|
||||||
// 4. link it all together into the .elf file
|
// 4. link it all together into the .elf file
|
||||||
sketch.setCompilingProgress(60);
|
progressListener.progress(60);
|
||||||
compileLink();
|
compileLink();
|
||||||
|
|
||||||
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
||||||
sketch.setCompilingProgress(70);
|
progressListener.progress(70);
|
||||||
compileEep();
|
compileEep();
|
||||||
|
|
||||||
// 6. build the .hex file
|
// 6. build the .hex file
|
||||||
sketch.setCompilingProgress(80);
|
progressListener.progress(80);
|
||||||
compileHex();
|
compileHex();
|
||||||
|
|
||||||
sketch.setCompilingProgress(90);
|
progressListener.progress(90);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,8 +217,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
|
|
||||||
p.put("build.path", _buildPath);
|
p.put("build.path", _buildPath);
|
||||||
p.put("build.project_name", _primaryClassName);
|
p.put("build.project_name", _primaryClassName);
|
||||||
targetArch = targetPlatform.getId();
|
p.put("build.arch", targetPlatform.getId().toUpperCase());
|
||||||
p.put("build.arch", targetArch.toUpperCase());
|
|
||||||
|
|
||||||
// Platform.txt should define its own compiler.path. For
|
// Platform.txt should define its own compiler.path. For
|
||||||
// compatibility with earlier 1.5 versions, we define a (ugly,
|
// compatibility with earlier 1.5 versions, we define a (ugly,
|
||||||
@ -356,8 +382,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean firstErrorFound;
|
|
||||||
boolean secondErrorFound;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either succeeds or throws a RunnerException fit for public consumption.
|
* Either succeeds or throws a RunnerException fit for public consumption.
|
||||||
@ -382,9 +406,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
firstErrorFound = false; // haven't found any errors yet
|
|
||||||
secondErrorFound = false;
|
|
||||||
|
|
||||||
Process process;
|
Process process;
|
||||||
try {
|
try {
|
||||||
process = ProcessUtils.exec(command);
|
process = ProcessUtils.exec(command);
|
||||||
@ -520,7 +541,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
if (!sketchIsCompiled) {
|
if (!sketchIsCompiled) {
|
||||||
// Place errors when compiling the sketch, but never while compiling libraries
|
// Place errors when compiling the sketch, but never while compiling libraries
|
||||||
// or the core. The user's sketch might contain the same filename!
|
// or the core. The user's sketch might contain the same filename!
|
||||||
e = sketch.placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1);
|
e = placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace full file path with the name of the sketch tab (unless we're
|
// replace full file path with the name of the sketch tab (unless we're
|
||||||
@ -656,7 +677,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
// 2. compile the libraries, outputting .o files to:
|
// 2. compile the libraries, outputting .o files to:
|
||||||
// <buildPath>/<library>/
|
// <buildPath>/<library>/
|
||||||
void compileLibraries(List<File> includeFolders) throws RunnerException {
|
void compileLibraries(List<File> includeFolders) throws RunnerException {
|
||||||
for (Library lib : sketch.getImportedLibraries()) {
|
for (Library lib : importedLibraries) {
|
||||||
compileLibrary(lib, includeFolders);
|
compileLibrary(lib, includeFolders);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -853,4 +874,144 @@ public class Compiler implements MessageConsumer {
|
|||||||
public PreferencesMap getBuildPreferences() {
|
public PreferencesMap getBuildPreferences() {
|
||||||
return prefs;
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build all the code for this sketch.
|
||||||
|
*
|
||||||
|
* In an advanced program, the returned class name could be different,
|
||||||
|
* which is why the className is set based on the return value.
|
||||||
|
* A compilation error will burp up a RunnerException.
|
||||||
|
*
|
||||||
|
* Setting purty to 'true' will cause exception line numbers to be incorrect.
|
||||||
|
* Unless you know the code compiles, you should first run the preprocessor
|
||||||
|
* with purty set to false to make sure there are no errors, then once
|
||||||
|
* successful, re-export with purty set to true.
|
||||||
|
*
|
||||||
|
* @param buildPath Location to copy all the .java files
|
||||||
|
* @return null if compilation failed, main class name if not
|
||||||
|
*/
|
||||||
|
public void preprocess(String buildPath) throws RunnerException {
|
||||||
|
preprocess(buildPath, new PdePreprocessor());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preprocess(String buildPath, PdePreprocessor preprocessor) throws RunnerException {
|
||||||
|
|
||||||
|
// 1. concatenate all .pde files to the 'main' pde
|
||||||
|
// store line number for starting point of each code bit
|
||||||
|
|
||||||
|
StringBuffer bigCode = new StringBuffer();
|
||||||
|
int bigCount = 0;
|
||||||
|
for (SketchCodeDocument scd : sketch.getCodeDocs()) {
|
||||||
|
SketchCode sc = scd.getCode();
|
||||||
|
if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||||
|
sc.setPreprocOffset(bigCount);
|
||||||
|
// These #line directives help the compiler report errors with
|
||||||
|
// correct the filename and line number (issue 281 & 907)
|
||||||
|
bigCode.append("#line 1 \"" + sc.getFileName() + "\"\n");
|
||||||
|
bigCode.append(sc.getProgram());
|
||||||
|
bigCode.append('\n');
|
||||||
|
bigCount += sc.getLineCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the headerOffset isn't applied until compile and run, because
|
||||||
|
// it only applies to the code after it's been written to the .java file.
|
||||||
|
int headerOffset = 0;
|
||||||
|
try {
|
||||||
|
headerOffset = preprocessor.writePrefix(bigCode.toString());
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
fnfe.printStackTrace();
|
||||||
|
String msg = _("Build folder disappeared or could not be written");
|
||||||
|
throw new RunnerException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. run preproc on that code using the sugg class name
|
||||||
|
// to create a single .java file and write to buildpath
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Output file
|
||||||
|
File streamFile = new File(buildPath, sketch.getName() + ".cpp");
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(streamFile);
|
||||||
|
preprocessor.write(outputStream);
|
||||||
|
outputStream.close();
|
||||||
|
} catch (FileNotFoundException fnfe) {
|
||||||
|
fnfe.printStackTrace();
|
||||||
|
String msg = _("Build folder disappeared or could not be written");
|
||||||
|
throw new RunnerException(msg);
|
||||||
|
} catch (RunnerException pe) {
|
||||||
|
// RunnerExceptions are caught here and re-thrown, so that they don't
|
||||||
|
// get lost in the more general "Exception" handler below.
|
||||||
|
throw pe;
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// TODO better method for handling this?
|
||||||
|
System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass()));
|
||||||
|
ex.printStackTrace();
|
||||||
|
throw new RunnerException(ex.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// grab the imports from the code just preproc'd
|
||||||
|
|
||||||
|
importedLibraries = new LibraryList();
|
||||||
|
for (String item : preprocessor.getExtraImports()) {
|
||||||
|
Library lib = Base.importToLibraryTable.get(item);
|
||||||
|
if (lib != null && !importedLibraries.contains(lib)) {
|
||||||
|
importedLibraries.add(lib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. then loop over the code[] and save each .java file
|
||||||
|
|
||||||
|
for (SketchCodeDocument scd : sketch.getCodeDocs()) {
|
||||||
|
SketchCode sc = scd.getCode();
|
||||||
|
if (sc.isExtension("c") || sc.isExtension("cpp") || sc.isExtension("h")) {
|
||||||
|
// no pre-processing services necessary for java files
|
||||||
|
// just write the the contents of 'program' to a .java file
|
||||||
|
// into the build directory. uses byte stream and reader/writer
|
||||||
|
// shtuff so that unicode bunk is properly handled
|
||||||
|
String filename = sc.getFileName(); //code[i].name + ".java";
|
||||||
|
try {
|
||||||
|
Base.saveFile(sc.getProgram(), new File(buildPath, filename));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RunnerException(I18n.format(_("Problem moving {0} to the build folder"), filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (sc.isExtension("ino") || sc.isExtension("pde")) {
|
||||||
|
// The compiler and runner will need this to have a proper offset
|
||||||
|
sc.addPreprocOffset(headerOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of library folders.
|
||||||
|
*/
|
||||||
|
private LibraryList importedLibraries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map an error from a set of processed .java files back to its location
|
||||||
|
* in the actual sketch.
|
||||||
|
* @param message The error message.
|
||||||
|
* @param dotJavaFilename The .java file where the exception was found.
|
||||||
|
* @param dotJavaLine Line number of the .java file for the exception (0-indexed!)
|
||||||
|
* @return A RunnerException to be sent to the editor, or null if it wasn't
|
||||||
|
* possible to place the exception to the sketch code.
|
||||||
|
*/
|
||||||
|
public RunnerException placeException(String message,
|
||||||
|
String dotJavaFilename,
|
||||||
|
int dotJavaLine) {
|
||||||
|
// Placing errors is simple, because we inserted #line directives
|
||||||
|
// into the preprocessed source. The compiler gives us correct
|
||||||
|
// the file name and line number. :-)
|
||||||
|
for (SketchCodeDocument codeDoc : sketch.getCodeDocs()) {
|
||||||
|
SketchCode code = codeDoc.getCode();
|
||||||
|
if (dotJavaFilename.equals(code.getFileName())) {
|
||||||
|
return new RunnerException(message, sketch.indexOfCode(code), dotJavaLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user