1. Added support for building the PairHMM vector library into build.xml.

The library is compiled using  makefile and copied into the directory:
build/java/classes/org/broadinstitute/sting/utils/pairhmm/
2. Bundled the library into StingUtils.jar. Unpacked and loaded at
runtime without the need to set java.library.path

Caveats:
Platform independence has probably been thrown out of the window.
Assumptions:
a. make command exists at /usr/bin/make
b. rsync command exists at /usr/bin/rsync
c. icc is in the PATH of the user
This commit is contained in:
Karthik Gururaj 2014-02-07 13:13:59 -08:00
parent 7815c30df8
commit dc44b64ad8
2 changed files with 172 additions and 56 deletions

View File

@ -64,6 +64,7 @@
<property name="R.private.scripts.dir" value="${private.dir}/R/scripts" /> <property name="R.private.scripts.dir" value="${private.dir}/R/scripts" />
<property name="R.protected.scripts.dir" value="${protected.dir}/R/scripts" /> <property name="R.protected.scripts.dir" value="${protected.dir}/R/scripts" />
<property name="R.public.src.dir" value="${public.dir}/R/src" /> <property name="R.public.src.dir" value="${public.dir}/R/src" />
<property name="vector.pairhmm.library.source.dir" value="${public.dir}/c++/VectorPairHMM" />
<!-- Build directories --> <!-- Build directories -->
<property name="java.classes" value="${build.dir}/java/classes" /> <property name="java.classes" value="${build.dir}/java/classes" />
@ -648,9 +649,23 @@
</copy> </copy>
</target> </target>
<target name="sting-utils.jar" depends="gatk.compile, init.jar, R.public.tar, R.script.stage"> <target name="build.vector.pairhmm.library">
<exec dir="${vector.pairhmm.library.source.dir}" executable="/usr/bin/make">
</exec>
</target>
<target name="copy.vector.pairhmm.library" depends="build.vector.pairhmm.library">
<exec executable="/usr/bin/rsync">
<arg value="-a"/>
<arg value="${vector.pairhmm.library.source.dir}/libVectorLoglessPairHMM.so"/>
<arg value="${java.classes}/org/broadinstitute/sting/utils/pairhmm/libVectorLoglessPairHMM.so"/>
</exec>
</target>
<target name="sting-utils.jar" depends="gatk.compile, init.jar, R.public.tar, R.script.stage, copy.vector.pairhmm.library">
<jar jarfile="${dist.dir}/StingUtils.jar"> <jar jarfile="${dist.dir}/StingUtils.jar">
<fileset dir="${java.classes}" includes="**/sting/utils/**/*.class"/> <fileset dir="${java.classes}" includes="**/sting/utils/**/*.class"/>
<fileset dir="${java.classes}" includes="**/sting/utils/**/*.so"/>
<fileset dir="${java.classes}" includes="**/sting/commandline/**/*.class"/> <fileset dir="${java.classes}" includes="**/sting/commandline/**/*.class"/>
<fileset dir="${java.classes}" includes="**/sting/pipeline/**/*.class"/> <fileset dir="${java.classes}" includes="**/sting/pipeline/**/*.class"/>
<fileset dir="${java.classes}" includes="**/sting/tools/**/*.class"/> <fileset dir="${java.classes}" includes="**/sting/tools/**/*.class"/>

View File

@ -59,6 +59,15 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
//For loading library from jar
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/** /**
* Created with IntelliJ IDEA. * Created with IntelliJ IDEA.
@ -111,7 +120,28 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM {
synchronized(isVectorLoglessPairHMMLibraryLoaded) { synchronized(isVectorLoglessPairHMMLibraryLoaded) {
//Load the library and initialize the FieldIDs //Load the library and initialize the FieldIDs
if(!isVectorLoglessPairHMMLibraryLoaded) { if(!isVectorLoglessPairHMMLibraryLoaded) {
try
{
//Try loading from Java's library path first
//Useful if someone builds his/her own library and wants to override the bundled
//implementation without modifying the Java code
System.loadLibrary("VectorLoglessPairHMM"); System.loadLibrary("VectorLoglessPairHMM");
}
catch(UnsatisfiedLinkError ule)
{
//Could not load from Java's library path - try unpacking from jar
try
{
logger.info("libVectorLoglessPairHMM not found in JVM library path - trying to unpack from StingUtils.jar");
loadLibraryFromJar("/org/broadinstitute/sting/utils/pairhmm/libVectorLoglessPairHMM.so");
}
catch(IOException ioe)
{
//Throw the UnsatisfiedLinkError to make it clear to the user what failed
throw ule;
}
}
isVectorLoglessPairHMMLibraryLoaded = true; isVectorLoglessPairHMMLibraryLoaded = true;
jniInitializeClassFieldsAndMachineMask(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class, enableAll); //need to do this only once jniInitializeClassFieldsAndMachineMask(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class, enableAll); //need to do this only once
} }
@ -229,4 +259,75 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM {
super.close(); super.close();
jniClose(); jniClose();
} }
//Copied from http://frommyplayground.com/how-to-load-native-jni-library-from-jar
/**
* Loads library from current JAR archive
*
* The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
* Method uses String as filename because the pathname is "abstract", not system-dependent.
*
* @param filename The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
* @throws IOException If temporary file creation or read/write operation fails
* @throws IllegalArgumentException If source file (param path) does not exist
* @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}).
*/
public static void loadLibraryFromJar(String path) throws IOException {
if (!path.startsWith("/")) {
throw new IllegalArgumentException("The path to be absolute (start with '/').");
}
// Obtain filename from path
String[] parts = path.split("/");
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
// Split filename to prexif and suffix (extension)
String prefix = "";
String suffix = null;
if (filename != null) {
parts = filename.split("\\.", 2);
prefix = parts[0];
suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
}
// Check if the filename is okay
if (filename == null || prefix.length() < 3) {
throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
}
// Prepare temporary file
File temp = File.createTempFile(prefix, suffix);
//System.out.println("Temp lib file "+temp.getAbsolutePath());
temp.deleteOnExit();
if (!temp.exists()) {
throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
}
// Prepare buffer for data copying
byte[] buffer = new byte[1024];
int readBytes;
// Open and check input stream
InputStream is = VectorLoglessPairHMM.class.getResourceAsStream(path);
if (is == null) {
throw new FileNotFoundException("File " + path + " was not found inside JAR.");
}
// Open output stream and copy data between source file in JAR and the temporary file
OutputStream os = new FileOutputStream(temp);
try {
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} finally {
// If read/write fails, close streams safely before throwing an exception
os.close();
is.close();
}
// Finally, load the library
System.load(temp.getAbsolutePath());
}
} }