aboutsummaryrefslogtreecommitdiff
path: root/jni-plugin
diff options
context:
space:
mode:
Diffstat (limited to 'jni-plugin')
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Defaults.scala192
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniJvm.scala71
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniNative.scala114
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniPlugin.scala19
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Keys.scala53
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildToolApi.scala14
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala53
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala49
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/NoTool.scala9
-rw-r--r--jni-plugin/src/main/scala/ch/jodersky/sbt/jni/util/ByteCode.scala57
10 files changed, 312 insertions, 319 deletions
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Defaults.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Defaults.scala
deleted file mode 100644
index 49f4a49..0000000
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Defaults.scala
+++ /dev/null
@@ -1,192 +0,0 @@
-package ch.jodersky.sbt.jni
-
-import sbt._
-import sbt.Keys._
-import Keys._
-
-import build.CMake
-import build.BuildTool
-
-import ch.jodersky.jni.Platform
-import ch.jodersky.jni.NativeLoader
-
-object Defaults {
-
- lazy val buildSettings: Seq[Setting[_]] = Seq(
-
- baseDirectory in jni := (baseDirectory in ThisBuild).value / "native",
-
- target in jni := target.value / "native" / (jniPlatform in jni).value.id,
-
- jniPlatform in jni := Platform.current.getOrElse{
- sLog.value.warn("Warning: cannot determine platform! It will be set to 'unknown'.")
- Platform.Unknown
- },
-
- jniBuildTool in jni := {
- val tools = Seq(CMake)
-
- val base = (baseDirectory in jni).value
-
- val tool = if (base.exists && base.isDirectory) {
- tools.find(t => t detect base)
- } else {
- None
- }
- tool.getOrElse(
- sys.error("No supported native build tool detected. " +
- s"Check that the setting 'baseDirectory in jni' (currently $base) " +
- "points to a valid directory. Supported build tools are: " +
- tools.map(_.name).mkString(",")
- )
- )
- },
-
- clean := {
- val log = streams.value.log
- val tool = try {
- Some((jniBuildTool in jni).value)
- } catch {
- case _: Exception => None
- }
- tool foreach { t =>
- log.debug("Cleaning native build")
- t.api.clean(
- (baseDirectory in jni).value,
- log
- )
- }
- clean.value
- },
-
- jni := {
- val tool = (jniBuildTool in jni).value
- val dir = (baseDirectory in jni).value
- val targetDir = (target in jni).value / "lib"
- val log = streams.value.log
-
- tool.api.library(dir, targetDir, log)
- },
-
- javahClasses in javah := Seq(),
-
- javahObjects in javah := Seq(),
-
- target in javah := (baseDirectory in jni).value,
-
- fullClasspath in javah := (fullClasspath in Compile).value,
-
- javah := {
- val out = (target in javah).value
- val jcp: Seq[File] = (fullClasspath in javah).value.map(_.data)
- val cp = jcp.mkString(sys.props("path.separator"))
-
- val classes = (javahClasses in javah).value ++
- (javahObjects in javah).value.map(_ + "$")
-
- for (clazz <- classes) {
- val parts = Seq(
- "javah",
- "-d", out.getAbsolutePath,
- "-classpath", cp,
- clazz)
- val cmd = parts.mkString(" ")
- val ev = Process(cmd) ! streams.value.log
- if (ev != 0) sys.error(s"Error occured running javah. Exit code: ${ev}")
- }
-
- out
- }
-
- )
-
- lazy val bundleSettings: Seq[Setting[_]] = Seq(
-
- jniLibraryPath in jni := {
- "/" + (organization.value + "." + name.value).replaceAll("\\.|-", "/")
- },
-
- unmanagedResourceDirectories in jni := Seq(
- (baseDirectory).value / "lib_native"
- ),
-
- unmanagedClasspath ++= (unmanagedResourceDirectories in jni).value.map{ file =>
- Attributed.blank(file)
- },
-
- resourceManaged in jni := (target in jni).value / "lib_managed",
-
- managedResourceDirectories in jni := Seq(
- (resourceManaged in jni).value
- ),
-
- managedClasspath ++= {
-
- //build native library
- val library = jni.value
-
- //native library as a managed resource file
- val libraryResource = (resourceManaged in jni).value /
- NativeLoader.fullLibraryPath(
- (jniLibraryPath in jni).value,
- (jniPlatform in jni).value
- )
-
- //copy native library to a managed resource (so it can also be loaded when not packages as a jar)
- IO.copyFile(library, libraryResource)
-
- Seq(Attributed.blank((resourceManaged in jni).value))
- },
-
- packageJni in Global := {
-
- val unmanagedMappings: Seq[(File, String)] = (unmanagedResourceDirectories in jni).value flatMap { dir =>
- val files = (dir ** "*").filter(_.isFile).get
- files map { file =>
- println(file.getAbsolutePath)
- file -> (file relativeTo dir).get.getPath
- }
- }
-
- managedClasspath.value //call this to generate files in resourceManaged
-
- val managedMappings: Seq[(File, String)] = (managedResourceDirectories in jni).value flatMap { dir =>
- val files = (dir ** "*").filter(_.isFile).get
- files map { file =>
- println(file.getAbsolutePath)
- file -> (file relativeTo dir).get.getPath
- }
- }
-
- val out = target.value / (name.value + "-native.jar")
-
- val manifest = new java.util.jar.Manifest
- Package.makeJar(
- unmanagedMappings ++ managedMappings,
- out,
- manifest,
- streams.value.log
- )
- out
- }
-
- )
-
- lazy val clientSettings: Seq[Setting[_]] = Seq(
- libraryDependencies += "ch.jodersky" %% "jni-library" % "0.1-SNAPSHOT",
- fork in run := true,
- artifact in jni := {
- Artifact(
- name = name.value,
- `type` = "jar",
- extension = "jar",
- classifier = Some("native"),
- configurations = Seq(Runtime),
- url = None
- ) extra (
- "platform" -> "all"
- )
- }
- ) ++ addArtifact(artifact in jni, packageJni)
-
-}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniJvm.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniJvm.scala
new file mode 100644
index 0000000..70c5787
--- /dev/null
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniJvm.scala
@@ -0,0 +1,71 @@
+package ch.jodersky.sbt.jni
+
+import sbt._
+import sbt.Keys._
+import util.ByteCode
+
+object JniJvm extends AutoPlugin {
+
+ override def requires = plugins.JvmPlugin
+
+ object autoImport {
+
+ val javahClasses = taskKey[Set[String]](
+ "Fully qualified names of classes containing native declarations."
+ )
+
+ val javah = taskKey[File](
+ "Generate JNI headers. Returns the directory containing generated headers."
+ )
+
+ }
+ import autoImport._
+
+ lazy val mainSettings: Seq[Setting[_]] = Seq(
+
+ javahClasses in javah := {
+ val classFiles: Set[File] = compile.value.relations.allProducts.toSet
+ val nativeClasses = classFiles.flatMap { file =>
+ ByteCode.natives(file)
+ }
+ nativeClasses
+ },
+
+ target in javah := target.value / "include",
+
+ fullClasspath in javah := (fullClasspath in Compile).value,
+
+ javah := {
+ val out = (target in javah).value
+ val jcp: Seq[File] = (fullClasspath in javah).value.map(_.data)
+ val cp = jcp.mkString(sys.props("path.separator"))
+ val log = streams.value.log
+
+ val classes = (javahClasses in javah).value
+
+ for (clazz <- classes) {
+ log.info("Generating header for " + clazz + "...")
+ val parts = Seq(
+ "javah",
+ "-d", out.getAbsolutePath,
+ "-classpath", cp,
+ clazz
+ )
+ val cmd = parts.mkString(" ")
+ val ev = Process(cmd) ! streams.value.log
+ if (ev != 0) sys.error(s"Error occured running javah. Exit code: ${ev}")
+ }
+ out
+ }
+ )
+
+ lazy val clientSettings = Seq(
+ //enable enhanced native library extraction
+ libraryDependencies += "ch.jodersky" %% "jni-library" % Version.PluginVersion,
+ crossPaths := false, //don't need to appends scala version to native jars
+ fork in run := true //fork new JVM as native libraries can only be loaded once
+ )
+
+ override lazy val projectSettings = inConfig(Compile)(mainSettings) ++ clientSettings
+
+}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniNative.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniNative.scala
new file mode 100644
index 0000000..7e36f50
--- /dev/null
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniNative.scala
@@ -0,0 +1,114 @@
+package ch.jodersky.sbt.jni
+
+import build._
+import ch.jodersky.jni.{NativeLoader, Platform}
+import sbt._
+import sbt.Keys._
+
+object JniNative extends AutoPlugin {
+
+ override def requires = plugins.JvmPlugin
+
+ object autoImport {
+
+ val jni = taskKey[File]("Builds a native library (by calling the native build tool).")
+
+ val jniPlatform = settingKey[Platform]("Platform of the system this build is running on.")
+ val jniBuildTool = taskKey[BuildTool]("The build tool to be used when building a native library.")
+
+ val jniLibraryPath = settingKey[String]("String that is prepended to the path of a native library when packaged.")
+
+ }
+ import autoImport._
+
+ lazy val rawSettings: Seq[Setting[_]] = Seq(
+
+ sourceDirectory in jni := baseDirectory.value / "src",
+
+ target in Global in jni := target.value / "native" / (jniPlatform in jni).value.id,
+
+ jniPlatform in Global in jni := Platform.current.getOrElse {
+ sLog.value.warn("Warning: cannot determine platform! It will be set to 'unknown'.")
+ Platform.Unknown
+ },
+
+ jniBuildTool in jni := {
+ val tools = Seq(CMake)
+
+ val base = (sourceDirectory in jni).value
+
+ val tool = if (base.exists && base.isDirectory) {
+ tools.find(t => t detect base)
+ } else {
+ None
+ }
+ tool.getOrElse(
+ sys.error("No supported native build tool detected. " +
+ s"Check that the setting 'sourceDirectory in jni' (currently $base) " +
+ "points to a valid directory. Supported build tools are: " +
+ tools.map(_.name).mkString(","))
+ )
+ },
+
+ clean in jni := {
+ val log = streams.value.log
+ val tool = try {
+ Some((jniBuildTool in jni).value)
+ } catch {
+ case _: Exception => None
+ }
+ tool foreach { t =>
+ log.debug("Cleaning native build")
+ t.api.clean(
+ (sourceDirectory in jni).value,
+ log
+ )
+ }
+ },
+
+ jni := {
+ val tool = (jniBuildTool in jni).value
+ val dir = (sourceDirectory in jni).value
+ val buildDir = (target in jni).value / "build"
+ val targetDir = (target in jni).value / "lib"
+ val log = streams.value.log
+
+ IO.createDirectory(buildDir)
+ IO.createDirectory(targetDir)
+
+ tool.api.library(dir, buildDir, targetDir, log)
+ },
+
+ clean := {
+ (clean in jni).value
+ clean.value
+ },
+
+ jniLibraryPath in jni := {
+ "/" + organization.value.replaceAll("\\.", "/") + "/" + name.value
+ },
+
+ unmanagedResourceDirectories += baseDirectory.value / "lib_native",
+
+ resourceGenerators += Def.task {
+ //build native library
+ val library = jni.value
+
+ //native library as a managed resource file
+ val libraryResource = (resourceManaged in Compile).value /
+ NativeLoader.fullLibraryPath(
+ (jniLibraryPath in jni).value,
+ (jniPlatform in jni).value
+ )
+
+ //copy native library to a managed resource (so it can also be loaded when not packaged as a jar)
+ IO.copyFile(library, libraryResource)
+
+ Seq(libraryResource)
+ }.taskValue
+
+ )
+
+ override lazy val projectSettings = inConfig(Compile)(rawSettings)
+
+}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniPlugin.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniPlugin.scala
deleted file mode 100644
index 98f8214..0000000
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/JniPlugin.scala
+++ /dev/null
@@ -1,19 +0,0 @@
-package ch.jodersky.sbt.jni
-
-import sbt._
-
-object JniPlugin extends AutoPlugin {
-
- override def requires = plugins.JvmPlugin
-
- lazy val autoImport = Keys
- import autoImport._
-
- override lazy val projectSettings =
- Defaults.buildSettings ++
- inConfig(Runtime)(Defaults.bundleSettings) ++
- Defaults.clientSettings
- //++inConfig(Runtime)(Defaults.bundleSettings)
-
-
-}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Keys.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Keys.scala
deleted file mode 100644
index 4286ff6..0000000
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/Keys.scala
+++ /dev/null
@@ -1,53 +0,0 @@
-package ch.jodersky.sbt.jni
-
-import build.BuildTool
-
-import ch.jodersky.jni.Platform
-import sbt._
-
-object Keys {
-
- val jni = taskKey[File]("Builds a native library (by calling the native build tool).")
- val jniClean = taskKey[Unit]("Cleans the native build directory.")
-
- val jniPlatform = settingKey[Platform]("Platform of the system this build is running on.")
- val jniBuildTool = taskKey[BuildTool]("The build tool to be used when building a native library.")
-
- //bundle
- val jniLibraryPath = settingKey[String]("Foo")
- val packageJni = taskKey[File]("Package native librraies into a fat jar.")
-
- val javahClasses = settingKey[Seq[String]]("Fully qualified names of classes containing native declarations.")
- val javahObjects = settingKey[Seq[String]]("Fully qualified names of singleton objects containing native declarations.")
- val javah = taskKey[File]("Generate JNI headers. Returns the directory containing generated headers.")
-
-
- //ivy
- //libraryDependencies += "com.github.jodersky" % "flow" % "2.4" extra("platform", "all") artifact("libflow", "so")
-
- //maven
- //libraryDependencies += "com.github.jodersky" % "flow" % "2.4" classifier "native"
-
-
-
- //Wraps tasks associated to an existing native build tool
- //val Native = config("native")
-
- //Extra tasks in native
- // val buildTool = settingKey[BuildTool]("The native build tool used.")
- //val platform = settingKey[Platform]("Platform of the system this build is being run on.")
-
- // organization = org.example
- // name = foo-bar
- // libraryPrefix = organization + "." + normalize(name)
- // libraryPrefix = org/example/foo/bar
- // libraryPrefix = org/example/foo/bar/native/<platform>/libraries
-
-
- //val libraryPath = settingKey[String](
- // "A slash (/) seprated path that specifies where native libraries should be stored (in a jar).")
- //val libraryResourceDirectory = settingKey[File]("")
-
- //Javah
-
-}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildToolApi.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildToolApi.scala
index 47d9a90..43dd17a 100644
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildToolApi.scala
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/BuildToolApi.scala
@@ -4,19 +4,23 @@ package build
import java.io.File
import sbt.Logger
-
trait BuildToolApi {
/** Invokes the native build tool's clean task */
- def clean(baseDirectory: File, log: Logger): Unit
+ def clean(baseDirectory: File, log: Logger): Unit
/**
- * Invokes the native build tool's main task, resulting in a single shared
- * library file.
- */
+ * Invokes the native build tool's main task, resulting in a single shared
+ * library file.
+ * @param baseDirectory the directory where the native project is located
+ * @param buildDirectory a directory from where the build is called, it may be used to store temporary files
+ * @param targetDirectory the directory into which the native library is copied
+ * @return the native library file
+ */
def library(
baseDirectory: File,
targetDirectory: File,
+ buildDirectory: File,
log: Logger
): File
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala
index cd0b363..3f75585 100644
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/CMake.scala
@@ -1,12 +1,8 @@
package ch.jodersky.sbt.jni
package build
-import Keys._
-import sbt._
-import sbt.Keys._
-import sbt.Logger
import java.io.File
-
+import sbt._
object CMake extends BuildTool {
@@ -14,46 +10,21 @@ object CMake extends BuildTool {
def detect(baseDirectory: File) = baseDirectory.list().contains("CMakeLists.txt")
- object api extends BuildToolApi {
+ object api extends ConfigureMakeInstall {
- def clean(baseDirectory: File, log: Logger) = Process("make clean", baseDirectory) ! log
-
- def library(
- baseDirectory: File,
- targetDirectory: File,
- log: Logger
- ): File = {
- val out = targetDirectory
- val outPath = out.getAbsolutePath
-
- val configure = Process(
+ override def configure(base: File, build: File, target: File) = {
+ val targetPath = target.getAbsolutePath
+ Process(
//Disable producing versioned library files, not needed for fat jars.
- s"cmake -DCMAKE_INSTALL_PREFIX:PATH=$outPath -DLIB_INSTALL_DIR:PATH=$outPath -DENABLE_VERSIONED_LIB:BOOLEAN=OFF",
- baseDirectory
+ "cmake " +
+ s"-DCMAKE_INSTALL_PREFIX:PATH=$targetPath " +
+ s"-DLIB_INSTALL_DIR:PATH=$targetPath " +
+ "-DENABLE_VERSIONED_LIB:BOOLEAN=OFF " +
+ base.getAbsolutePath,
+ build
)
-
- val make = Process("make", baseDirectory)
-
- val makeInstall = Process("make install", baseDirectory)
-
- val ev = configure #&& make #&& makeInstall ! log
- if (ev != 0) sys.error(s"Building native library failed. Exit code: ${ev}")
-
- val products: List[File] = (out ** ("*" -- "*.la")).get.filter(_.isFile).toList
-
- //only one produced library is expected
- products match {
- case Nil =>
- sys.error("No files were created during compilation, " +
- "something went wrong with the autotools configuration.")
- case head :: Nil =>
- head
- case head :: tail =>
- log.warn("More than one file was created during compilation, " +
- s"only the first one (${head.getAbsolutePath}) will be used.")
- head
- }
}
+
}
}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala
new file mode 100644
index 0000000..97011ed
--- /dev/null
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/ConfigureMakeInstall.scala
@@ -0,0 +1,49 @@
+package ch.jodersky.sbt.jni
+package build
+
+import java.io.File
+import sbt._
+
+/** Native build tools relying on a standard 'configure && make && make install' process */
+trait ConfigureMakeInstall extends BuildToolApi {
+
+ override def clean(baseDirectory: File, log: Logger) = Process("make clean", baseDirectory) ! log
+
+ def configure(baseDirectory: File, buildDirectory: File, targetDirectory: File): ProcessBuilder
+
+ def make(baseDirectory: File, buildDirectory: File, targetDirectory: File): ProcessBuilder = Process("make", buildDirectory)
+
+ def install(baseDirectory: File, buildDirectory: File, targetDirectory: File): ProcessBuilder = Process("make install", buildDirectory)
+
+ override def library(
+ baseDirectory: File,
+ buildDirectory: File,
+ targetDirectory: File,
+ log: Logger
+ ): File = {
+
+ val ev = (
+ configure(baseDirectory, buildDirectory, targetDirectory) #&&
+ make(baseDirectory, buildDirectory, targetDirectory) #&&
+ install(baseDirectory, buildDirectory, targetDirectory)
+ ) ! log
+
+ if (ev != 0) sys.error(s"Building native library failed. Exit code: ${ev}")
+
+ val products: List[File] = (targetDirectory ** ("*" -- "*.la")).get.filter(_.isFile).toList
+
+ //only one produced library is expected
+ products match {
+ case Nil =>
+ sys.error("No files were created during compilation, " +
+ "something went wrong with the autotools configuration.")
+ case head :: Nil =>
+ head
+ case head :: tail =>
+ log.warn("More than one file was created during compilation, " +
+ s"only the first one (${head.getAbsolutePath}) will be used.")
+ head
+ }
+ }
+}
+
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/NoTool.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/NoTool.scala
deleted file mode 100644
index 96dd85f..0000000
--- a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/build/NoTool.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-package ch.jodersky.sbt.jni
-package build
-
-
-object NoTool {
-
-
-
-}
diff --git a/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/util/ByteCode.scala b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/util/ByteCode.scala
new file mode 100644
index 0000000..308a077
--- /dev/null
+++ b/jni-plugin/src/main/scala/ch/jodersky/sbt/jni/util/ByteCode.scala
@@ -0,0 +1,57 @@
+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 ByteCode {
+
+ private class NativeFinder extends ClassVisitor(Opcodes.ASM5) {
+
+ //contains any 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 //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()
+ }
+ }
+ }
+
+ def natives(classFile: File): Set[String] = using(new FileInputStream(classFile)) { in =>
+ val reader = new ClassReader(in)
+ val finder = new NativeFinder
+ reader.accept(finder, 0)
+ finder.nativeClasses
+ }
+
+}