| /* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ |
| |
| /* |
| Part of the Processing project - http://processing.org |
| |
| 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 |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software Foundation, |
| Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| package processing.app.debug; |
| |
| import static processing.app.I18n._; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import processing.app.Base; |
| import processing.app.I18n; |
| import processing.app.Preferences; |
| import processing.app.Sketch; |
| import processing.app.SketchCode; |
| import processing.app.helpers.PreferencesMap; |
| import processing.app.helpers.StringReplacer; |
| import processing.core.PApplet; |
| |
| public class Compiler implements MessageConsumer { |
| static final String BUGS_URL = |
| _("http://code.google.com/p/arduino/issues/list"); |
| static final String SUPER_BADNESS = |
| I18n.format(_("Compiler error, please submit this code to {0}"), BUGS_URL); |
| |
| private Sketch sketch; |
| |
| private List<File> objectFiles; |
| |
| private PreferencesMap prefs; |
| private boolean verbose; |
| |
| private RunnerException exception; |
| |
| /** |
| * Compile sketch. |
| * |
| * @param _sketch Sketch object to be compiled. |
| * @param _buildPath Where the temporary files live and will be built from. |
| * @param _primaryClassName the name of the combined sketch file w/ extension |
| * @return true if successful. |
| * @throws RunnerException Only if there's a problem. Only then. |
| */ |
| public boolean compile(Sketch _sketch, String _buildPath, |
| String _primaryClassName, boolean _verbose) |
| throws RunnerException { |
| sketch = _sketch; |
| verbose = _verbose; |
| objectFiles = new ArrayList<File>(); |
| |
| prefs = createBuildPreferences(_buildPath, _primaryClassName); |
| |
| // 0. include paths for core + all libraries |
| sketch.setCompilingProgress(20); |
| List<String> includePaths = new ArrayList<String>(); |
| includePaths.add(prefs.get("build.core.path")); |
| if (!prefs.get("build.variant.path").isEmpty()) |
| includePaths.add(prefs.get("build.variant.path")); |
| for (File file : sketch.getImportedLibraries()) |
| includePaths.add(file.getPath()); |
| |
| // 1. compile the sketch (already in the buildPath) |
| sketch.setCompilingProgress(30); |
| compileSketch(includePaths); |
| |
| // 2. compile the libraries, outputting .o files to: <buildPath>/<library>/ |
| // Doesn't really use configPreferences |
| sketch.setCompilingProgress(40); |
| compileLibraries(includePaths); |
| |
| // 3. compile the core, outputting .o files to <buildPath> and then |
| // collecting them into the core.a library file. |
| sketch.setCompilingProgress(50); |
| compileCore(); |
| |
| // 4. link it all together into the .elf file |
| sketch.setCompilingProgress(60); |
| compileLink(includePaths); |
| |
| // 5. extract EEPROM data (from EEMEM directive) to .eep file. |
| sketch.setCompilingProgress(70); |
| compileEep(includePaths); |
| |
| // 6. build the .hex file |
| sketch.setCompilingProgress(80); |
| compileHex(includePaths); |
| |
| sketch.setCompilingProgress(90); |
| return true; |
| } |
| |
| private PreferencesMap createBuildPreferences(String _buildPath, |
| String _primaryClassName) |
| throws RunnerException { |
| |
| if (Base.getBoardPreferences() == null) { |
| RunnerException re = new RunnerException( |
| _("No board selected; please choose a board from the Tools > Board menu.")); |
| re.hideStackTrace(); |
| throw re; |
| } |
| |
| TargetPlatform targetPlatform = Base.getTargetPlatform(); |
| |
| // Merge all the global preference configuration in order of priority |
| PreferencesMap p = new PreferencesMap(); |
| p.putAll(Preferences.getMap()); |
| p.putAll(targetPlatform.getPreferences()); |
| p.putAll(Base.getBoardPreferences()); |
| for (String k : p.keySet()) { |
| if (p.get(k) == null) |
| p.put(k, ""); |
| } |
| |
| p.put("build.path", _buildPath); |
| p.put("build.project_name", _primaryClassName); |
| |
| if (!p.containsKey("compiler.path")) |
| p.put("compiler.path", Base.getAvrBasePath()); |
| |
| // Core folder |
| String core = p.get("build.core"); |
| TargetPlatform tp; |
| if (!core.contains(":")) { |
| tp = targetPlatform; |
| } else { |
| String[] split = core.split(":", 2); |
| tp = Base.getTargetPlatform(split[0], Preferences.get("target_platform")); |
| core = split[1]; |
| } |
| File coreFolder = new File(tp.getFolder(), "cores"); |
| coreFolder = new File(coreFolder, core); |
| p.put("build.core.path", coreFolder.getAbsolutePath()); |
| |
| // System Folder |
| File systemFolder = targetPlatform.getFolder(); |
| systemFolder = new File(systemFolder, "system"); |
| p.put("build.system.path", systemFolder.getAbsolutePath()); |
| |
| // Variant Folder |
| String variant = p.get("build.variant"); |
| if (variant != null) { |
| TargetPlatform t; |
| if (!variant.contains(":")) { |
| t = targetPlatform; |
| } else { |
| String[] split = variant.split(":", 2); |
| t = Base |
| .getTargetPlatform(split[0], Preferences.get("target_platform")); |
| variant = split[1]; |
| } |
| File variantFolder = new File(t.getFolder(), "variants"); |
| variantFolder = new File(variantFolder, variant); |
| p.put("build.variant.path", variantFolder.getAbsolutePath()); |
| } else { |
| p.put("build.variant.path", ""); |
| } |
| |
| return p; |
| } |
| |
| private List<File> compileFiles(String outputPath, File sourcePath, |
| boolean recurse, List<String> includePaths) |
| throws RunnerException { |
| List<File> sSources = findFilesInFolder(sourcePath, "S", recurse); |
| List<File> cSources = findFilesInFolder(sourcePath, "c", recurse); |
| List<File> cppSources = findFilesInFolder(sourcePath, "cpp", recurse); |
| List<File> objectPaths = new ArrayList<File>(); |
| |
| for (File file : sSources) { |
| String objectPath = outputPath + File.separator + file.getName() + ".o"; |
| objectPaths.add(new File(objectPath)); |
| String[] cmd = getCommandCompilerS(includePaths, file.getAbsolutePath(), |
| objectPath); |
| execAsynchronously(cmd); |
| } |
| |
| for (File file : cSources) { |
| String objectPath = outputPath + File.separator + file.getName() + ".o"; |
| String dependPath = outputPath + 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, prefs)) |
| continue; |
| String[] cmd = getCommandCompilerC(includePaths, file.getAbsolutePath(), |
| objectPath); |
| execAsynchronously(cmd); |
| } |
| |
| for (File file : cppSources) { |
| String objectPath = outputPath + File.separator + file.getName() + ".o"; |
| String dependPath = outputPath + 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, prefs)) |
| continue; |
| String[] cmd = getCommandCompilerCPP(includePaths, |
| file.getAbsolutePath(), objectPath); |
| execAsynchronously(cmd); |
| } |
| |
| return objectPaths; |
| } |
| |
| private boolean is_already_compiled(File src, File obj, File dep, Map<String, String> 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; |
| |
| /** |
| * Either succeeds or throws a RunnerException fit for public consumption. |
| */ |
| private void execAsynchronously(String[] command) throws RunnerException { |
| |
| // eliminate any empty array entries |
| List<String> stringList = new ArrayList<String>(); |
| for (String string : command) { |
| string = string.trim(); |
| if (!string.isEmpty()) |
| stringList.add(string); |
| } |
| command = stringList.toArray(new String[stringList.size()]); |
| if (command.length == 0) |
| return; |
| int result = 0; |
| |
| if (verbose || Preferences.getBoolean("build.verbose")) { |
| for (String c : command) |
| System.out.print(c + " "); |
| System.out.println(); |
| } |
| |
| firstErrorFound = false; // haven't found any errors yet |
| secondErrorFound = false; |
| |
| Process process; |
| |
| try { |
| process = Runtime.getRuntime().exec(command); |
| } catch (IOException e) { |
| RunnerException re = new RunnerException(e.getMessage()); |
| re.hideStackTrace(); |
| throw re; |
| } |
| |
| MessageSiphon in = new MessageSiphon(process.getInputStream(), this); |
| MessageSiphon err = new MessageSiphon(process.getErrorStream(), this); |
| |
| // wait for the process to finish. if interrupted |
| // before waitFor returns, continue waiting |
| boolean compiling = true; |
| while (compiling) { |
| try { |
| if (in.thread != null) |
| in.thread.join(); |
| if (err.thread != null) |
| err.thread.join(); |
| result = process.waitFor(); |
| //System.out.println("result is " + result); |
| compiling = false; |
| } catch (InterruptedException ignored) { } |
| } |
| |
| // an error was queued up by message(), barf this back to compile(), |
| // 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 (result > 1) { |
| // a failure in the tool (e.g. unable to locate a sub-executable) |
| System.err |
| .println(I18n.format(_("{0} returned {1}"), command[0], result)); |
| } |
| |
| if (result != 0) { |
| RunnerException re = new RunnerException(_("Error compiling.")); |
| re.hideStackTrace(); |
| throw re; |
| } |
| } |
| |
| /** |
| * 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) { |
| int i; |
| |
| // remove the build path so people only see the filename |
| // can't use replaceAll() because the path may have characters in it which |
| // have meaning in a regular expression. |
| if (!verbose) { |
| String buildPath = prefs.get("build.path"); |
| while ((i = s.indexOf(buildPath + File.separator)) != -1) { |
| s = s.substring(0, i) + s.substring(i + (buildPath + File.separator).length()); |
| } |
| } |
| |
| // look for error line, which contains file name, line number, |
| // and at least the first line of the error message |
| String errorFormat = "([\\w\\d_]+.\\w+):(\\d+):\\s*error:\\s*(.*)\\s*"; |
| String[] pieces = PApplet.match(s, errorFormat); |
| |
| // if (pieces != null && exception == null) { |
| // exception = sketch.placeException(pieces[3], pieces[1], PApplet.parseInt(pieces[2]) - 1); |
| // if (exception != null) exception.hideStackTrace(); |
| // } |
| |
| if (pieces != null) { |
| String error = pieces[3], msg = ""; |
| |
| if (pieces[3].trim().equals("SPI.h: No such file or directory")) { |
| error = _("Please import the SPI library from the Sketch > Import Library menu."); |
| msg = _("\nAs of Arduino 0019, the Ethernet library depends on the SPI library." + |
| "\nYou appear to be using it or another library that depends on the SPI library.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'BYTE' was not declared in this scope")) { |
| error = _("The 'BYTE' keyword is no longer supported."); |
| msg = _("\nAs of Arduino 1.0, the 'BYTE' keyword is no longer supported." + |
| "\nPlease use Serial.write() instead.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("no matching function for call to 'Server::Server(int)'")) { |
| error = _("The Server class has been renamed EthernetServer."); |
| msg = _("\nAs of Arduino 1.0, the Server class in the Ethernet library " + |
| "has been renamed to EthernetServer.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("no matching function for call to 'Client::Client(byte [4], int)'")) { |
| error = _("The Client class has been renamed EthernetClient."); |
| msg = _("\nAs of Arduino 1.0, the Client class in the Ethernet library " + |
| "has been renamed to EthernetClient.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'Udp' was not declared in this scope")) { |
| error = _("The Udp class has been renamed EthernetUdp."); |
| msg = _("\nAs of Arduino 1.0, the Udp class in the Ethernet library " + |
| "has been renamed to EthernetClient.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'class TwoWire' has no member named 'send'")) { |
| error = _("Wire.send() has been renamed Wire.write()."); |
| msg = _("\nAs of Arduino 1.0, the Wire.send() function was renamed " + |
| "to Wire.write() for consistency with other libraries.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'class TwoWire' has no member named 'receive'")) { |
| error = _("Wire.receive() has been renamed Wire.read()."); |
| msg = _("\nAs of Arduino 1.0, the Wire.receive() function was renamed " + |
| "to Wire.read() for consistency with other libraries.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'Mouse' was not declared in this scope")) { |
| error = _("'Mouse' only supported on the Arduino Leonardo"); |
| //msg = _("\nThe 'Mouse' class is only supported on the Arduino Leonardo.\n\n"); |
| } |
| |
| if (pieces[3].trim().equals("'Keyboard' was not declared in this scope")) { |
| error = _("'Keyboard' only supported on the Arduino Leonardo"); |
| //msg = _("\nThe 'Keyboard' class is only supported on the Arduino Leonardo.\n\n"); |
| } |
| |
| RunnerException e = sketch.placeException(error, pieces[1], PApplet.parseInt(pieces[2]) - 1); |
| |
| // replace full file path with the name of the sketch tab (unless we're |
| // in verbose mode, in which case don't modify the compiler output) |
| if (e != null && !verbose) { |
| SketchCode code = sketch.getCode(e.getCodeIndex()); |
| String fileName = code.isExtension(sketch.getDefaultExtension()) ? code.getPrettyName() : code.getFileName(); |
| s = fileName + ":" + e.getCodeLine() + ": error: " + pieces[3] + msg; |
| } |
| |
| if (exception == null && e != null) { |
| exception = e; |
| exception.hideStackTrace(); |
| } |
| } |
| |
| System.err.print(s); |
| } |
| |
| private String[] getCommandCompilerS(List<String> includePaths, |
| String sourceName, String objectName) |
| throws RunnerException { |
| String includes = preparePaths(includePaths); |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| dict.put("includes", includes); |
| dict.put("source_file", sourceName); |
| dict.put("object_file", objectName); |
| |
| try { |
| String cmd = prefs.get("recipe.S.o.pattern"); |
| return StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| } |
| |
| private String[] getCommandCompilerC(List<String> includePaths, |
| String sourceName, String objectName) |
| throws RunnerException { |
| String includes = preparePaths(includePaths); |
| |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| dict.put("includes", includes); |
| dict.put("source_file", sourceName); |
| dict.put("object_file", objectName); |
| |
| String cmd = prefs.get("recipe.c.o.pattern"); |
| try { |
| return StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| } |
| |
| private String[] getCommandCompilerCPP(List<String> includePaths, |
| String sourceName, String objectName) |
| throws RunnerException { |
| String includes = preparePaths(includePaths); |
| |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| dict.put("includes", includes); |
| dict.put("source_file", sourceName); |
| dict.put("object_file", objectName); |
| |
| String cmd = prefs.get("recipe.cpp.o.pattern"); |
| try { |
| return StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| private void createFolder(File folder) throws RunnerException { |
| if (folder.isDirectory()) |
| return; |
| if (!folder.mkdir()) |
| throw new RunnerException("Couldn't create: " + folder); |
| } |
| |
| static public List<File> findFilesInFolder(File folder, String extension, |
| boolean recurse) { |
| List<File> files = new ArrayList<File>(); |
| |
| if (folder.listFiles() == null) |
| return files; |
| |
| for (File file : folder.listFiles()) { |
| if (file.getName().startsWith(".")) |
| continue; // skip hidden files |
| |
| if (file.getName().endsWith("." + extension)) |
| files.add(file); |
| |
| if (recurse && file.isDirectory()) { |
| files.addAll(findFilesInFolder(file, extension, true)); |
| } |
| } |
| |
| return files; |
| } |
| |
| // 1. compile the sketch (already in the buildPath) |
| void compileSketch(List<String> includePaths) throws RunnerException { |
| String buildPath = prefs.get("build.path"); |
| objectFiles.addAll(compileFiles(buildPath, new File(buildPath), false, |
| includePaths)); |
| } |
| |
| // 2. compile the libraries, outputting .o files to: |
| // <buildPath>/<library>/ |
| void compileLibraries(List<String> includePaths) throws RunnerException { |
| |
| for (File libraryFolder : sketch.getImportedLibraries()) { |
| String outputPath = prefs.get("build.path"); |
| File outputFolder = new File(outputPath, libraryFolder.getName()); |
| File utilityFolder = new File(libraryFolder, "utility"); |
| createFolder(outputFolder); |
| // this library can use includes in its utility/ folder |
| includePaths.add(utilityFolder.getAbsolutePath()); |
| |
| objectFiles.addAll(compileFiles(outputFolder.getAbsolutePath(), |
| libraryFolder, false, includePaths)); |
| outputFolder = new File(outputFolder, "utility"); |
| createFolder(outputFolder); |
| objectFiles.addAll(compileFiles(outputFolder.getAbsolutePath(), |
| utilityFolder, false, includePaths)); |
| // other libraries should not see this library's utility/ folder |
| includePaths.remove(includePaths.size() - 1); |
| } |
| } |
| |
| // 3. compile the core, outputting .o files to <buildPath> and then |
| // collecting them into the core.a library file. |
| void compileCore() |
| throws RunnerException { |
| |
| String corePath = prefs.get("build.core.path"); |
| String variantPath = prefs.get("build.variant.path"); |
| String buildPath = prefs.get("build.path"); |
| |
| List<String> includePaths = new ArrayList<String>(); |
| includePaths.add(corePath); // include core path only |
| if (!variantPath.isEmpty()) |
| includePaths.add(variantPath); |
| |
| List<File> coreObjectFiles = compileFiles(buildPath, new File(corePath), |
| true, includePaths); |
| if (!variantPath.isEmpty()) |
| coreObjectFiles.addAll(compileFiles(buildPath, new File(variantPath), |
| true, includePaths)); |
| |
| for (File file : coreObjectFiles) { |
| |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| dict.put("archive_file", "core.a"); |
| dict.put("object_file", file.getAbsolutePath()); |
| |
| String[] cmdArray; |
| try { |
| String cmd = prefs.get("recipe.ar.pattern"); |
| cmdArray = StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| execAsynchronously(cmdArray); |
| } |
| } |
| |
| // 4. link it all together into the .elf file |
| void compileLink(List<String> includePaths) |
| throws RunnerException { |
| |
| // TODO: Make the --relax thing in configuration files. |
| |
| // For atmega2560, need --relax linker option to link larger |
| // programs correctly. |
| String optRelax = ""; |
| if (prefs.get("build.mcu").equals("atmega2560")) |
| optRelax = ",--relax"; |
| |
| String objectFileList = ""; |
| for (File file : objectFiles) |
| objectFileList += " \"" + file.getAbsolutePath() + '"'; |
| objectFileList = objectFileList.substring(1); |
| |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("compiler.c.elf.flags", dict |
| .get("compiler.c.elf.flags" + optRelax)); |
| dict.put("archive_file", "core.a"); |
| dict.put("object_files", objectFileList); |
| dict.put("ide_version", "" + Base.REVISION); |
| |
| String[] cmdArray; |
| try { |
| String cmd = prefs.get("recipe.c.combine.pattern"); |
| cmdArray = StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| execAsynchronously(cmdArray); |
| } |
| |
| // 5. extract EEPROM data (from EEMEM directive) to .eep file. |
| void compileEep(List<String> includePaths) throws RunnerException { |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| |
| String[] cmdArray; |
| try { |
| String cmd = prefs.get("recipe.objcopy.eep.pattern"); |
| cmdArray = StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| execAsynchronously(cmdArray); |
| } |
| |
| // 6. build the .hex file |
| void compileHex(List<String> includePaths) throws RunnerException { |
| PreferencesMap dict = new PreferencesMap(prefs); |
| dict.put("ide_version", "" + Base.REVISION); |
| |
| String[] cmdArray; |
| try { |
| String cmd = prefs.get("recipe.objcopy.hex.pattern"); |
| cmdArray = StringReplacer.formatAndSplit(cmd, dict, true); |
| } catch (Exception e) { |
| throw new RunnerException(e); |
| } |
| execAsynchronously(cmdArray); |
| } |
| |
| private static String preparePaths(List<String> includePaths) { |
| String res = ""; |
| for (String p : includePaths) |
| res += " \"-I" + p + '"'; |
| |
| // Remove first space |
| return res.substring(1); |
| } |
| |
| public PreferencesMap getBuildPreferences() { |
| return prefs; |
| } |
| } |