diff options
author | Jakob Odersky <jakob@odersky.com> | 2016-05-02 05:19:07 -0700 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2016-05-11 11:17:09 -0700 |
commit | 791cb363b77332e3abdf4039102dfcdb863ce6c3 (patch) | |
tree | 09ff5d807a1407abedade57b692204ceac3f3280 /plugin/src/main/scala/ch/jodersky/sbt/jni/util | |
parent | 49563ee13599b0cb1add27b24446677a13b1f563 (diff) | |
download | sbt-jni-791cb363b77332e3abdf4039102dfcdb863ce6c3.tar.gz sbt-jni-791cb363b77332e3abdf4039102dfcdb863ce6c3.tar.bz2 sbt-jni-791cb363b77332e3abdf4039102dfcdb863ce6c3.zip |
Use macro annotation to load native library
This also removes the need for third projects to depend on a "loader library".
Diffstat (limited to 'plugin/src/main/scala/ch/jodersky/sbt/jni/util')
-rw-r--r-- | plugin/src/main/scala/ch/jodersky/sbt/jni/util/BytecodeUtil.scala | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/plugin/src/main/scala/ch/jodersky/sbt/jni/util/BytecodeUtil.scala b/plugin/src/main/scala/ch/jodersky/sbt/jni/util/BytecodeUtil.scala new file mode 100644 index 0000000..fe728a6 --- /dev/null +++ b/plugin/src/main/scala/ch/jodersky/sbt/jni/util/BytecodeUtil.scala @@ -0,0 +1,62 @@ +package ch.jodersky.sbt.jni +package util + +import java.io.{ File, FileInputStream, Closeable } +import scala.collection.mutable.{ HashSet } + +import org.objectweb.asm.{ ClassReader, ClassVisitor, MethodVisitor, Opcodes } + +object BytecodeUtil { + + private class NativeFinder extends ClassVisitor(Opcodes.ASM5) { + + // classes found to contain at least one @native def + val _nativeClasses = new HashSet[String] + def nativeClasses = _nativeClasses.toSet + + private var fullyQualifiedName: String = "" + + override def visit(version: Int, access: Int, name: String, signature: String, + superName: String, interfaces: Array[String]): Unit = { + fullyQualifiedName = name.replaceAll("/", ".") + } + + override def visitMethod(access: Int, name: String, desc: String, + signature: String, exceptions: Array[String]): MethodVisitor = { + + val isNative = (access & Opcodes.ACC_NATIVE) != 0 + + if (isNative) { + _nativeClasses += fullyQualifiedName + } + + null //return null, do not visit method further + } + + } + + private def using[A >: Null <: Closeable, R](mkStream: => A)(action: A => R): R = { + var stream: A = null + try { + stream = mkStream + action(stream) + } finally { + if (stream != null) { + stream.close() + } + } + } + + /** Finds classes containing native implementations. + * @param classFile java class file from which classes are read + * @return all fully qualified names of classes that contain at least one member annotated + * with @native + */ + def nativeClasses(classFile: File): Set[String] = using(new FileInputStream(classFile)) { in => + val reader = new ClassReader(in) + val finder = new NativeFinder + reader.accept(finder, 0) + finder.nativeClasses + } + +} |