private List<Loaded<Program>> loadLibraries(ByteProvider provider, Program program,
			Project project, String projectFolderPath, LoadSpec desiredLoadSpec,
			List<Option> options, MessageLog log, Object consumer, List<String> libraryNameList,
			TaskMonitor monitor) throws CancelledException, IOException {

		List<Loaded<Program>> loadedPrograms = new ArrayList<>();
		Set<String> processed = new TreeSet<>(getLibraryNameComparator());
		Queue<UnprocessedLibrary> unprocessed = createUnprocessedQueue(libraryNameList, options);
		boolean loadLibraries = isLoadLibraries(options);
		List<LibrarySearchPath> customSearchPaths =
			getCustomLibrarySearchPaths(provider, options, log, monitor);
		List<LibrarySearchPath> searchPaths =
			getLibrarySearchPaths(program, desiredLoadSpec, options, log, monitor);
		DomainFolder linkSearchFolder =
			getLinkSearchFolder(project, program, projectFolderPath, options, log);
		String libraryDestFolderPath =
			getLibraryDestinationFolderPath(project, projectFolderPath, options);
		DomainFolder libraryDestFolder =
			getLibraryDestinationSearchFolder(project, libraryDestFolderPath, options);

		boolean success = false;
		try {
			while (!unprocessed.isEmpty()) {
				monitor.checkCancelled();
				UnprocessedLibrary unprocessedLibrary = unprocessed.remove();
				String library = unprocessedLibrary.name().trim();
				int depth = unprocessedLibrary.depth();
				if (depth == 0 || processed.contains(library)) {
					continue;
				}
				processed.add(library);
				if (findLibraryInProject(library, libraryDestFolder, searchPaths, options,
					monitor) != null) {
					log.appendMsg("Found %s in %s...".formatted(library, libraryDestFolder));
					log.appendMsg("------------------------------------------------\n");
				}
				else if (findLibraryInProject(library, linkSearchFolder, searchPaths, options,
					monitor) != null) {
					log.appendMsg("Found %s in %s...".formatted(library, linkSearchFolder));
					log.appendMsg("------------------------------------------------\n");
				}
				else if (isLoadLibraries(options) || shouldSearchAllPaths(program, options, log)) {
					Loaded<Program> loadedLibrary = loadLibraryFromSearchPaths(library, provider,
						customSearchPaths, libraryDestFolderPath, unprocessed, depth,
						desiredLoadSpec, options, log, consumer, monitor);
					if (loadedLibrary == null) {
						loadedLibrary = loadLibraryFromSearchPaths(library, provider, searchPaths,
							libraryDestFolderPath, unprocessed, depth, desiredLoadSpec, options,
							log, consumer, monitor);
					}
					if (loadedLibrary != null) {
						boolean discarding = !loadLibraries || unprocessedLibrary.discard();
						loadedLibrary.setDiscard(discarding);
						loadedPrograms.add(loadedLibrary);
						log.appendMsg(discarding ? "Library not saved to project."
								: "Saving library to: " + loadedLibrary);
					}
					log.appendMsg("------------------------------------------------\n");
				}
			}
			success = true;
			return loadedPrograms;
		}
		finally {
			if (!success) {
				release(loadedPrograms, consumer);
			}
			Stream.of(customSearchPaths, searchPaths)
					.flatMap(Collection::stream)
					.forEach(fsSearchPath -> {
						if (!fsSearchPath.fsRef().isClosed()) {
							fsSearchPath.fsRef().close();
						}
					});
			FileSystemService.getInstance().closeUnusedFileSystems();
		}
	}
Loads the given list of libraries as {@link Loaded} {@link Program}s

@param provider The {@link ByteProvider} of the program being loaded
@param program The {@link Program} being loaded
@param project The {@link Project}. Could be null if there is no project.
@param projectFolderPath The project folder path the program will get saved to. Could be null
  if the program is not getting saved to the project.
@param desiredLoadSpec The desired {@link LoadSpec}
@param options The load options
@param log The log
@param consumer A consumer object for {@link DomainObject}s generated
@param monitor A cancelable task monitor
@return A {@link List} of newly loaded programs and libraries.  Any program in the list is 
  the caller's responsibility to release.
@throws IOException if there was an IO-related problem loading
@throws CancelledException if the user cancelled the load
Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractLibrarySupportLoader.java