Skip to content
Snippets Groups Projects
Commit e29627ba authored by Georg Graßnick's avatar Georg Graßnick :thinking:
Browse files

Load native libraries from resources on runtime

parent 9b42953a
No related branches found
No related tags found
1 merge request!35Feat/libluis bin
......@@ -22,3 +22,8 @@ src/main/resources/mapping/liblouis
# Exported SVG files
*.svg
# Native libraries
*.so
*.dynlib
*.dll
......@@ -68,6 +68,23 @@ clean {
delete "$rootDir/src/main/resources/mapping/liblouis"
}
// Copy native liblouis libraries for major platforms to the resource folder
task copyLibLouisBinary(type: Copy) {
from "$projectDir/third_party/liblouis_bin/bin/"
into "$rootDir/src/main/resources/native/liblouis"
}
processResources.dependsOn copyLibLouisBinary
// Abort if files are missing
gradle.taskGraph.afterTask { copyLibLouisBinary ->
if(copyLibLouisBinary.state.noSource){
throw new GradleException("Could not find liblouis native libraries in \"$projectDir/third_party/liblouis_bin/bin/\". Please make sure you updated all git submodules using \"git submodule update --init --recursive\" ")
}
}
// Delete libraries on "clean" task
clean {
delete "$rootDir/src/main/resources/native/liblouis"
}
// Define the main class for the application
mainClassName = 'de.tudresden.inf.mci.brailleplot.App'
......
......@@ -151,8 +151,6 @@ public final class App {
try {
// Logging example
mLogger.info("Application started");
// Needed for Windows machines
System.setProperty("jna.library.path", System.getProperty("user.dir") + "/third_party");
// Parse command line parameters
CommandLineParser cliParser = new CommandLineParser();
SettingsWriter settings = cliParser.parse(args);
......
......@@ -7,6 +7,8 @@ import de.tudresden.inf.mci.brailleplot.layout.InsufficientRenderingAreaExceptio
import de.tudresden.inf.mci.brailleplot.layout.RasterCanvas;
import de.tudresden.inf.mci.brailleplot.layout.Rectangle;
import de.tudresden.inf.mci.brailleplot.printerbackend.NotSupportedFileExtensionException;
import de.tudresden.inf.mci.brailleplot.util.NativeLibraryHelper;
import de.tudresden.inf.mci.brailleplot.util.NoSuchNativeLibraryException;
import org.liblouis.DisplayException;
import org.liblouis.DisplayTable;
import org.liblouis.TranslationException;
......@@ -42,6 +44,13 @@ public class LiblouisBrailleTextRasterizer implements Rasterizer<BrailleText> {
* @param printer Needed to get the semantictable according to the printer config.
*/
public LiblouisBrailleTextRasterizer(final Printer printer) {
try {
NativeLibraryHelper.loadNativeLibrary("liblouis");
} catch (NoSuchNativeLibraryException e) {
// Even if the library is not distributed within the jar file, it might be installed on the system.
}
Objects.requireNonNull(printer, "The given printer for the LiblouisBrailleTextRasterizer was null!");
try {
mParser = AbstractBrailleTableParser.getParser(printer, "semantictable");
......
package de.tudresden.inf.mci.brailleplot.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
/**
* This class offers static methods for native library loading purposes.
* @author Georg Graßnick
* @version 2019.09.26
*/
public final class NativeLibraryHelper {
private static final Logger LOG = LoggerFactory.getLogger(NativeLibraryHelper.class);
private static final String LIB_PATH = calculateLibPath();
private NativeLibraryHelper() { }
/**
* Loads a library from the resources according to the current system architecture and operating system.
* @param libName The name of the library. Library prefixes ({@literal "}lib{@literal "}) are not treated separately.
* The system specific file ending is added automatically and must not be included in the parameter.
* @return A File object representing the file of the library. The JNI is automatically set up to take of the library,
* so there is most likely no need for this return value.
* @throws NoSuchNativeLibraryException If the requested library could not be found or read.
*/
public static synchronized File loadNativeLibrary(final String libName) throws NoSuchNativeLibraryException {
File libFile;
try {
String libPath = "native/" + libName + "/" + LIB_PATH + "/" + libName + dynamicLibFileEnding();
libFile = GeneralResource.getOrExportResourceFile(libPath).getAbsoluteFile();
registerNewSystemLibPath(libFile.getParent());
} catch (Exception e) {
throw new NoSuchNativeLibraryException("Could not provide native library from java resources", e);
}
LOG.debug("Found and exported native library \"" + libFile + "\" for requested library \"" + libName + "\"");
return libFile;
}
/**
* Adds a path in the file system to the search path of the JNI.
* @param path The path to add.
*/
private static synchronized void registerNewSystemLibPath(final String path) {
// TODO Check if path is already included and abort, if so
String currentLibPath = System.getProperty("jna.library.path");
String newLibPath = null;
if (currentLibPath == null) {
newLibPath = path;
} else {
newLibPath = currentLibPath + File.pathSeparator + path;
}
LOG.debug("Setting JNI library path property to \"" + newLibPath + "\"");
System.setProperty("jna.library.path", newLibPath);
}
private static String calculateLibPath() {
return getArch() + "/" + getOs();
}
private static String getArch() {
String arch = System.getProperty("os.arch");
// reference: https://stackoverflow.com/a/36926327
switch (arch) {
case "x86":
case "i386":
case "i486":
case "i586":
case "i686":
return "x86_32";
case "x86_64":
case "amd64":
return "x86_64";
default:
throw new RuntimeException("Operating System architecture \"" + arch + "\" is currently not supported");
}
}
private static String getOs() {
String name = System.getProperty("os.name");
String nameLow = name.toLowerCase();
if (nameLow.contains("linux")) {
return "linux";
} else if (nameLow.contains("mac")) {
return "osx";
} else if (nameLow.contains("win")) {
return "win32";
} else {
throw new RuntimeException("Operating System \"" + name + "\" is currently not supported");
}
}
private static String dynamicLibFileEnding() {
switch (getOs()) {
case "win32":
return ".dll";
case "linux":
return ".so";
case "osx":
return ".dynlib";
default:
throw new IllegalStateException("If this exception was thrown, something is wrong with your code");
}
}
}
package de.tudresden.inf.mci.brailleplot.util;
/**
* Indicates, some error has occurred while trying to load a native library from the java resources.
* @author Georg Graßnick
* @version 2019.09.26
*/
public class NoSuchNativeLibraryException extends RuntimeException {
public NoSuchNativeLibraryException() { }
public NoSuchNativeLibraryException(final String message) {
super(message);
}
public NoSuchNativeLibraryException(final Throwable cause) {
super(cause);
}
public NoSuchNativeLibraryException(final String message, final Throwable cause) {
super(message, cause);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment