Skip to content

Commit 0502b94

Browse files
committed
Include library paths used by libraries in the compiler search path.
See arduino#1250 See arduino#236
1 parent 60c24ef commit 0502b94

File tree

5 files changed

+229
-34
lines changed

5 files changed

+229
-34
lines changed

Diff for: app/src/processing/app/Base.java

+10-29
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@
4444
import processing.app.helpers.FileUtils;
4545
import processing.app.helpers.PreferencesMap;
4646
import processing.app.helpers.filefilters.OnlyDirs;
47-
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
4847
import processing.app.javax.swing.filechooser.FileNameExtensionFilter;
48+
import processing.app.packages.HeuristicResolver;
4949
import processing.app.packages.Library;
5050
import processing.app.packages.LibraryList;
51+
import processing.app.packages.LibraryResolver;
5152
import processing.app.tools.MenuScroller;
5253
import processing.app.tools.ZipDeflater;
5354
import processing.core.*;
@@ -105,7 +106,7 @@ public class Base {
105106
static private LibraryList libraries;
106107

107108
// maps #included files to their library folder
108-
static Map<String, Library> importToLibraryTable;
109+
static private LibraryResolver libraryResolver;
109110

110111
// classpath for all known libraries for p5
111112
// (both those in the p5/libs folder and those with lib subfolders
@@ -1326,20 +1327,9 @@ public void onBoardOrPortChange() {
13261327
String currentArch = Base.getTargetPlatform().getId();
13271328
libraries = libraries.filterByArchitecture(currentArch);
13281329

1329-
// Populate importToLibraryTable
1330-
importToLibraryTable = new HashMap<String, Library>();
1331-
for (Library lib : libraries) {
1332-
try {
1333-
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
1334-
for (String header : headers) {
1335-
importToLibraryTable.put(header, lib);
1336-
}
1337-
} catch (IOException e) {
1338-
showWarning(_("Error"), I18n
1339-
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
1340-
}
1341-
}
1342-
1330+
// Create library resolver
1331+
libraryResolver = new HeuristicResolver(libraries, currentArch);
1332+
13431333
// Update editors status bar
13441334
for (Editor editor : editors)
13451335
editor.onBoardOrPortChange();
@@ -1736,19 +1726,6 @@ public void actionPerformed(ActionEvent event) {
17361726
}
17371727
}
17381728

1739-
/**
1740-
* Given a folder, return a list of the header files in that folder (but not
1741-
* the header files in its sub-folders, as those should be included from
1742-
* within the header files at the top-level).
1743-
*/
1744-
static public String[] headerListFromIncludePath(File path) throws IOException {
1745-
String[] list = path.list(new OnlyFilesWithExtension(".h"));
1746-
if (list == null) {
1747-
throw new IOException();
1748-
}
1749-
return list;
1750-
}
1751-
17521729
protected void loadHardware(File folder) {
17531730
if (!folder.isDirectory()) return;
17541731

@@ -2982,4 +2959,8 @@ public void handleAddLibrary() {
29822959
public static DiscoveryManager getDiscoveryManager() {
29832960
return discoveryManager;
29842961
}
2962+
2963+
public static LibraryResolver getLibraryResolver() {
2964+
return libraryResolver;
2965+
}
29852966
}

Diff for: app/src/processing/app/Sketch.java

+21-5
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@
3232
import processing.app.forms.PasswordAuthorizationDialog;
3333
import processing.app.helpers.PreferencesMap;
3434
import processing.app.helpers.FileUtils;
35+
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
3536
import processing.app.packages.Library;
3637
import processing.app.packages.LibraryList;
38+
import processing.app.packages.LibraryResolver;
3739
import processing.app.preproc.*;
3840
import processing.core.*;
3941
import static processing.app.I18n._;
4042

41-
import java.awt.*;
4243
import java.io.*;
4344
import java.util.*;
44-
import java.util.List;
4545

4646
import javax.swing.*;
4747

@@ -1116,7 +1116,7 @@ public void importLibrary(File jarPath) throws IOException {
11161116
// make sure the user didn't hide the sketch folder
11171117
ensureExistence();
11181118

1119-
String list[] = Base.headerListFromIncludePath(jarPath);
1119+
String list[] = jarPath.list(new OnlyFilesWithExtension(".h"));
11201120

11211121
// import statements into the main sketch file (code[0])
11221122
// if the current code is a .java file, insert into current
@@ -1389,13 +1389,29 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru
13891389
// grab the imports from the code just preproc'd
13901390

13911391
importedLibraries = new LibraryList();
1392+
LibraryResolver resolver = Base.getLibraryResolver();
13921393
for (String item : preprocessor.getExtraImports()) {
1393-
Library lib = Base.importToLibraryTable.get(item);
1394+
Library lib = resolver.importToLibrary(item);
13941395
if (lib != null && !importedLibraries.contains(lib)) {
13951396
importedLibraries.add(lib);
13961397
}
13971398
}
1398-
1399+
1400+
// extend the import list with the library dependency tree
1401+
while (true) {
1402+
LibraryList dependencies = new LibraryList();
1403+
for (Library library : importedLibraries) {
1404+
for (Library dependency : library.getResolvedDependencies()) {
1405+
if (importedLibraries.contains(dependency))
1406+
continue;
1407+
dependencies.addOrReplace(dependency);
1408+
}
1409+
}
1410+
if (dependencies.size() == 0)
1411+
break;
1412+
importedLibraries.addAll(dependencies);
1413+
}
1414+
13991415
// 3. then loop over the code[] and save each .java file
14001416

14011417
for (SketchCode sc : code) {
+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Arduino is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*
18+
* As a special exception, you may use this file as part of a free software
19+
* library without restriction. Specifically, if other files instantiate
20+
* templates or use macros or inline functions from this file, or you compile
21+
* this file and link it with other files to produce an executable, this
22+
* file does not by itself cause the resulting executable to be covered by
23+
* the GNU General Public License. This exception does not however
24+
* invalidate any other reasons why the executable file might be covered by
25+
* the GNU General Public License.
26+
*
27+
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
28+
*/
29+
30+
package processing.app.packages;
31+
32+
import java.io.File;
33+
import java.io.IOException;
34+
import java.util.ArrayList;
35+
import java.util.HashMap;
36+
import java.util.List;
37+
import java.util.Map;
38+
39+
import processing.app.helpers.FileUtils;
40+
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
41+
import processing.app.preproc.PdePreprocessor;
42+
43+
/**
44+
* This resolver uses an heuristic approach to resolve dependencies between
45+
* libraries without looking into libraries metadata.
46+
*
47+
* All libraries headers are inspected to search for #include lines, afterward
48+
* import dependencies are searched in the same way we do for includes in
49+
* sketches, i.e. looking for a library containing the requested headers.
50+
*/
51+
public class HeuristicResolver implements LibraryResolver {
52+
53+
private LibraryList libraries;
54+
private Map<String, Library> importToLibrary;
55+
56+
public HeuristicResolver(LibraryList _libraries, String arch) {
57+
libraries = _libraries;
58+
importToLibrary = new HashMap<String, Library>();
59+
60+
// Populate importToLibrary table
61+
for (Library library : libraries) {
62+
File srcFolder = library.getSrcFolder();
63+
for (String header : srcFolder.list(new OnlyFilesWithExtension(".h"))) {
64+
importToLibrary.put(header, library);
65+
}
66+
}
67+
68+
// Resolve all libraries dependencies
69+
for (Library library : libraries)
70+
library.resolvedDependencies = resolve(library, arch);
71+
}
72+
73+
/**
74+
* Resolve dependencies for a library
75+
*
76+
* @param library
77+
* @param arch
78+
* @return A LibraryList containing the dependencies
79+
*/
80+
private LibraryList resolve(Library library, String arch) {
81+
List<File> headers = new ArrayList<File>();
82+
for (File folder : library.getSrcFolders(arch)) {
83+
List<File> files = FileUtils.listAllFilesWithExtension(folder, ".h",
84+
".c", ".cpp");
85+
headers.addAll(files);
86+
}
87+
88+
LibraryList result = new LibraryList();
89+
for (File header : headers)
90+
result.addOrReplaceAll(resolveHeader(header, headers, library));
91+
return result;
92+
}
93+
94+
/**
95+
* Inspect headerFile and search for dependencies
96+
*
97+
* @param headerFile
98+
* @param exclusionList
99+
* @param library
100+
*/
101+
private LibraryList resolveHeader(File headerFile, List<File> exclusionList,
102+
Library library) {
103+
LibraryList res = new LibraryList();
104+
105+
// Extract #includes from header file
106+
List<String> imports;
107+
try {
108+
PdePreprocessor preprocessor = new PdePreprocessor();
109+
String header = FileUtils.readFileToString(headerFile);
110+
preprocessor.writePrefix(header);
111+
imports = preprocessor.getExtraImports();
112+
} catch (IOException e) {
113+
e.printStackTrace();
114+
return res;
115+
}
116+
117+
// For every #include found...
118+
for (String libImport : imports) {
119+
120+
// ...check if there is a matching library...
121+
Library depLib = importToLibrary.get(libImport);
122+
if (depLib == null || depLib == library)
123+
continue;
124+
125+
// ...and check if the include is not in the exclusion list
126+
boolean exclude = false;
127+
for (File excluded : exclusionList) {
128+
if (excluded.getName().equals(libImport))
129+
exclude = true;
130+
}
131+
if (exclude)
132+
continue;
133+
134+
// add the dependency
135+
res.addOrReplace(depLib);
136+
137+
System.out.println("Found dependency for " + library.getName());
138+
System.out.println(" " + headerFile + " uses " + libImport + " -> " +
139+
depLib.getName());
140+
}
141+
142+
return res;
143+
}
144+
145+
@Override
146+
public Library importToLibrary(String h) {
147+
return importToLibrary.get(h);
148+
}
149+
150+
}

Diff for: app/src/processing/app/packages/Library.java

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class Library {
2626
private File folder, srcFolder, archFolder;
2727
private List<String> architectures;
2828
private boolean pre15Lib;
29+
protected LibraryList resolvedDependencies;
2930

3031
private static final List<String> MANDATORY_PROPERTIES = Arrays
3132
.asList(new String[] { "architectures", "author", "core-dependencies",
@@ -189,6 +190,10 @@ public List<String> getDependencies() {
189190
return dependencies;
190191
}
191192

193+
public LibraryList getResolvedDependencies() {
194+
return resolvedDependencies;
195+
}
196+
192197
public String getEmail() {
193198
return email;
194199
}

Diff for: app/src/processing/app/packages/LibraryResolver.java

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Arduino is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+
*
18+
* As a special exception, you may use this file as part of a free software
19+
* library without restriction. Specifically, if other files instantiate
20+
* templates or use macros or inline functions from this file, or you compile
21+
* this file and link it with other files to produce an executable, this
22+
* file does not by itself cause the resulting executable to be covered by
23+
* the GNU General Public License. This exception does not however
24+
* invalidate any other reasons why the executable file might be covered by
25+
* the GNU General Public License.
26+
*
27+
* Copyright 2013 Arduino LLC (http://www.arduino.cc/)
28+
*/
29+
30+
package processing.app.packages;
31+
32+
public interface LibraryResolver {
33+
34+
/**
35+
* Returns the Library referenced by the include file name
36+
*
37+
* @param header
38+
* The include file name, for example "SPI.h".
39+
* @return The referenced library
40+
*/
41+
public abstract Library importToLibrary(String header);
42+
43+
}

0 commit comments

Comments
 (0)