Skip to content

Commit b5367bc

Browse files
Advise of duplicate libraries after compiling
1 parent 1fcd6ff commit b5367bc

File tree

4 files changed

+126
-28
lines changed

4 files changed

+126
-28
lines changed

arduino-core/src/cc/arduino/contributions/libraries/LibrariesIndexer.java

+25-4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class LibrariesIndexer {
5252

5353
private LibrariesIndex index;
5454
private final LibraryList installedLibraries = new LibraryList();
55+
private final LibraryList installedLibrariesWithDuplicates = new LibraryList();
5556
private List<File> librariesFolders;
5657
private final File indexFile;
5758
private final File stagingFolder;
@@ -92,15 +93,16 @@ public void setLibrariesFolders(List<File> _librariesFolders) {
9293
public void rescanLibraries() {
9394
// Clear all installed flags
9495
installedLibraries.clear();
96+
installedLibrariesWithDuplicates.clear();
9597
for (ContributedLibrary lib : index.getLibraries())
9698
lib.setInstalled(false);
9799

98100
// Rescan libraries
99101
for (File folder : librariesFolders)
100-
scanInstalledLibraries(folder);
102+
scanInstalledLibraries(folder, folder.equals(sketchbookLibrariesFolder));
101103
}
102104

103-
private void scanInstalledLibraries(File folder) {
105+
private void scanInstalledLibraries(File folder, boolean isSketchbook) {
104106
File list[] = folder.listFiles(OnlyDirs.ONLY_DIRS);
105107
// if a bad folder or something like that, this might come back null
106108
if (list == null)
@@ -117,14 +119,14 @@ private void scanInstalledLibraries(File folder) {
117119
}
118120

119121
try {
120-
scanLibrary(subfolder);
122+
scanLibrary(subfolder, isSketchbook);
121123
} catch (IOException e) {
122124
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), subfolder, e.getMessage()));
123125
}
124126
}
125127
}
126128

127-
private void scanLibrary(File folder) throws IOException {
129+
private void scanLibrary(File folder, boolean isSketchbook) throws IOException {
128130
boolean readOnly = !FileUtils.isSubDirectory(sketchbookLibrariesFolder, folder);
129131

130132
// A library is considered "legacy" if it doesn't contains
@@ -135,13 +137,23 @@ private void scanLibrary(File folder) throws IOException {
135137
LegacyUserLibrary lib = LegacyUserLibrary.create(folder);
136138
lib.setReadOnly(readOnly);
137139
installedLibraries.addOrReplace(lib);
140+
if (isSketchbook) {
141+
installedLibrariesWithDuplicates.add(lib);
142+
} else {
143+
installedLibrariesWithDuplicates.addOrReplace(lib);
144+
}
138145
return;
139146
}
140147

141148
// Create a regular library
142149
UserLibrary lib = UserLibrary.create(folder);
143150
lib.setReadOnly(readOnly);
144151
installedLibraries.addOrReplace(lib);
152+
if (isSketchbook) {
153+
installedLibrariesWithDuplicates.add(lib);
154+
} else {
155+
installedLibrariesWithDuplicates.addOrReplace(lib);
156+
}
145157

146158
// Check if we can find the same library in the index
147159
// and mark it as installed
@@ -170,6 +182,15 @@ public LibraryList getInstalledLibraries() {
170182
return installedLibraries;
171183
}
172184

185+
// Same as getInstalledLibraries(), but allow duplicates between
186+
// builtin+package libraries and sketchbook installed libraries.
187+
// However, do not report duplicates among builtin and packages, to
188+
// allow any package to override builtin libraries without being
189+
// reported as duplicates.
190+
public LibraryList getInstalledLibrariesWithDuplicates() {
191+
return installedLibrariesWithDuplicates;
192+
}
193+
173194
public File getStagingFolder() {
174195
return stagingFolder;
175196
}

arduino-core/src/processing/app/BaseNoGui.java

+51-18
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class BaseNoGui {
4545
static private File toolsFolder;
4646

4747
// maps #included files to their library folder
48-
public static Map<String, UserLibrary> importToLibraryTable;
48+
public static Map<String, LibraryList> importToLibraryTable;
4949

5050
// maps library name to their library folder
5151
static private LibraryList libraries;
@@ -787,14 +787,24 @@ static private void createToolPreferences(ContributionsIndexer indexer) {
787787
}
788788

789789
static public void populateImportToLibraryTable() {
790-
// Populate importToLibraryTable
791-
importToLibraryTable = new HashMap<String, UserLibrary>();
790+
// Populate importToLibraryTable. Each header filename maps to
791+
// a list of libraries. Compiler.java will use only the first
792+
// library on each list. The others are used only to advise
793+
// user of ambiguously matched and duplicate libraries.
794+
importToLibraryTable = new HashMap<String, LibraryList>();
792795
for (UserLibrary lib : librariesIndexer.getInstalledLibraries()) {
793796
try {
794797
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
795798
for (String header : headers) {
796-
UserLibrary old = importToLibraryTable.get(header);
797-
if (old != null) {
799+
LibraryList list = importToLibraryTable.get(header);
800+
if (list == null) {
801+
// This is the first library found with this header
802+
list = new LibraryList();
803+
list.addFirst(lib);
804+
importToLibraryTable.put(header, list);
805+
} else {
806+
UserLibrary old = list.peekFirst();
807+
boolean useThisLib = true;
798808
// This is the case where 2 libraries have a .h header
799809
// with the same name. We must decide which library to
800810
// use when a sketch has #include "name.h"
@@ -812,58 +822,81 @@ static public void populateImportToLibraryTable() {
812822
String oldName = old.getInstalledFolder().getName(); // just the library folder name
813823
String libName = lib.getInstalledFolder().getName(); // just the library folder name
814824
//System.out.println("name conflict: " + name);
815-
//System.out.println(" old = " + oldName + " -> " + old.getFolder().getPath());
816-
//System.out.println(" new = " + libName + " -> " + lib.getFolder().getPath());
825+
//System.out.println(" old = " + oldName + " -> " + old.getInstalledFolder().getPath());
826+
//System.out.println(" new = " + libName + " -> " + lib.getInstalledFolder().getPath());
817827
String name_lc = name.toLowerCase();
818828
String oldName_lc = oldName.toLowerCase();
819829
String libName_lc = libName.toLowerCase();
820830
// always favor a perfect name match
821831
if (libName.equals(name)) {
822832
} else if (oldName.equals(name)) {
823-
continue;
833+
useThisLib = false;
824834
// check for "-master" appended (zip file from github)
825835
} else if (libName.equals(name+"-master")) {
826836
} else if (oldName.equals(name+"-master")) {
827-
continue;
837+
useThisLib = false;
828838
// next, favor a match with other stuff appended
829839
} else if (libName.startsWith(name)) {
830840
} else if (oldName.startsWith(name)) {
831-
continue;
841+
useThisLib = false;
832842
// otherwise, favor a match with stuff prepended
833843
} else if (libName.endsWith(name)) {
834844
} else if (oldName.endsWith(name)) {
835-
continue;
845+
useThisLib = false;
836846
// as a last resort, match if stuff prepended and appended
837847
} else if (libName.contains(name)) {
838848
} else if (oldName.contains(name)) {
839-
continue;
849+
useThisLib = false;
840850
// repeat all the above tests, with case insensitive matching
841851
} else if (libName_lc.equals(name_lc)) {
842852
} else if (oldName_lc.equals(name_lc)) {
843-
continue;
853+
useThisLib = false;
844854
} else if (libName_lc.equals(name_lc+"-master")) {
845855
} else if (oldName_lc.equals(name_lc+"-master")) {
846-
continue;
856+
useThisLib = false;
847857
} else if (libName_lc.startsWith(name_lc)) {
848858
} else if (oldName_lc.startsWith(name_lc)) {
849-
continue;
859+
useThisLib = false;
850860
} else if (libName_lc.endsWith(name_lc)) {
851861
} else if (oldName_lc.endsWith(name_lc)) {
852-
continue;
862+
useThisLib = false;
853863
} else if (libName_lc.contains(name_lc)) {
854864
} else if (oldName_lc.contains(name_lc)) {
855-
continue;
865+
useThisLib = false;
856866
} else {
857867
// none of these tests matched, so just default to "libName".
858868
}
869+
if (useThisLib) {
870+
list.addFirst(lib);
871+
} else {
872+
list.addLast(lib);
873+
}
859874
}
860-
importToLibraryTable.put(header, lib);
861875
}
862876
} catch (IOException e) {
863877
showWarning(_("Error"), I18n
864878
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
865879
}
866880
}
881+
// repeat for ALL libraries, to pick up duplicates not visible normally.
882+
// any new libraries found here are NEVER used, but they are added to the
883+
// end of already-found headers, to allow Compiler to report them if
884+
// the sketch tries to use them.
885+
for (UserLibrary lib : librariesIndexer.getInstalledLibrariesWithDuplicates()) {
886+
try {
887+
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
888+
for (String header : headers) {
889+
LibraryList list = importToLibraryTable.get(header);
890+
if (list != null) {
891+
if (!(list.hasLibrary(lib))) {
892+
list.addLast(lib);
893+
//System.out.println(" duplicate lib: " + lib.getInstalledFolder().getPath());
894+
}
895+
}
896+
}
897+
} catch (IOException e) {
898+
}
899+
}
867900
}
868901

869902
static public void initParameters(String args[]) {

arduino-core/src/processing/app/debug/Compiler.java

+43-6
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,16 @@ static public String build(SketchData data, String buildPath, File tempBuildFold
114114

115115
// compile the program. errors will happen as a RunnerException
116116
// that will bubble up to whomever called build().
117-
if (compiler.compile(verbose)) {
118-
compiler.size(compiler.getBuildPreferences());
119-
return primaryClassName;
117+
try {
118+
if (compiler.compile(verbose)) {
119+
compiler.size(compiler.getBuildPreferences());
120+
return primaryClassName;
121+
}
122+
} catch (RunnerException e) {
123+
// when the compile fails, take this opportunity to show
124+
// any helpful info possible before throwing the exception
125+
compiler.adviseDuplicateLibraries();
126+
throw e;
120127
}
121128
return null;
122129
}
@@ -428,10 +435,29 @@ public boolean compile(boolean _verbose) throws RunnerException, PreferencesMapE
428435

429436
// Hook runs at End of Compilation
430437
runActions("hooks.postbuild", prefs);
438+
adviseDuplicateLibraries();
431439

432440
return true;
433441
}
434442

443+
private void adviseDuplicateLibraries() {
444+
for (int i=0; i < importedDuplicateHeaders.size(); i++) {
445+
System.out.println(I18n.format(_("Multiple libraries were found for \"{0}\""),
446+
importedDuplicateHeaders.get(i)));
447+
boolean first = true;
448+
for (UserLibrary lib : importedDuplicateLibraries.get(i)) {
449+
if (first) {
450+
System.out.println(I18n.format(_(" Used: {0}"),
451+
lib.getInstalledFolder().getPath()));
452+
first = false;
453+
} else {
454+
System.out.println(I18n.format(_(" Not used: {0}"),
455+
lib.getInstalledFolder().getPath()));
456+
}
457+
}
458+
}
459+
}
460+
435461
private PreferencesMap createBuildPreferences(String _buildPath,
436462
String _primaryClassName)
437463
throws RunnerException {
@@ -1166,10 +1192,19 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru
11661192
// grab the imports from the code just preproc'd
11671193

11681194
importedLibraries = new LibraryList();
1195+
importedDuplicateHeaders = new ArrayList<String>();
1196+
importedDuplicateLibraries = new ArrayList<LibraryList>();
11691197
for (String item : preprocessor.getExtraImports()) {
1170-
UserLibrary lib = BaseNoGui.importToLibraryTable.get(item);
1171-
if (lib != null && !importedLibraries.contains(lib)) {
1172-
importedLibraries.add(lib);
1198+
LibraryList list = BaseNoGui.importToLibraryTable.get(item);
1199+
if (list != null) {
1200+
UserLibrary lib = list.peekFirst();
1201+
if (lib != null && !importedLibraries.contains(lib)) {
1202+
importedLibraries.add(lib);
1203+
if (list.size() > 1) {
1204+
importedDuplicateHeaders.add(item);
1205+
importedDuplicateLibraries.add(list);
1206+
}
1207+
}
11731208
}
11741209
}
11751210

@@ -1201,6 +1236,8 @@ public void preprocess(String buildPath, PdePreprocessor preprocessor) throws Ru
12011236
* List of library folders.
12021237
*/
12031238
private LibraryList importedLibraries;
1239+
private List<String> importedDuplicateHeaders;
1240+
private List<LibraryList> importedDuplicateLibraries;
12041241

12051242
/**
12061243
* Map an error from a set of processed .java files back to its location

arduino-core/src/processing/app/packages/LibraryList.java

+7
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,11 @@ public LibraryList filterLibrariesInSubfolder(File subFolder) {
8181
}
8282
return res;
8383
}
84+
85+
public boolean hasLibrary(UserLibrary lib) {
86+
for (UserLibrary l : this)
87+
if (l == lib) return true;
88+
return false;
89+
}
8490
}
91+

0 commit comments

Comments
 (0)