Skip to content

Commit 4592acc

Browse files
Change the logic deciding when to do a full rebuild
Previously, a full cleanup of the work directory (and thus a full rebuild) was done on the first build after: - startup, or - a change in the board or board suboption. This did not cooperate nicely with commandline compilation using --verify. Using the build.path option a persistent build path could be used, but the actual files in that path would never be reused. Now, each build saves the preferences used for building in a file "buildprefs.txt" inside the build directory. Subsequent builds will read this file to see if any build options changed and re-use the existing files if the build options are identical. Because the main .cpp file is not handled by Compiler::build, but by Sketch::preprocess, it is still always regenerated, even if the Sketch itself didn't change. This could be fixed later, though it is probably not a problem. When writing buildprefs.txt, only the build preferences starting with "build.", "compiler." or "recipes." are used. These should be enough to ensure files are always rebuilt when needed (probably also sometimes when not needed, when change build.verbose for example). Using all build preferences would cause the files to be rebuild too often, and because of last.ide.xxx.daterun, they would still rebuild on _every_ invocation... This approach is perhaps not ideal, but improving it would require putting more structure in the preferences instead of piling them all together into the build preferences. Because of this new mechanism, the old buildSettingsChanged()/deleteFilesOnNextBuild could be removed.
1 parent 7b7f447 commit 4592acc

File tree

3 files changed

+69
-23
lines changed

3 files changed

+69
-23
lines changed

app/src/processing/app/Base.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,6 @@ public void actionPerformed(ActionEvent actionevent) {
14541454
Action subAction = new AbstractAction(_(boardCustomMenu.get(customMenuOption))) {
14551455
public void actionPerformed(ActionEvent e) {
14561456
Preferences.set("custom_" + menuId, ((TargetBoard)getValue("board")).getId() + "_" + getValue("custom_menu_option"));
1457-
Sketch.buildSettingChanged();
14581457
}
14591458
};
14601459
subAction.putValue("board", board);
@@ -1568,7 +1567,6 @@ private void selectBoard(TargetBoard targetBoard) {
15681567
filterVisibilityOfSubsequentBoardMenus(targetBoard, 1);
15691568

15701569
onBoardOrPortChange();
1571-
Sketch.buildSettingChanged();
15721570
rebuildImportMenu(Editor.importMenu);
15731571
rebuildExamplesMenu(Editor.examplesMenu);
15741572
}

app/src/processing/app/Editor.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,8 +2007,6 @@ public void internalCloseRunner() {
20072007
try {
20082008
stopHandler.run();
20092009
} catch (Exception e) { }
2010-
2011-
sketch.cleanup();
20122010
}
20132011

20142012

app/src/processing/app/Sketch.java

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import processing.app.debug.Compiler;
3232
import processing.app.forms.PasswordAuthorizationDialog;
3333
import processing.app.helpers.PreferencesMap;
34+
import processing.app.helpers.FileUtils;
3435
import processing.app.packages.Library;
3536
import processing.app.packages.LibraryList;
3637
import processing.app.preproc.*;
@@ -96,6 +97,12 @@ public class Sketch {
9697
*/
9798
private LibraryList importedLibraries;
9899

100+
/**
101+
* File inside the build directory that contains the build options
102+
* used for the last build.
103+
*/
104+
static final String BUILD_PREFS_FILE = "buildprefs.txt";
105+
99106
/**
100107
* path is location of the main .pde file, because this is also
101108
* simplest to use when opening the file from the finder/explorer.
@@ -1182,12 +1189,12 @@ protected void setCurrentCode(String findName) {
11821189
/**
11831190
* Cleanup temporary files used during a build/run.
11841191
*/
1185-
protected void cleanup() {
1192+
protected void cleanup(boolean force) {
11861193
// if the java runtime is holding onto any files in the build dir, we
11871194
// won't be able to delete them, so we need to force a gc here
11881195
System.gc();
11891196

1190-
if (deleteFilesOnNextBuild) {
1197+
if (force) {
11911198
// delete the entire directory and all contents
11921199
// when we know something changed and all objects
11931200
// need to be recompiled, or if the board does not
@@ -1199,8 +1206,6 @@ protected void cleanup() {
11991206
// work because the build dir won't exist at startup, so the classloader
12001207
// will ignore the fact that that dir is in the CLASSPATH in run.sh
12011208
Base.removeDescendants(tempBuildFolder);
1202-
1203-
deleteFilesOnNextBuild = false;
12041209
} else {
12051210
// delete only stale source files, from the previously
12061211
// compiled sketch. This allows multiple windows to be
@@ -1251,13 +1256,6 @@ protected void cleanup() {
12511256
*/
12521257
//protected String compile() throws RunnerException {
12531258

1254-
// called when any setting changes that requires all files to be recompiled
1255-
public static void buildSettingChanged() {
1256-
deleteFilesOnNextBuild = true;
1257-
}
1258-
1259-
private static boolean deleteFilesOnNextBuild = true;
1260-
12611259
/**
12621260
* When running from the editor, take care of preparations before running
12631261
* the build.
@@ -1286,12 +1284,6 @@ public void prepare() throws IOException {
12861284
load();
12871285
}
12881286

1289-
// in case there were any boogers left behind
1290-
// do this here instead of after exiting, since the exit
1291-
// can happen so many different ways.. and this will be
1292-
// better connected to the dataFolder stuff below.
1293-
cleanup();
1294-
12951287
// // handle preprocessing the main file's code
12961288
// return build(tempBuildFolder.getAbsolutePath());
12971289
}
@@ -1518,6 +1510,46 @@ public String build(boolean verbose) throws RunnerException {
15181510
return build(tempBuildFolder.getAbsolutePath(), verbose);
15191511
}
15201512

1513+
/**
1514+
* Check if the build preferences used on the previous build in
1515+
* buildPath match the ones given.
1516+
*/
1517+
protected boolean buildPreferencesChanged(File buildPrefsFile, String newBuildPrefs) {
1518+
// No previous build, so no match
1519+
if (!buildPrefsFile.exists())
1520+
return true;
1521+
1522+
String previousPrefs;
1523+
try {
1524+
previousPrefs = FileUtils.readFileToString(buildPrefsFile);
1525+
} catch (IOException e) {
1526+
System.err.println(_("Could not read prevous build preferences file, rebuilding all"));
1527+
return true;
1528+
}
1529+
1530+
if (!previousPrefs.equals(newBuildPrefs)) {
1531+
System.out.println(_("Build options changed, rebuilding all"));
1532+
return true;
1533+
} else {
1534+
return false;
1535+
}
1536+
}
1537+
1538+
/**
1539+
* Returns the build preferences of the given compiler as a string.
1540+
* Only includes build-specific preferences, to make sure unrelated
1541+
* preferences don't cause a rebuild (in particular preferences that
1542+
* change on every start, like last.ide.xxx.daterun). */
1543+
protected String buildPrefsString(Compiler compiler) {
1544+
PreferencesMap buildPrefs = compiler.getBuildPreferences();
1545+
String res = "";
1546+
SortedSet<String> treeSet = new TreeSet<String>(buildPrefs.keySet());
1547+
for (String k : treeSet) {
1548+
if (k.startsWith("build.") || k.startsWith("compiler.") || k.startsWith("recipes."))
1549+
res += k + " = " + buildPrefs.get(k) + "\n";
1550+
}
1551+
return res;
1552+
}
15211553

15221554
/**
15231555
* Preprocess and compile all the code for this sketch.
@@ -1529,14 +1561,32 @@ public String build(boolean verbose) throws RunnerException {
15291561
* @return null if compilation failed, main class name if not
15301562
*/
15311563
public String build(String buildPath, boolean verbose) throws RunnerException {
1564+
String primaryClassName = name + ".cpp";
1565+
Compiler compiler = new Compiler(this, buildPath, primaryClassName);
1566+
File buildPrefsFile = new File(buildPath, BUILD_PREFS_FILE);
1567+
String newBuildPrefs = buildPrefsString(compiler);
1568+
1569+
// Do a forced cleanup (throw everything away) if the previous
1570+
// build settings do not match the previous ones
1571+
boolean prefsChanged = buildPreferencesChanged(buildPrefsFile, newBuildPrefs);
1572+
cleanup(prefsChanged);
1573+
1574+
if (prefsChanged) {
1575+
try {
1576+
PrintWriter out = new PrintWriter(buildPrefsFile);
1577+
out.print(newBuildPrefs);
1578+
out.close();
1579+
} catch (IOException e) {
1580+
System.err.println(_("Could not write build preferences file"));
1581+
}
1582+
}
1583+
15321584
// run the preprocessor
15331585
editor.status.progressUpdate(20);
1534-
String primaryClassName = name + ".cpp";
15351586
preprocess(buildPath);
15361587

15371588
// compile the program. errors will happen as a RunnerException
15381589
// that will bubble up to whomever called build().
1539-
Compiler compiler = new Compiler(this, buildPath, primaryClassName);
15401590
if (compiler.compile(verbose)) {
15411591
size(compiler.getBuildPreferences());
15421592
return primaryClassName;

0 commit comments

Comments
 (0)