Change loading of native libraries. They are now included in the

classpath and extracted to a temporary directory during runtime. Looks
like I also fixed the loading problems of libusb.dylib on MacOS X by
changing the dependency path from @executable_path to @loader_path. So
no java.library.path and DYLD_LIBRARY_PATH needed anymore. Just add
usb4java as a dependency and that#s it.
This commit is contained in:
Klaus Reimer 2012-11-12 18:06:48 +01:00
parent 7affcc1864
commit e7948fc191
24 changed files with 337 additions and 177 deletions

24
pom.xml
View File

@ -113,30 +113,6 @@
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version><!--$NO-MVN-MAN-VER$-->
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
<descriptor>src/main/assembly/linux-x86.xml</descriptor>
<descriptor>src/main/assembly/linux-x86_64.xml</descriptor>
<descriptor>src/main/assembly/windows-x86.xml</descriptor>
<descriptor>src/main/assembly/windows-x86_64.xml</descriptor>
<descriptor>src/main/assembly/macosx-universal.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>package-assembly</id>
<phase>package</phase>
<goals>
<goal>attached</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

View File

@ -1,18 +0,0 @@
<assembly>
<id>linux-x86</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/assembly/linux-x86</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
<fileMode>644</fileMode>
<lineEnding>keep</lineEnding>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,18 +0,0 @@
<assembly>
<id>linux-x86_64</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/assembly/linux-x86_64</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
<fileMode>644</fileMode>
<lineEnding>keep</lineEnding>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,18 +0,0 @@
<assembly>
<id>macosx-universal</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/assembly/macosx-universal</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
<fileMode>644</fileMode>
<lineEnding>keep</lineEnding>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,24 +0,0 @@
<assembly>
<id>src</id>
<formats>
<format>zip</format>
<format>tar.bz2</format>
</formats>
<fileSets>
<fileSet>
<includes>
<include>README.txt</include>
<include>LICENSE.txt</include>
<include>pom.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>src</directory>
<excludes>
<exclude>**/log?????.txt</exclude>
<exclude>**/dump/out/*</exclude>
<exclude>**/dump/lib/*.class</exclude>
</excludes>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,18 +0,0 @@
<assembly>
<id>windows-x86</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/assembly/windows-x86</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
<fileMode>644</fileMode>
<lineEnding>keep</lineEnding>
</fileSet>
</fileSets>
</assembly>

View File

@ -1,18 +0,0 @@
<assembly>
<id>windows-x86_64</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>src/main/assembly/windows-x86_64</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
<fileMode>644</fileMode>
<lineEnding>keep</lineEnding>
</fileSet>
</fileSets>
</assembly>

View File

@ -10,7 +10,7 @@ cd $(dirname $0)/..
OS=linux
ARCH=x86
TMPDIR=$(pwd)/tmp
DISTDIR=$(pwd)/../assembly/${OS}-${ARCH}
DISTDIR=$(pwd)/../resources/${OS}-${ARCH}
# Clean up
rm -rf $TMPDIR

View File

@ -9,7 +9,7 @@ cd $(dirname $0)/..
OS=linux
ARCH=x86_64
TMPDIR=$(pwd)/tmp
DISTDIR=$(pwd)/../assembly/${OS}-${ARCH}
DISTDIR=$(pwd)/../resources/${OS}-${ARCH}
# Clean up
rm -rf $TMPDIR

View File

@ -8,7 +8,7 @@ cd $(dirname $0)/..
OS=macosx
ARCH=universal
TMPDIR=$(pwd)/tmp
DISTDIR=$(pwd)/../assembly/${OS}-${ARCH}
DISTDIR=$(pwd)/../resources/${OS}-${ARCH}
# Clean up
rm -rf $TMPDIR
@ -66,4 +66,4 @@ rm -rf $TMPDIR
# Remove paths from libraries
install_name_tool -id @executable_path/libusb.dylib $DISTDIR/libusb.dylib
install_name_tool -id @executable_path/libusb4java.dylib $DISTDIR/libusb4java.dylib
install_name_tool -change /usr/lib/libusb-0.1.4.dylib @executable_path/libusb.dylib $DISTDIR/libusb4java.dylib
install_name_tool -change /usr/lib/libusb-0.1.4.dylib @loader_path/libusb.dylib $DISTDIR/libusb4java.dylib

View File

@ -9,7 +9,7 @@ cd $(dirname $0)/..
OS=windows
ARCH=x86
TMPDIR=$(pwd)/tmp
DISTDIR=$(pwd)/../assembly/${OS}-${ARCH}
DISTDIR=$(pwd)/../resources/${OS}-${ARCH}
# Clean up
rm -rf $TMPDIR

View File

@ -9,7 +9,7 @@ cd $(dirname $0)/..
OS=windows
ARCH=x86_64
TMPDIR=$(pwd)/tmp
DISTDIR=$(pwd)/../assembly/${OS}-${ARCH}
DISTDIR=$(pwd)/../resources/${OS}-${ARCH}
# Clean up
rm -rf $TMPDIR

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
* See LICENSE.txt for licensing information.
*/
package de.ailis.usb4java.exceptions;
/**
* Exception thrown when something goes wrong while loading native libraries.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class NativesException extends RuntimeException
{
/** Serial version UID. */
private static final long serialVersionUID = 1L;
/**
* Constructor.
*
* @param message
* The error message.
*/
public NativesException(final String message)
{
super(message);
}
/**
* Constructor.
*
* @param message
* The error message.
* @param cause
* The root cause.
*/
public NativesException(final String message, final Throwable cause)
{
super(message, cause);
}
}

View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2011 Klaus Reimer <k@ailis.de>
* See LICENSE.txt for licensing information.
*/
package de.ailis.usb4java.jni;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import de.ailis.usb4java.exceptions.NativesException;
import de.ailis.usb4java.support.IOUtils;
/**
* Utility class to load native libraries from classpath.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class NativesLoader
{
/** If Windows operating system. */
private static final boolean WINDOWS = System.getProperty("os.name")
.contains("Windows");
/** If Linux operating system. */
private static final boolean LINUX = System.getProperty("os.name")
.contains("Linux");
/** If Mac operating system. */
private static final boolean MAC = System.getProperty("os.name").contains(
"Mac");
/** If 64 bit operating system. */
private static final boolean IS_64_BIT = System.getProperty("os.arch")
.equals("amd64") ||
System.getProperty("os.arch").equals("x86_64");
/** The temporary directory for native libraries. */
private static final File TMP = createTempDirectory();
/** If library is already loaded. */
private static boolean loaded = false;
/**
* Private constructor to prevent instantiation.
*/
private NativesLoader()
{
// Nothing to do here
}
/**
* Creates the temporary directory used for unpacking the native libraries.
* This directory is marked for deletion on exit.
*
* @return The temporary directory for native libraries.
*/
private static File createTempDirectory()
{
try
{
File tmp = File.createTempFile("usb4java", null);
tmp.delete();
tmp.mkdirs();
tmp.deleteOnExit();
return tmp;
}
catch (IOException e)
{
throw new NativesException("Unable to create temporary directory " +
"for usb4java natives: " + e, e);
}
}
/**
* Returns the platform name. This could be for example "linux-x86" or
* "windows-x86_64".
*
* @return The architecture name. Never null.
* @throws NativesException
* When operating system or architecture is not supported.
*/
private static String getPlatform()
{
if (WINDOWS)
return IS_64_BIT ? "windows-x86_64" : "windows-x86";
else if (MAC)
return "macosx-universal";
else if (LINUX)
return IS_64_BIT ? "linux-x86_64" : "linux-x86";
else
throw new NativesException("Unsupported operating system ("
+ System.getProperty("os.name") + ") and/or architecture ("
+ System.getProperty("os.arch") + ")");
}
/**
* Returns the name of the usb4java native library. This could be
* "libusb4java.dll" for example.
*
* @return The usb4java native library name. Never null.
* @throws NativesException
* When operating system or architecture is not supported.
*/
private static String getLibName()
{
if (WINDOWS)
return "libusb4java.dll";
else if (MAC)
return "libusb4java.dylib";
else if (LINUX)
return "libusb4java.so";
else
throw new NativesException("Unsupported operating system ("
+ System.getProperty("os.name") + ") and/or architecture ("
+ System.getProperty("os.arch") + ")");
}
/**
* Returns the name of the libusb native library. This could be
* "libusb0.dll" for example or null if this library is not needed on the
* current platform (Because it is provided by the operating system).
*
* @return The libusb native library name or null if not needed.
* @throws NativesException
* When operating system or architecture is not supported.
*/
private static String getExtraLibName()
{
if (WINDOWS)
return "libusb0.dll";
else if (MAC)
return "libusb.dylib";
else if (LINUX)
return null;
else
throw new NativesException("Unsupported operating system ("
+ System.getProperty("os.name") + ") and/or architecture ("
+ System.getProperty("os.arch") + ")");
}
/**
* Extracts a single library.
*
* @param platform
* The platform name (For example "linux-x86")
* @param lib
* The library name to extract (For example "libusb0.dll")
* @return The absolute path to the extracted library.
*/
private static String extractLibrary(String platform, String lib)
{
// Extract the usb4java library
final String source = platform + "/" + lib;
final File dest = new File(TMP, lib);
try
{
final InputStream stream =
NativesLoader.class.getClassLoader()
.getResourceAsStream(source);
if (stream == null)
throw new NativesException("Unable to find " + source
+ " in the classpath");
try
{
IOUtils.copy(stream, dest);
}
finally
{
stream.close();
}
}
catch (IOException e)
{
throw new NativesException(
"Unable to extract native library " + source + " to " + dest
+ ": " + e, e);
}
// Mark usb4java library for deletion
dest.deleteOnExit();
return dest.getAbsolutePath();
}
/**
* Extracts the usb4java library (and the libusb library if needed) and
* returns the absolute filename to be loaded by Java. The extracted
* libraries are marked for deletion on exit.
*
* @return The absolute path to the extracted usb4java library.
*/
private static String extract()
{
final String platform, lib, extraLib;
platform = getPlatform();
lib = getLibName();
extraLib = getExtraLibName();
if (extraLib != null) extractLibrary(platform, extraLib);
return extractLibrary(platform, lib);
}
/**
* Loads the usb4java native library. Can be safely called multiple times.
* Duplicate calls are ignored.
*/
public static void load()
{
if (loaded) return;
final String path = extract();
System.load(path);
loaded = true;
}
}

View File

@ -5,12 +5,8 @@
package de.ailis.usb4java.jni;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
@ -224,37 +220,9 @@ public final class USB
/** Endpoint interrupt type. */
public static final int USB_ENDPOINT_TYPE_INTERRUPT = 3;
/** Possible library names we try to load. */
private static String[] libNames = new String[] { "usb4java", "usb4java32",
"libusb4java", "libusb4java32" };
static
{
final List<Throwable> errors = new ArrayList<Throwable>();
for (final String libName : libNames)
{
try
{
System.loadLibrary(libName);
errors.clear();
break;
}
catch (final Throwable e)
{
errors.add(e);
}
}
if (!errors.isEmpty())
{
final StringWriter out = new StringWriter();
for (final Throwable error: errors)
{
error.printStackTrace(new PrintWriter(out));
}
LOG.severe(out.toString());
throw new RuntimeException(
"Unable to load JNI library of usb4java");
}
NativesLoader.load();
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2012 Klaus Reimer <k@ailis.de>
* See LICENSE.txt for licensing information.
*/
package de.ailis.usb4java.support;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* IO utility methods.
*
* @author Klaus Reimer (k@ailis.de)
*/
public final class IOUtils
{
/**
* Private constructor to prevent instantiation.
*/
private IOUtils()
{
// Empty
}
/**
* Copies the specified input stream to the specified output stream.
*
* @param input
* The input stream.
* @param output
* The output stream.
* @throws IOException
* If copying failed.
*/
public static void copy(final InputStream input, final OutputStream output)
throws IOException
{
final byte[] buffer = new byte[8192];
int read;
while ((read = input.read(buffer)) != -1)
{
output.write(buffer, 0, read);
}
}
/**
* Copies the specified input stream to the specified output file.
*
* @param input
* The input stream.
* @param output
* The output file.
* @throws IOException
* If copying failed.
*/
public static void copy(final InputStream input, final File output)
throws IOException
{
FileOutputStream stream = new FileOutputStream(output);
try
{
copy(input, stream);
}
finally
{
stream.close();
}
}
}