Skip to content

Private libraries not working properly #1723 #1724

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

Merged
merged 7 commits into from
Jun 9, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import io.sloeber.core.common.InstancePreferences;
import io.sloeber.core.core.DefaultInstallHandler;
import io.sloeber.core.internal.ArduinoHardwareLibrary;
import io.sloeber.core.internal.ArduinoPrivateLibraryVersion;
import io.sloeber.core.internal.ArduinoPrivateHardwareLibraryVersion;
import io.sloeber.core.internal.Example;
import io.sloeber.core.tools.FileModifiers;
import io.sloeber.core.tools.PackageManager;
Expand Down Expand Up @@ -87,6 +87,10 @@ public static String getPrivateLibraryPathsString() {
return InstancePreferences.getPrivateLibraryPathsString();
}

public static String[] getPrivateLibraryPaths() {
return InstancePreferences.getPrivateLibraryPaths();
}

public static void setPrivateLibraryPaths(String[] libraryPaths) {
InstancePreferences.setPrivateLibraryPaths(libraryPaths);

Expand Down Expand Up @@ -335,43 +339,59 @@ public static IStatus updateLibraries(Set<IArduinoLibraryVersion> toUnInstallLib
return status;
}

/**
* A convenience (and downward compatibility method of
* getLibrariesAll(BoardDescription boardDescriptor, true) {
*
* @param confDesc can be null
* @return A map of FQN IArduinoLibraryVersion
*/
public static TreeMap<String, IArduinoLibraryVersion> getLibrariesAll(BoardDescription boardDescriptor) {
return getLibrariesAll( boardDescriptor, true);
}

/**
* Given a sloeber configuration provide all the libraries that can be used by
* this sketch This boils down to all libraries maintained by the Library
* manager plus all the libraries provided by the core plus all the libraries
* provided by the personal libraries
*
* @param confDesc can be null
* @return
* @return if keyIsFQN is true: A map of FQN IArduinoLibraryVersion
* if keyIsFQN is false: A map of location IArduinoLibraryVersion
*/
public static TreeMap<String, IArduinoLibraryVersion> getLibrariesAll(BoardDescription boardDescriptor) {
public static TreeMap<String, IArduinoLibraryVersion> getLibrariesAll(BoardDescription boardDescriptor, boolean keyIsFQN) {
TreeMap<String, IArduinoLibraryVersion> libraries = new TreeMap<>();
libraries.putAll(getLibrariesdManaged());
libraries.putAll(getLibrariesPrivate());
libraries.putAll(getLibrariesdManaged(keyIsFQN));
libraries.putAll(getLibrariesPrivate(keyIsFQN));
if (boardDescriptor != null) {
libraries.putAll(getLibrariesHarware(boardDescriptor));
libraries.putAll(getLibrariesHarware(boardDescriptor,keyIsFQN));
}
return libraries;
}

private static Map<String, IArduinoLibraryVersion> getLibrariesdManaged() {
private static Map<String, IArduinoLibraryVersion> getLibrariesdManaged(boolean keyIsFQN) {
Map<String, IArduinoLibraryVersion> ret = new HashMap<>();
for (IArduinoLibraryIndex libindex : libraryIndices) {
for (IArduinoLibrary curLib : libindex.getLibraries()) {
IArduinoLibraryVersion instVersion = curLib.getInstalledVersion();
if (instVersion != null) {
ret.put(instVersion.getFQN().toPortableString(), instVersion);
if (keyIsFQN) {
ret.put(instVersion.getFQN().toPortableString(), instVersion);
} else {
ret.put(instVersion.getInstallPath().toPortableString(), instVersion);
}
}
}
}
return ret;
}

private static Map<String, IArduinoLibraryVersion> getLibrariesPrivate() {
private static Map<String, IArduinoLibraryVersion> getLibrariesPrivate(boolean keyIsFQN) {
Map<String, IArduinoLibraryVersion> ret = new HashMap<>();
String privateLibPaths[] = InstancePreferences.getPrivateLibraryPaths();
for (String curLibPath : privateLibPaths) {
ret.putAll(getLibrariesFromFolder(new Path(curLibPath), 2, false,true));
ret.putAll(getLibrariesFromFolder(new Path(curLibPath), 2, false,true,keyIsFQN));
}
return ret;

Expand All @@ -381,12 +401,13 @@ private static Map<String, IArduinoLibraryVersion> getLibrariesPrivate() {
* for a given folder return all subfolders
*
* @param ipath the folder you want the subfolders off
* @param keyIsFQN
* @return The subfolders of the ipath folder. May contain empty values. This
* method returns a key value pair of key equals foldername and value
* equals full path.
*/
private static Map<String, IArduinoLibraryVersion> getLibrariesFromFolder(IPath ipath, int depth,
boolean isHardwareLib,boolean isPrivate) {
boolean isHardwareLib,boolean isPrivate, boolean keyIsFQN) {
if (ConfigurationPreferences.getInstallationPathLibraries().isPrefixOf(ipath)) {
System.err.println("The method findAllPrivateLibs should not be called on Library manager installed libs"); //$NON-NLS-1$
}
Expand All @@ -405,13 +426,9 @@ private static Map<String, IArduinoLibraryVersion> getLibrariesFromFolder(IPath
}
String fileExt = (new Path(curChild)).getFileExtension();
if (LIBRARY_INDICATION_FILES.contains(curChild) || CODE_EXTENSIONS.contains(fileExt)) {
if (isHardwareLib) {
IArduinoLibraryVersion retVersion = new ArduinoHardwareLibrary(ipath);
ret.put(retVersion.getFQN().toPortableString(), retVersion);
} else {
IArduinoLibraryVersion retVersion = new ArduinoPrivateLibraryVersion(ipath);
ret.put(retVersion.getFQN().toPortableString(), retVersion);
}
IArduinoLibraryVersion retVersion = isHardwareLib?new ArduinoHardwareLibrary(ipath):new ArduinoPrivateHardwareLibraryVersion(ipath);
String key=keyIsFQN?retVersion.getFQN().toPortableString():retVersion.getInstallPath().toPortableString();
ret.put(key, retVersion);

return ret;
}
Expand All @@ -425,7 +442,7 @@ private static Map<String, IArduinoLibraryVersion> getLibrariesFromFolder(IPath
IPath LibPath = ipath.append(curFolder);
File LibPathFile = LibPath.toFile();
if (LibPathFile.isDirectory() && !LibPathFile.isHidden()) {
ret.putAll(getLibrariesFromFolder(LibPath, depth - 1, isHardwareLib,isPrivate));
ret.putAll(getLibrariesFromFolder(LibPath, depth - 1, isHardwareLib,isPrivate,keyIsFQN));
}
}
return ret;
Expand All @@ -435,21 +452,22 @@ private static Map<String, IArduinoLibraryVersion> getLibrariesFromFolder(IPath
* Searches all the hardware dependent libraries of a project. If this is a
* board referencing a core then the libraries of the referenced core are added
* as well
* @param keyIsFQN
*
* @param project the project to find all hardware libraries for
* @return all the library folder names. May contain empty values.
*/
public static Map<String, IArduinoLibraryVersion> getLibrariesHarware(BoardDescription boardDescriptor) {
public static Map<String, IArduinoLibraryVersion> getLibrariesHarware(BoardDescription boardDescriptor, boolean keyIsFQN) {
Map<String, IArduinoLibraryVersion> ret = new HashMap<>();
// first add the referenced
IPath libPath = boardDescriptor.getReferencedCoreLibraryPath();
if (libPath != null) {
ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate()));
ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate(),keyIsFQN));
}
// then add the referencing
libPath = boardDescriptor.getReferencingLibraryPath();
if (libPath != null) {
ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate()));
ret.putAll(getLibrariesFromFolder(libPath, 1, true,boardDescriptor.isPrivate(),keyIsFQN));
}
return ret;
}
Expand All @@ -458,17 +476,39 @@ public static IArduinoLibraryVersion getLibraryVersionFromLocation(IFolder libFo
if (boardDescriptor != null) {
IPath libPath=boardDescriptor.getReferencedCoreLibraryPath();
if(libPath!=null && libPath.isPrefixOf(libFolder.getLocation())) {
String FQNLibName=ArduinoHardwareLibrary.calculateFQN(libFolder.getName()).toString();
return getLibrariesHarware(boardDescriptor).get(FQNLibName);
return getLibrariesHarware(boardDescriptor,false).get(libFolder.getLocation().toPortableString());
}
}

if(ConfigurationPreferences.getInstallationPathLibraries().isPrefixOf(libFolder.getLocation())) {
String FQNLibName= ArduinoLibraryVersion.calculateFQN(libFolder.getName()).toString();
return getLibrariesdManaged().get(FQNLibName);
return getLibrariesdManaged(false).get(libFolder.getLocation().toPortableString());
}

return getLibrariesPrivate().get(libFolder.getName());
return getLibrariesPrivate(false).get(libFolder.getLocation().toPortableString());
}

public static IArduinoLibraryVersion getLibraryVersionFromFQN(String FQNLibName, BoardDescription boardDescriptor) {
String[] fqnParts = FQNLibName.split(SLACH);
if (fqnParts.length < 3) {
return null;
}
if (!SLOEBER_LIBRARY_FQN.equals(fqnParts[0])) {
// this is not a library
return null;
}
if (MANAGED.equals(fqnParts[1])) {
if (BOARD.equals(fqnParts[2])) {
if (boardDescriptor == null) {
return null;
}
return getLibrariesHarware(boardDescriptor,true).get(FQNLibName);
}
return getLibrariesdManaged(true).get(FQNLibName);
}
if (PRIVATE.equals(fqnParts[1])) {
return getLibrariesPrivate(true).get(FQNLibName);
}
return null;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions io.sloeber.core/src/io/sloeber/core/api/SloeberProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
import io.sloeber.core.Messages;
import io.sloeber.core.api.CompileDescription.SizeCommands;
import io.sloeber.core.internal.ArduinoHardwareLibrary;
import io.sloeber.core.internal.ArduinoPrivateLibraryVersion;
import io.sloeber.core.internal.ArduinoPrivateHardwareLibraryVersion;
import io.sloeber.core.internal.SloeberConfiguration;
import io.sloeber.core.listeners.IndexerController;
import io.sloeber.core.natures.SloeberNature;
Expand Down Expand Up @@ -241,7 +241,7 @@ public void run(IProgressMonitor internalMonitor) throws CoreException {
continue;
}

IPath privateLibFQN = ArduinoPrivateLibraryVersion.calculateFQN(curLibName);
IPath privateLibFQN = ArduinoPrivateHardwareLibraryVersion.calculateFQN(curLibName);
foundLib = availableLibs.get(privateLibFQN.toString());
if (foundLib != null) {
toInstallLibs.add(foundLib);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@
import io.sloeber.core.api.VersionNumber;
import io.sloeber.core.common.InstancePreferences;

public class ArduinoPrivateLibraryVersion implements IArduinoLibraryVersion {
public class ArduinoPrivateHardwareLibraryVersion implements IArduinoLibraryVersion {
private IPath myInstallPath;
private String myName;
private IPath myFQN;

public ArduinoPrivateLibraryVersion(IPath installPath) {
public ArduinoPrivateHardwareLibraryVersion(IPath installPath) {
myInstallPath = installPath;
myName = myInstallPath.lastSegment();
myFQN= calculateFQN(getName());
}

public ArduinoPrivateLibraryVersion(String curSaveString) {
public ArduinoPrivateHardwareLibraryVersion(String curSaveString) {
String[] parts=curSaveString.split(SEMI_COLON);
myName=parts[parts.length-1];
myFQN= calculateFQN(getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ private void upDateHardwareLibraries() {
}
}
if (!hardwareLibsFQN.isEmpty()) {
Map<String, IArduinoLibraryVersion> boardLibs = LibraryManager.getLibrariesHarware(boardDesc);
Map<String, IArduinoLibraryVersion> boardLibs = LibraryManager.getLibrariesHarware(boardDesc,true);
for (IPath curReplaceLibFQN : hardwareLibsFQN) {
IArduinoLibraryVersion newLib = boardLibs.get(curReplaceLibFQN.toPortableString());
if (newLib != null) {
Expand Down
106 changes: 105 additions & 1 deletion io.sloeber.tests/src/io/sloeber/core/BuildTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@




import static io.sloeber.core.api.Const.*;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -15,6 +15,8 @@
import java.util.TreeMap;
import java.util.stream.Stream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;

import org.apache.commons.io.FileUtils;

Expand All @@ -25,8 +27,10 @@
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
Expand Down Expand Up @@ -801,4 +805,104 @@ public void NightlyBoardPatron(String name, MCUBoard boardID, Example example, C

}


/**
* Use private lib from the workspace.
* Close project
* open project
* Is the lib still there (as does project still build)
*
* @throws Exception
*/
@Test
public void issue1723() throws Exception {
final String projectName = "private_lib";
final String privateLibFolderName = "an_private_lib";
final String privateLibName = "a_private_lib";
final String libHeaderContent=("int aFunction();")+System.lineSeparator();
String libCodeContent=("#include \""+privateLibName+".h\"")+System.lineSeparator();
libCodeContent=libCodeContent+("int aFunction(){")+System.lineSeparator();
libCodeContent=libCodeContent+("}")+System.lineSeparator();
String libRefContent=("#include \""+privateLibName+".h\"")+System.lineSeparator();
libRefContent=libRefContent+("int aRefFunction(){")+System.lineSeparator();
libRefContent=libRefContent+("aFunction();")+System.lineSeparator();
libRefContent=libRefContent+("}")+System.lineSeparator();


//create a basic arduino project
BoardDescription unoBoardid = Arduino.uno().getBoardDescriptor();
IProject theTestProject = null;

IPath templateFolder = Shared.getTemplateFolder("CreateAndCompileTest");
CodeDescription codeDescriptor = CodeDescription.createCustomTemplate(templateFolder);
theTestProject = SloeberProject.createArduinoProject(projectName, null, unoBoardid, codeDescriptor,
new CompileDescription(), new NullProgressMonitor());
Shared.waitForIndexer(theTestProject);

//create a private library project
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = workspace.getRoot();
IProject theLibProject= root.getProject("PrivateLibs");
theLibProject.create(new NullProgressMonitor());
theLibProject.open(new NullProgressMonitor());
IFolder libFolder = theLibProject.getFolder(privateLibFolderName);
libFolder.create(true, true, new NullProgressMonitor());
IFile libHeaderFile=libFolder.getFile(privateLibName+".h");
IFile libSourceFile=libFolder.getFile(privateLibName+".cpp");

Files.write(libHeaderFile.getLocation().toPath(), libHeaderContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE);
Files.write(libSourceFile.getLocation().toPath(), libCodeContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE);


//build project (should work)
theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
assertNull(Shared.hasBuildErrors(theTestProject),"Created Project does not build.");


//Add code to project that uses private lib
IFolder srcFolder = theTestProject.getFolder("src");
IFile referingFile=srcFolder.getFile("privateLibUser.cpp");
Files.write(referingFile.getLocation().toPath(), libRefContent.getBytes(), StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.CREATE);

//build project (should fail)
theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
assertNotNull(Shared.hasBuildErrors(theTestProject),"Lib should be missing; build should fail.");


//add private libs project to the sloeber preferences private libs
List<String> privateLibList= new LinkedList<>();
privateLibList.add(theLibProject.getLocation().toOSString());
privateLibList.addAll( Arrays.asList( LibraryManager.getPrivateLibraryPaths()));
LibraryManager.setPrivateLibraryPaths(privateLibList.toArray(new String[privateLibList.size()]));



//add the private lib to the project
IArduinoLibraryVersion privateArduinoLib=LibraryManager.getLibraryVersionFromFQN(SLOEBER_LIBRARY_FQN+SLACH+PRIVATE+SLACH+libFolder.getName(), null);
Collection<IArduinoLibraryVersion> myPrivateLibs =new LinkedList<>();
myPrivateLibs.add(privateArduinoLib);

ISloeberConfiguration sloeberConf=ISloeberConfiguration.getActiveConfig(theTestProject, true);
sloeberConf.addLibraries(myPrivateLibs);

//build project (should work)
theTestProject.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor());
assertNull(Shared.hasBuildErrors(theTestProject),"lib added build should succeed");

//open and close the project to clear the cache
theTestProject.close(null);
// just wait a while
Thread.sleep(1000);

theTestProject.open(new NullProgressMonitor());

//There should be 1 lib in the project
sloeberConf=ISloeberConfiguration.getActiveConfig(theTestProject, true);
Map<IPath, IArduinoLibraryVersion> usedLibs=sloeberConf.getUsedLibraries();
assertEquals(1,usedLibs.size(),"Private Lib not found");

}
}