From 66974e7daa8754368cbe3836054ae5607ed7dfff Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Sun, 8 Dec 2013 21:12:43 +0100 Subject: [PATCH 1/5] Removed unused variables --- app/src/processing/app/debug/Compiler.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/processing/app/debug/Compiler.java b/app/src/processing/app/debug/Compiler.java index 5bdb7d2e989..80efff9818a 100644 --- a/app/src/processing/app/debug/Compiler.java +++ b/app/src/processing/app/debug/Compiler.java @@ -47,10 +47,6 @@ import processing.core.PApplet; public class Compiler implements MessageConsumer { - static final String BUGS_URL = - _("http://github.com/arduino/Arduino/issues"); - static final String SUPER_BADNESS = - I18n.format(_("Compiler error, please submit this code to {0}"), BUGS_URL); private Sketch sketch; From 60c24eff31f5cc6454ae694f079eca4bc883c582 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 9 Dec 2013 00:10:36 +0100 Subject: [PATCH 2/5] FileUtils: added function to recursively find files with given extension --- app/src/processing/app/helpers/FileUtils.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app/src/processing/app/helpers/FileUtils.java b/app/src/processing/app/helpers/FileUtils.java index 592d2dc74e6..0861ddc151f 100644 --- a/app/src/processing/app/helpers/FileUtils.java +++ b/app/src/processing/app/helpers/FileUtils.java @@ -1,6 +1,7 @@ package processing.app.helpers; import java.io.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; @@ -188,4 +189,30 @@ public static String readFileToString(File file) throws IOException { } } } + + /** + * Recursively find all files in a folder with the specified extension + * + * @param folder + * @param extensions + * @return + */ + public static List listAllFilesWithExtension(File folder, String... extensions) { + List result = new ArrayList(); + for (File file : folder.listFiles()) { + if (file.isDirectory()) { + result.addAll(listAllFilesWithExtension(file, extensions)); + continue; + } + + for (String ext : extensions) { + if (file.getName().endsWith(ext)) { + result.add(file); + break; + } + } + } + return result; + } + } From 0502b948ff7de0f0b4a8fc4a76f78a04ddb9e77c Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 9 Dec 2013 01:08:45 +0100 Subject: [PATCH 3/5] Include library paths used by libraries in the compiler search path. See #1250 See #236 --- app/src/processing/app/Base.java | 39 ++--- app/src/processing/app/Sketch.java | 26 ++- .../app/packages/HeuristicResolver.java | 150 ++++++++++++++++++ app/src/processing/app/packages/Library.java | 5 + .../app/packages/LibraryResolver.java | 43 +++++ 5 files changed, 229 insertions(+), 34 deletions(-) create mode 100644 app/src/processing/app/packages/HeuristicResolver.java create mode 100644 app/src/processing/app/packages/LibraryResolver.java diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 5f351f76477..482ee5c2be5 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -44,10 +44,11 @@ import processing.app.helpers.FileUtils; import processing.app.helpers.PreferencesMap; import processing.app.helpers.filefilters.OnlyDirs; -import processing.app.helpers.filefilters.OnlyFilesWithExtension; import processing.app.javax.swing.filechooser.FileNameExtensionFilter; +import processing.app.packages.HeuristicResolver; import processing.app.packages.Library; import processing.app.packages.LibraryList; +import processing.app.packages.LibraryResolver; import processing.app.tools.MenuScroller; import processing.app.tools.ZipDeflater; import processing.core.*; @@ -105,7 +106,7 @@ public class Base { static private LibraryList libraries; // maps #included files to their library folder - static Map importToLibraryTable; + static private LibraryResolver libraryResolver; // classpath for all known libraries for p5 // (both those in the p5/libs folder and those with lib subfolders @@ -1326,20 +1327,9 @@ public void onBoardOrPortChange() { String currentArch = Base.getTargetPlatform().getId(); libraries = libraries.filterByArchitecture(currentArch); - // Populate importToLibraryTable - importToLibraryTable = new HashMap(); - for (Library lib : libraries) { - try { - String headers[] = headerListFromIncludePath(lib.getSrcFolder()); - for (String header : headers) { - importToLibraryTable.put(header, lib); - } - } catch (IOException e) { - showWarning(_("Error"), I18n - .format("Unable to list header files in {0}", lib.getSrcFolder()), e); - } - } - + // Create library resolver + libraryResolver = new HeuristicResolver(libraries, currentArch); + // Update editors status bar for (Editor editor : editors) editor.onBoardOrPortChange(); @@ -1736,19 +1726,6 @@ public void actionPerformed(ActionEvent event) { } } - /** - * Given a folder, return a list of the header files in that folder (but not - * the header files in its sub-folders, as those should be included from - * within the header files at the top-level). - */ - static public String[] headerListFromIncludePath(File path) throws IOException { - String[] list = path.list(new OnlyFilesWithExtension(".h")); - if (list == null) { - throw new IOException(); - } - return list; - } - protected void loadHardware(File folder) { if (!folder.isDirectory()) return; @@ -2982,4 +2959,8 @@ public void handleAddLibrary() { public static DiscoveryManager getDiscoveryManager() { return discoveryManager; } + + public static LibraryResolver getLibraryResolver() { + return libraryResolver; + } } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index c8a2967ec0f..08b938bb686 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -32,16 +32,16 @@ import processing.app.forms.PasswordAuthorizationDialog; import processing.app.helpers.PreferencesMap; import processing.app.helpers.FileUtils; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; import processing.app.packages.Library; import processing.app.packages.LibraryList; +import processing.app.packages.LibraryResolver; import processing.app.preproc.*; import processing.core.*; import static processing.app.I18n._; -import java.awt.*; import java.io.*; import java.util.*; -import java.util.List; import javax.swing.*; @@ -1116,7 +1116,7 @@ public void importLibrary(File jarPath) throws IOException { // make sure the user didn't hide the sketch folder ensureExistence(); - String list[] = Base.headerListFromIncludePath(jarPath); + String list[] = jarPath.list(new OnlyFilesWithExtension(".h")); // import statements into the main sketch file (code[0]) // if the current code is a .java file, insert into current @@ -1389,13 +1389,29 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru // grab the imports from the code just preproc'd importedLibraries = new LibraryList(); + LibraryResolver resolver = Base.getLibraryResolver(); for (String item : preprocessor.getExtraImports()) { - Library lib = Base.importToLibraryTable.get(item); + Library lib = resolver.importToLibrary(item); if (lib != null && !importedLibraries.contains(lib)) { importedLibraries.add(lib); } } - + + // extend the import list with the library dependency tree + while (true) { + LibraryList dependencies = new LibraryList(); + for (Library library : importedLibraries) { + for (Library dependency : library.getResolvedDependencies()) { + if (importedLibraries.contains(dependency)) + continue; + dependencies.addOrReplace(dependency); + } + } + if (dependencies.size() == 0) + break; + importedLibraries.addAll(dependencies); + } + // 3. then loop over the code[] and save each .java file for (SketchCode sc : code) { diff --git a/app/src/processing/app/packages/HeuristicResolver.java b/app/src/processing/app/packages/HeuristicResolver.java new file mode 100644 index 00000000000..98a7430d72d --- /dev/null +++ b/app/src/processing/app/packages/HeuristicResolver.java @@ -0,0 +1,150 @@ +/* + * This file is part of Arduino. + * + * Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2013 Arduino LLC (http://www.arduino.cc/) + */ + +package processing.app.packages; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import processing.app.helpers.FileUtils; +import processing.app.helpers.filefilters.OnlyFilesWithExtension; +import processing.app.preproc.PdePreprocessor; + +/** + * This resolver uses an heuristic approach to resolve dependencies between + * libraries without looking into libraries metadata. + * + * All libraries headers are inspected to search for #include lines, afterward + * import dependencies are searched in the same way we do for includes in + * sketches, i.e. looking for a library containing the requested headers. + */ +public class HeuristicResolver implements LibraryResolver { + + private LibraryList libraries; + private Map importToLibrary; + + public HeuristicResolver(LibraryList _libraries, String arch) { + libraries = _libraries; + importToLibrary = new HashMap(); + + // Populate importToLibrary table + for (Library library : libraries) { + File srcFolder = library.getSrcFolder(); + for (String header : srcFolder.list(new OnlyFilesWithExtension(".h"))) { + importToLibrary.put(header, library); + } + } + + // Resolve all libraries dependencies + for (Library library : libraries) + library.resolvedDependencies = resolve(library, arch); + } + + /** + * Resolve dependencies for a library + * + * @param library + * @param arch + * @return A LibraryList containing the dependencies + */ + private LibraryList resolve(Library library, String arch) { + List headers = new ArrayList(); + for (File folder : library.getSrcFolders(arch)) { + List files = FileUtils.listAllFilesWithExtension(folder, ".h", + ".c", ".cpp"); + headers.addAll(files); + } + + LibraryList result = new LibraryList(); + for (File header : headers) + result.addOrReplaceAll(resolveHeader(header, headers, library)); + return result; + } + + /** + * Inspect headerFile and search for dependencies + * + * @param headerFile + * @param exclusionList + * @param library + */ + private LibraryList resolveHeader(File headerFile, List exclusionList, + Library library) { + LibraryList res = new LibraryList(); + + // Extract #includes from header file + List imports; + try { + PdePreprocessor preprocessor = new PdePreprocessor(); + String header = FileUtils.readFileToString(headerFile); + preprocessor.writePrefix(header); + imports = preprocessor.getExtraImports(); + } catch (IOException e) { + e.printStackTrace(); + return res; + } + + // For every #include found... + for (String libImport : imports) { + + // ...check if there is a matching library... + Library depLib = importToLibrary.get(libImport); + if (depLib == null || depLib == library) + continue; + + // ...and check if the include is not in the exclusion list + boolean exclude = false; + for (File excluded : exclusionList) { + if (excluded.getName().equals(libImport)) + exclude = true; + } + if (exclude) + continue; + + // add the dependency + res.addOrReplace(depLib); + + System.out.println("Found dependency for " + library.getName()); + System.out.println(" " + headerFile + " uses " + libImport + " -> " + + depLib.getName()); + } + + return res; + } + + @Override + public Library importToLibrary(String h) { + return importToLibrary.get(h); + } + +} diff --git a/app/src/processing/app/packages/Library.java b/app/src/processing/app/packages/Library.java index a6322ab449f..41de1e8502c 100644 --- a/app/src/processing/app/packages/Library.java +++ b/app/src/processing/app/packages/Library.java @@ -26,6 +26,7 @@ public class Library { private File folder, srcFolder, archFolder; private List architectures; private boolean pre15Lib; + protected LibraryList resolvedDependencies; private static final List MANDATORY_PROPERTIES = Arrays .asList(new String[] { "architectures", "author", "core-dependencies", @@ -189,6 +190,10 @@ public List getDependencies() { return dependencies; } + public LibraryList getResolvedDependencies() { + return resolvedDependencies; + } + public String getEmail() { return email; } diff --git a/app/src/processing/app/packages/LibraryResolver.java b/app/src/processing/app/packages/LibraryResolver.java new file mode 100644 index 00000000000..fe01caf2393 --- /dev/null +++ b/app/src/processing/app/packages/LibraryResolver.java @@ -0,0 +1,43 @@ +/* + * This file is part of Arduino. + * + * Arduino 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, you may use this file as part of a free software + * library without restriction. Specifically, if other files instantiate + * templates or use macros or inline functions from this file, or you compile + * this file and link it with other files to produce an executable, this + * file does not by itself cause the resulting executable to be covered by + * the GNU General Public License. This exception does not however + * invalidate any other reasons why the executable file might be covered by + * the GNU General Public License. + * + * Copyright 2013 Arduino LLC (http://www.arduino.cc/) + */ + +package processing.app.packages; + +public interface LibraryResolver { + + /** + * Returns the Library referenced by the include file name + * + * @param header + * The include file name, for example "SPI.h". + * @return The referenced library + */ + public abstract Library importToLibrary(String header); + +} From 6878839c86dac7cca109ef1f395b4a2c23afc79f Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 9 Dec 2013 18:46:30 +0100 Subject: [PATCH 4/5] Better names for HeuristicResolver class. --- .../processing/app/packages/HeuristicResolver.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/packages/HeuristicResolver.java b/app/src/processing/app/packages/HeuristicResolver.java index 98a7430d72d..0a9c31b588b 100644 --- a/app/src/processing/app/packages/HeuristicResolver.java +++ b/app/src/processing/app/packages/HeuristicResolver.java @@ -67,7 +67,7 @@ public HeuristicResolver(LibraryList _libraries, String arch) { // Resolve all libraries dependencies for (Library library : libraries) - library.resolvedDependencies = resolve(library, arch); + library.resolvedDependencies = findLibraryDependencies(library, arch); } /** @@ -77,7 +77,7 @@ public HeuristicResolver(LibraryList _libraries, String arch) { * @param arch * @return A LibraryList containing the dependencies */ - private LibraryList resolve(Library library, String arch) { + private LibraryList findLibraryDependencies(Library library, String arch) { List headers = new ArrayList(); for (File folder : library.getSrcFolders(arch)) { List files = FileUtils.listAllFilesWithExtension(folder, ".h", @@ -87,7 +87,7 @@ private LibraryList resolve(Library library, String arch) { LibraryList result = new LibraryList(); for (File header : headers) - result.addOrReplaceAll(resolveHeader(header, headers, library)); + result.addOrReplaceAll(findHeaderDependencies(header, headers, library)); return result; } @@ -98,8 +98,9 @@ private LibraryList resolve(Library library, String arch) { * @param exclusionList * @param library */ - private LibraryList resolveHeader(File headerFile, List exclusionList, - Library library) { + private LibraryList findHeaderDependencies(File headerFile, + List exclusionList, + Library library) { LibraryList res = new LibraryList(); // Extract #includes from header file From b198d1e29f976126561c513afc8d3c9c2b59cbbd Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 9 Dec 2013 18:58:06 +0100 Subject: [PATCH 5/5] Disable recursion check on pre-1.5 libraries. https://github.com/cmaglie/Arduino/commit/0502b948ff7de0f0b4a8fc4a76f78a04ddb9e77c#commitcomment-4806719 See #1726 --- app/src/processing/app/helpers/FileUtils.java | 12 +++++++++--- .../processing/app/packages/HeuristicResolver.java | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/processing/app/helpers/FileUtils.java b/app/src/processing/app/helpers/FileUtils.java index 0861ddc151f..4cb0e1fec19 100644 --- a/app/src/processing/app/helpers/FileUtils.java +++ b/app/src/processing/app/helpers/FileUtils.java @@ -194,14 +194,20 @@ public static String readFileToString(File file) throws IOException { * Recursively find all files in a folder with the specified extension * * @param folder + * Folder to look into + * @param recursive + * true will recursively find all files in sub-folders * @param extensions + * A list of file extensions to search * @return */ - public static List listAllFilesWithExtension(File folder, String... extensions) { + public static List listAllFilesWithExtension(File folder, + boolean recursive, + String... extensions) { List result = new ArrayList(); for (File file : folder.listFiles()) { - if (file.isDirectory()) { - result.addAll(listAllFilesWithExtension(file, extensions)); + if (recursive && file.isDirectory()) { + result.addAll(listAllFilesWithExtension(file, true, extensions)); continue; } diff --git a/app/src/processing/app/packages/HeuristicResolver.java b/app/src/processing/app/packages/HeuristicResolver.java index 0a9c31b588b..be88bcc670c 100644 --- a/app/src/processing/app/packages/HeuristicResolver.java +++ b/app/src/processing/app/packages/HeuristicResolver.java @@ -79,9 +79,10 @@ public HeuristicResolver(LibraryList _libraries, String arch) { */ private LibraryList findLibraryDependencies(Library library, String arch) { List headers = new ArrayList(); + boolean recursive = !library.isPre15Lib(); for (File folder : library.getSrcFolders(arch)) { - List files = FileUtils.listAllFilesWithExtension(folder, ".h", - ".c", ".cpp"); + List files = FileUtils + .listAllFilesWithExtension(folder, recursive, ".h", ".c", ".cpp"); headers.addAll(files); }