Skip to content

Include library paths used by libraries in the compiler search path (take 2) #1726

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 10 additions & 29 deletions app/src/processing/app/Base.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.*;
Expand Down Expand Up @@ -105,7 +106,7 @@ public class Base {
static private LibraryList libraries;

// maps #included files to their library folder
static Map<String, Library> importToLibraryTable;
static private LibraryResolver libraryResolver;

// classpath for all known libraries for p5
// (both those in the p5/libs folder and those with lib subfolders
Expand Down Expand Up @@ -1341,20 +1342,9 @@ public void onBoardOrPortChange() {
showWarning(_("Error"), _("Error loading libraries"), e);
}

// Populate importToLibraryTable
importToLibraryTable = new HashMap<String, Library>();
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);

// Update editors status bar
for (Editor editor : editors)
editor.onBoardOrPortChange();
Expand Down Expand Up @@ -1755,19 +1745,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;

Expand Down Expand Up @@ -3001,4 +2978,8 @@ public void handleAddLibrary() {
public static DiscoveryManager getDiscoveryManager() {
return discoveryManager;
}

public static LibraryResolver getLibraryResolver() {
return libraryResolver;
}
}
25 changes: 21 additions & 4 deletions app/src/processing/app/Sketch.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +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.io.*;
import java.util.*;
import java.util.List;

import javax.swing.*;

Expand Down Expand Up @@ -1115,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
Expand Down Expand Up @@ -1388,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) {
Expand Down
4 changes: 0 additions & 4 deletions app/src/processing/app/debug/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,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;

Expand Down
33 changes: 33 additions & 0 deletions app/src/processing/app/helpers/FileUtils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -188,4 +189,36 @@ 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
* <b>true</b> will recursively find all files in sub-folders
* @param extensions
* A list of file extensions to search
* @return
*/
public static List<File> listAllFilesWithExtension(File folder,
boolean recursive,
String... extensions) {
List<File> result = new ArrayList<File>();
for (File file : folder.listFiles()) {
if (recursive && file.isDirectory()) {
result.addAll(listAllFilesWithExtension(file, true, extensions));
continue;
}

for (String ext : extensions) {
if (file.getName().endsWith(ext)) {
result.add(file);
break;
}
}
}
return result;
}

}
150 changes: 150 additions & 0 deletions app/src/processing/app/packages/HeuristicResolver.java
Original file line number Diff line number Diff line change
@@ -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<String, Library> importToLibrary;

public HeuristicResolver(LibraryList _libraries) {
libraries = _libraries;
importToLibrary = new HashMap<String, Library>();

// 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 = findLibraryDependencies(library);
}

/**
* Resolve dependencies for a library
*
* @param library
* @param arch
* @return A LibraryList containing the dependencies
*/
private LibraryList findLibraryDependencies(Library library) {
List<File> headers = new ArrayList<File>();
boolean recursive = library.useRecursion();
File folder = library.getSrcFolder();
List<File> files = FileUtils.listAllFilesWithExtension(folder, recursive,
".h", ".c", ".cpp");
headers.addAll(files);
LibraryList result = new LibraryList();
for (File header : headers)
result.addOrReplaceAll(findHeaderDependencies(header, headers, library));
return result;
}

/**
* Inspect headerFile and search for dependencies
*
* @param headerFile
* @param exclusionList
* @param library
*/
private LibraryList findHeaderDependencies(File headerFile,
List<File> exclusionList,
Library library) {
LibraryList res = new LibraryList();

// Extract #includes from header file
List<String> 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);
}

}
5 changes: 5 additions & 0 deletions app/src/processing/app/packages/Library.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class Library {
private String category;
private String license;
private List<String> architectures;
protected LibraryList resolvedDependencies;
private File folder;
private File srcFolder;
private boolean useRecursion;
Expand Down Expand Up @@ -209,6 +210,10 @@ public String getAuthor() {
return author;
}

public LibraryList getResolvedDependencies() {
return resolvedDependencies;
}

public String getParagraph() {
return paragraph;
}
Expand Down
Loading