diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 131f75c87..aaa28162f 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -1010,6 +1010,7 @@ public class Base { Preferences.set("target", (String) getValue("target")); Preferences.set("board", (String) getValue("board")); onBoardOrPortChange(); + Sketch.buildSettingChanged(); } }; action.putValue("target", target.getName()); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 5572c62d0..423b20559 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -116,7 +116,6 @@ public class Preferences { JCheckBox exportSeparateBox; JCheckBox verboseCompilationBox; JCheckBox verboseUploadBox; - JCheckBox deletePreviousBox; JCheckBox externalEditorBox; JCheckBox memoryOverrideBox; JTextField memoryField; @@ -302,17 +301,6 @@ public class Preferences { top += d.height + GUI_BETWEEN; - // [ ] Delete previous applet or application folder on export - - deletePreviousBox = - new JCheckBox(_("Delete previous applet or application folder on export")); - pain.add(deletePreviousBox); - d = deletePreviousBox.getPreferredSize(); - deletePreviousBox.setBounds(left, top, d.width + 10, d.height); - right = Math.max(right, left + d.width); - top += d.height + GUI_BETWEEN; - - // [ ] Use external editor externalEditorBox = new JCheckBox(_("Use external editor")); @@ -494,8 +482,6 @@ public class Preferences { // put each of the settings into the table setBoolean("build.verbose", verboseCompilationBox.isSelected()); setBoolean("upload.verbose", verboseUploadBox.isSelected()); - setBoolean("export.delete_target_folder", - deletePreviousBox.isSelected()); // setBoolean("sketchbook.closing_last_window_quits", // closingLastQuitsBox.isSelected()); @@ -553,8 +539,6 @@ public class Preferences { // set all settings entry boxes to their actual status verboseCompilationBox.setSelected(getBoolean("build.verbose")); verboseUploadBox.setSelected(getBoolean("upload.verbose")); - deletePreviousBox. - setSelected(getBoolean("export.delete_target_folder")); //closingLastQuitsBox. // setSelected(getBoolean("sketchbook.closing_last_window_quits")); diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 6c425927e..1d540c374 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -1210,11 +1210,39 @@ public class Sketch { // won't be able to delete them, so we need to force a gc here System.gc(); - // note that we can't remove the builddir itself, otherwise - // the next time we start up, internal runs using Runner won't - // work because the build dir won't exist at startup, so the classloader - // will ignore the fact that that dir is in the CLASSPATH in run.sh - Base.removeDescendants(tempBuildFolder); + if (deleteFilesOnNextBuild) { + // delete the entire directory and all contents + // when we know something changed and all objects + // need to be recompiled, or if the board does not + // use setting build.dependency + //Base.removeDir(tempBuildFolder); + + // note that we can't remove the builddir itself, otherwise + // the next time we start up, internal runs using Runner won't + // work because the build dir won't exist at startup, so the classloader + // will ignore the fact that that dir is in the CLASSPATH in run.sh + Base.removeDescendants(tempBuildFolder); + + deleteFilesOnNextBuild = false; + } else { + // delete only stale source files, from the previously + // compiled sketch. This allows multiple windows to be + // used. Keep everything else, which might be reusable + if (tempBuildFolder.exists()) { + String files[] = tempBuildFolder.list(); + for (String file : files) { + if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".s")) { + File deleteMe = new File(tempBuildFolder, file); + if (!deleteMe.delete()) { + System.err.println("Could not delete " + deleteMe); + } + } + } + } + } + + // Create a fresh applet folder (needed before preproc is run below) + //tempBuildFolder.mkdirs(); } @@ -1246,6 +1274,12 @@ public class Sketch { */ //protected String compile() throws RunnerException { + // called when any setting changes that requires all files to be recompiled + public static void buildSettingChanged() { + deleteFilesOnNextBuild = true; + } + + private static boolean deleteFilesOnNextBuild = true; /** * When running from the editor, take care of preparations before running @@ -1606,30 +1640,12 @@ public class Sketch { */ public boolean exportApplet(String appletPath, boolean usingProgrammer) throws RunnerException, IOException, SerialException { - - // Make sure the user didn't hide the sketch folder - ensureExistence(); - - current.setProgram(editor.getText()); - - // Reload the code when an external editor is being used - if (Preferences.getBoolean("editor.external")) { - current = null; - // nuke previous files and settings - load(); - } - - File appletFolder = new File(appletPath); - // Nuke the old applet folder because it can cause trouble - if (Preferences.getBoolean("export.delete_target_folder")) { - Base.removeDir(appletFolder); - } - // Create a fresh applet folder (needed before preproc is run below) - appletFolder.mkdirs(); + prepare(); + // build the sketch editor.status.progressNotice(_("Compiling sketch...")); - String foundName = build(appletFolder.getPath(), false); + String foundName = build(appletPath, false); // (already reported) error during export, exit this function if (foundName == null) return false; @@ -1643,7 +1659,7 @@ public class Sketch { // } editor.status.progressNotice(_("Uploading...")); - upload(appletFolder.getPath(), foundName, usingProgrammer); + upload(appletPath, foundName, usingProgrammer); editor.status.progressUpdate(100); return true; } diff --git a/app/src/processing/app/debug/Compiler.java b/app/src/processing/app/debug/Compiler.java index df027ae15..29953666d 100644 --- a/app/src/processing/app/debug/Compiler.java +++ b/app/src/processing/app/debug/Compiler.java @@ -269,7 +269,11 @@ public class Compiler implements MessageConsumer { for (File file : cSources) { String objectPath = buildPath + File.separator + file.getName() + ".o"; - objectPaths.add(new File(objectPath)); + String dependPath = buildPath + File.separator + file.getName() + ".d"; + File objectFile = new File(objectPath); + File dependFile = new File(dependPath); + objectPaths.add(objectFile); + if (is_already_compiled(file, objectFile, dependFile, boardPreferences)) continue; execAsynchronously(getCommandCompilerC(avrBasePath, includePaths, file.getAbsolutePath(), objectPath, @@ -278,7 +282,11 @@ public class Compiler implements MessageConsumer { for (File file : cppSources) { String objectPath = buildPath + File.separator + file.getName() + ".o"; - objectPaths.add(new File(objectPath)); + String dependPath = buildPath + File.separator + file.getName() + ".d"; + File objectFile = new File(objectPath); + File dependFile = new File(dependPath); + objectPaths.add(objectFile); + if (is_already_compiled(file, objectFile, dependFile, boardPreferences)) continue; execAsynchronously(getCommandCompilerCPP(avrBasePath, includePaths, file.getAbsolutePath(), objectPath, @@ -288,6 +296,68 @@ public class Compiler implements MessageConsumer { return objectPaths; } + private boolean is_already_compiled(File src, File obj, File dep, Map prefs) { + boolean ret=true; + try { + //System.out.println("\n is_already_compiled: begin checks: " + obj.getPath()); + if (!obj.exists()) return false; // object file (.o) does not exist + if (!dep.exists()) return false; // dep file (.d) does not exist + long src_modified = src.lastModified(); + long obj_modified = obj.lastModified(); + if (src_modified >= obj_modified) return false; // source modified since object compiled + if (src_modified >= dep.lastModified()) return false; // src modified since dep compiled + BufferedReader reader = new BufferedReader(new FileReader(dep.getPath())); + String line; + boolean need_obj_parse = true; + while ((line = reader.readLine()) != null) { + if (line.endsWith("\\")) { + line = line.substring(0, line.length() - 1); + } + line = line.trim(); + if (line.length() == 0) continue; // ignore blank lines + if (need_obj_parse) { + // line is supposed to be the object file - make sure it really is! + if (line.endsWith(":")) { + line = line.substring(0, line.length() - 1); + String objpath = obj.getCanonicalPath(); + File linefile = new File(line); + String linepath = linefile.getCanonicalPath(); + //System.out.println(" is_already_compiled: obj = " + objpath); + //System.out.println(" is_already_compiled: line = " + linepath); + if (objpath.compareTo(linepath) == 0) { + need_obj_parse = false; + continue; + } else { + ret = false; // object named inside .d file is not the correct file! + break; + } + } else { + ret = false; // object file supposed to end with ':', but didn't + break; + } + } else { + // line is a prerequisite file + File prereq = new File(line); + if (!prereq.exists()) { + ret = false; // prerequisite file did not exist + break; + } + if (prereq.lastModified() >= obj_modified) { + ret = false; // prerequisite modified since object was compiled + break; + } + //System.out.println(" is_already_compiled: prerequisite ok"); + } + } + reader.close(); + } catch (Exception e) { + return false; // any error reading dep file = recompile it + } + if (ret && (verbose || Preferences.getBoolean("build.verbose"))) { + System.out.println(" Using previously compiled: " + obj.getPath()); + } + return ret; + } boolean firstErrorFound; boolean secondErrorFound; @@ -490,6 +560,7 @@ public class Compiler implements MessageConsumer { "-fdata-sections", "-mmcu=" + boardPreferences.get("build.mcu"), "-DF_CPU=" + boardPreferences.get("build.f_cpu"), + "-MMD", // output dependancy info "-DARDUINO=" + Base.REVISION, })); @@ -498,7 +569,8 @@ public class Compiler implements MessageConsumer { } baseCommandCompiler.add(sourceName); - baseCommandCompiler.add("-o"+ objectName); + baseCommandCompiler.add("-o"); + baseCommandCompiler.add(objectName); return baseCommandCompiler; } @@ -519,6 +591,7 @@ public class Compiler implements MessageConsumer { "-fdata-sections", "-mmcu=" + boardPreferences.get("build.mcu"), "-DF_CPU=" + boardPreferences.get("build.f_cpu"), + "-MMD", // output dependancy info "-DARDUINO=" + Base.REVISION, })); @@ -527,7 +600,8 @@ public class Compiler implements MessageConsumer { } baseCommandCompilerCPP.add(sourceName); - baseCommandCompilerCPP.add("-o"+ objectName); + baseCommandCompilerCPP.add("-o"); + baseCommandCompilerCPP.add(objectName); return baseCommandCompilerCPP; } diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp index e7a29323b..62bbfebc0 100755 --- a/libraries/Ethernet/Dhcp.cpp +++ b/libraries/Ethernet/Dhcp.cpp @@ -163,15 +163,15 @@ void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) // OPT - host name buffer[16] = hostName; - buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address strcpy((char*)&(buffer[18]), HOST_NAME); - buffer[24] = _dhcpMacAddr[3]; - buffer[25] = _dhcpMacAddr[4]; - buffer[26] = _dhcpMacAddr[5]; + printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); + printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); + printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); //put data in W5100 transmit buffer - _dhcpUdpSocket.write(buffer, 27); + _dhcpUdpSocket.write(buffer, 30); if(messageType == DHCP_REQUEST) { @@ -347,3 +347,13 @@ IPAddress DhcpClass::getDnsServerIp() return IPAddress(_dhcpDnsServerIp); } +void DhcpClass::printByte(char * buf, uint8_t n ) { + char *str = &buf[1]; + buf[0]='0'; + do { + unsigned long m = n; + n /= 16; + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); +} diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h index f87719959..149876d79 100755 --- a/libraries/Ethernet/Dhcp.h +++ b/libraries/Ethernet/Dhcp.h @@ -143,6 +143,7 @@ private: void presend_DHCP(); void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); public: