diff --git a/scala-package/assembly/linux-x86_64-cpu/pom.xml b/scala-package/assembly/linux-x86_64-cpu/pom.xml
index 05db3a5f70b9..d3c95a60639a 100644
--- a/scala-package/assembly/linux-x86_64-cpu/pom.xml
+++ b/scala-package/assembly/linux-x86_64-cpu/pom.xml
@@ -30,6 +30,10 @@
MXNet Scala Package - Full Linux-x86_64 CPU-only
jar
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
diff --git a/scala-package/assembly/linux-x86_64-cpu/src/main/assembly/assembly.xml b/scala-package/assembly/linux-x86_64-cpu/src/main/assembly/assembly.xml
index 9f28706ac596..6b5a5b238216 100644
--- a/scala-package/assembly/linux-x86_64-cpu/src/main/assembly/assembly.xml
+++ b/scala-package/assembly/linux-x86_64-cpu/src/main/assembly/assembly.xml
@@ -41,4 +41,10 @@
+
+
+
+ lib/native
+
+
diff --git a/scala-package/assembly/linux-x86_64-gpu/pom.xml b/scala-package/assembly/linux-x86_64-gpu/pom.xml
index 708b1c48e98b..122beb0977ba 100644
--- a/scala-package/assembly/linux-x86_64-gpu/pom.xml
+++ b/scala-package/assembly/linux-x86_64-gpu/pom.xml
@@ -30,6 +30,10 @@
MXNet Scala Package - Full Linux-x86_64 GPU
jar
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
diff --git a/scala-package/assembly/linux-x86_64-gpu/src/main/assembly/assembly.xml b/scala-package/assembly/linux-x86_64-gpu/src/main/assembly/assembly.xml
index 2b65a8c7ad66..471f07cf4bfc 100644
--- a/scala-package/assembly/linux-x86_64-gpu/src/main/assembly/assembly.xml
+++ b/scala-package/assembly/linux-x86_64-gpu/src/main/assembly/assembly.xml
@@ -41,4 +41,10 @@
+
+
+
+ lib/native
+
+
diff --git a/scala-package/assembly/osx-x86_64-cpu/main/assembly/assembly.xml b/scala-package/assembly/osx-x86_64-cpu/main/assembly/assembly.xml
deleted file mode 100644
index d0550a3623b1..000000000000
--- a/scala-package/assembly/osx-x86_64-cpu/main/assembly/assembly.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
- full
-
- jar
-
- false
-
-
-
- *:*:jar
-
- /
- true
- true
- runtime
-
-
- lib/native
- ${artifact.artifactId}${dashClassifier?}.${artifact.extension}
- false
- false
- false
-
- *:*:dll:*
- *:*:so:*
- *:*:jnilib:*
-
-
-
-
diff --git a/scala-package/assembly/osx-x86_64-cpu/pom.xml b/scala-package/assembly/osx-x86_64-cpu/pom.xml
index 2f80dd7fb707..68fb09df68e3 100644
--- a/scala-package/assembly/osx-x86_64-cpu/pom.xml
+++ b/scala-package/assembly/osx-x86_64-cpu/pom.xml
@@ -30,6 +30,10 @@
MXNet Scala Package - Full OSX-x86_64 CPU-only
jar
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
diff --git a/scala-package/assembly/osx-x86_64-cpu/src/main/assembly/assembly.xml b/scala-package/assembly/osx-x86_64-cpu/src/main/assembly/assembly.xml
index 7a6c3ea9f525..3f632a76daf6 100644
--- a/scala-package/assembly/osx-x86_64-cpu/src/main/assembly/assembly.xml
+++ b/scala-package/assembly/osx-x86_64-cpu/src/main/assembly/assembly.xml
@@ -41,4 +41,10 @@
+
+
+
+ lib/native
+
+
diff --git a/scala-package/core/pom.xml b/scala-package/core/pom.xml
index 1b1a570c3386..7b3cffc96f6b 100644
--- a/scala-package/core/pom.xml
+++ b/scala-package/core/pom.xml
@@ -28,6 +28,7 @@
true
+ ${project.parent.basedir}/..
mxnet-core_2.11
@@ -93,6 +94,9 @@
-Djava.library.path=${project.parent.basedir}/native/${platform}/target \
-Dlog4j.configuration=file://${project.basedir}/src/test/resources/log4j.properties
+
+ ${MXNET_DIR}/lib
+
@@ -104,6 +108,10 @@
-Djava.library.path=${project.parent.basedir}/native/${platform}/target
${skipTests}
+ always
+
+ ${MXNET_DIR}/lib
+
diff --git a/scala-package/core/src/main/scala/org/apache/mxnet/util/NativeLibraryLoader.scala b/scala-package/core/src/main/scala/org/apache/mxnet/util/NativeLibraryLoader.scala
index e94d320391fa..2ce893b478ed 100644
--- a/scala-package/core/src/main/scala/org/apache/mxnet/util/NativeLibraryLoader.scala
+++ b/scala-package/core/src/main/scala/org/apache/mxnet/util/NativeLibraryLoader.scala
@@ -85,12 +85,10 @@ private[mxnet] object NativeLibraryLoader {
}
logger.debug(s"Attempting to load $loadLibname")
val libFileInJar = libPathInJar + loadLibname
- val is: InputStream = getClass.getResourceAsStream(libFileInJar)
- if (is == null) {
- throw new UnsatisfiedLinkError(s"Couldn't find the resource $loadLibname")
- }
- logger.info(s"Loading $loadLibname from $libPathInJar copying to $libname")
- loadLibraryFromStream(libname, is)
+ saveLibraryToTemp("libmxnet.so", "/lib/native/libmxnet.so")
+ val tempfile: File = saveLibraryToTemp(libname, libFileInJar)
+
+ loadLibraryFromFile(libname, tempfile)
}
/**
@@ -109,7 +107,7 @@ private[mxnet] object NativeLibraryLoader {
@throws(classOf[IOException])
private def createTempFile(name: String): File = {
- new File(_tempDir + File.separator + name)
+ new File(_tempDir, name)
}
/**
@@ -117,11 +115,34 @@ private[mxnet] object NativeLibraryLoader {
* and loads from there.
*
* @param libname name of the library (just used in constructing the library name)
- * @param is InputStream pointing to the library
+ * @param tempfile File pointing to the library
*/
- private def loadLibraryFromStream(libname: String, is: InputStream) {
+ private def loadLibraryFromFile(libname: String, tempfile: File) {
+ try {
+ logger.debug("Loading library from {}", tempfile.getPath)
+ System.load(tempfile.getPath)
+ } catch {
+ case ule: UnsatisfiedLinkError =>
+ logger.error("Couldn't load copied link file: {}", ule.toString)
+ throw ule
+ }
+ }
+
+ /**
+ * Load a system library from a stream. Copies the library to a temp file
+ * and loads from there.
+ *
+ * @param libname name of the library (just used in constructing the library name)
+ * @param resource String resource path in the jar file
+ */
+ private def saveLibraryToTemp(libname: String, resource: String): File = {
try {
- val tempfile: File = createTempFile(libname)
+ val is: InputStream = getClass.getResourceAsStream(resource)
+ if (is == null) {
+ throw new UnsatisfiedLinkError(s"Couldn't find the resource $resource")
+ }
+
+ val tempfile: File = new File(_tempDir, libname)
val os: OutputStream = new FileOutputStream(tempfile)
logger.debug("tempfile.getPath() = {}", tempfile.getPath)
val savedTime: Long = System.currentTimeMillis
@@ -131,20 +152,14 @@ private[mxnet] object NativeLibraryLoader {
os.write(buf, 0, len)
len = is.read(buf)
}
- os.flush()
- val lock: InputStream = new FileInputStream(tempfile)
os.close()
+ is.close()
val seconds: Double = (System.currentTimeMillis - savedTime).toDouble / 1e3
- logger.debug(s"Copying took $seconds seconds.")
- logger.debug("Loading library from {}", tempfile.getPath)
- System.load(tempfile.getPath)
- lock.close()
+ logger.debug(s"Copying $libname took $seconds seconds.")
+ tempfile
} catch {
case io: IOException =>
- logger.error("Could not create the temp file: {}", io.toString)
- case ule: UnsatisfiedLinkError =>
- logger.error("Couldn't load copied link file: {}", ule.toString)
- throw ule
+ throw new UnsatisfiedLinkError(s"Could not create temp file for $libname")
}
}
}
diff --git a/scala-package/examples/pom.xml b/scala-package/examples/pom.xml
index 666ea1c9fb5c..1ebc37a0d456 100644
--- a/scala-package/examples/pom.xml
+++ b/scala-package/examples/pom.xml
@@ -31,6 +31,7 @@
true
+ ${project.parent.basedir}/..
@@ -167,6 +168,9 @@
-Djava.library.path=${project.parent.basedir}/native/${platform}/target \
-Dlog4j.configuration=file://${project.basedir}/src/test/resources/log4j.properties
+
+ ${MXNET_DIR}/lib
+
diff --git a/scala-package/infer/pom.xml b/scala-package/infer/pom.xml
index d8be5584677c..6a8e77d63e11 100644
--- a/scala-package/infer/pom.xml
+++ b/scala-package/infer/pom.xml
@@ -31,6 +31,7 @@
true
+ ${project.parent.basedir}/..
@@ -93,6 +94,9 @@
-Djava.library.path=${project.parent.basedir}/native/${platform}/target \
-Dlog4j.configuration=file://${project.basedir}/src/test/resources/log4j.properties
+
+ ${MXNET_DIR}/lib
+
diff --git a/scala-package/init-native/linux-x86_64/pom.xml b/scala-package/init-native/linux-x86_64/pom.xml
index c1f61fca01aa..2f0f586ee2e0 100644
--- a/scala-package/init-native/linux-x86_64/pom.xml
+++ b/scala-package/init-native/linux-x86_64/pom.xml
@@ -32,6 +32,10 @@
so
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
@@ -78,22 +82,24 @@
-std=c++0x
- -I${project.basedir}/../../../include
- ${all_includes}
- ${cflags}
+ -I${MXNET_DIR}/include
+ -I${MXNET_DIR}/3rdparty/dmlc-core/include
+ -I${MXNET_DIR}/3rdparty/mshadow
+ -I${MXNET_DIR}/3rdparty/dlpack/include
+ -I${MXNET_DIR}/3rdparty/tvm/nnvm/include
+ -DMSHADOW_USE_MKL=0 -DMSHADOW_USE_CUDA=0
+ -O3 -DNDEBUG=1 -fPIC -msse3 -mf16c
+ -Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
-shared
- ${all_ldpaths}
-Wl,--whole-archive
- ${lddeps}
- -Wl,--no-whole-archive
+ -Wl,--no-whole-archive -pthread -lm -fopenmp -lrt
- ${ldflags}
- -fopenmp
+ -Wl,-rpath=${dollar}ORIGIN -lmxnet -L${MXNET_DIR}/lib
@@ -102,7 +108,6 @@
javah
generate-sources
- linux
default
${project.build.directory}/custom-javah
${basedir}
@@ -117,6 +122,25 @@
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+ link-native-lib
+ generate-resources
+
+ exec
+
+
+ ln
+ -sf ${MXNET_DIR}/lib/libmxnet.so ${project.build.directory}/libmxnet.so
+
+
+
+
diff --git a/scala-package/init-native/osx-x86_64/pom.xml b/scala-package/init-native/osx-x86_64/pom.xml
index 1c1342eea149..59a04192ad5c 100644
--- a/scala-package/init-native/osx-x86_64/pom.xml
+++ b/scala-package/init-native/osx-x86_64/pom.xml
@@ -32,6 +32,10 @@
jnilib
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
@@ -78,8 +82,14 @@
-std=c++0x
- -I${project.basedir}/../../../include
- ${cflags}
+ -I${MXNET_DIR}/include
+ -I${MXNET_DIR}/3rdparty/dmlc-core/include
+ -I${MXNET_DIR}/3rdparty/mshadow
+ -I${MXNET_DIR}/3rdparty/dlpack/include
+ -I${MXNET_DIR}/3rdparty/tvm/nnvm/include
+ -DMSHADOW_USE_MKL=0 -DMSHADOW_USE_CUDA=0
+ -g -O0 -fPIC -msse3 -mf16c
+ -Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
-shared
@@ -88,11 +98,9 @@
-framework JavaVM
-Wl,-exported_symbol,_Java_*
-Wl,-x
- ${lddeps}
- -force_load ${project.basedir}/../../../lib/libmxnet.a
- ${ldflags}
+ -lmxnet -L${MXNET_DIR}/lib
@@ -101,7 +109,6 @@
javah
generate-sources
- darwin
default
${project.build.directory}/custom-javah
${basedir}
@@ -116,6 +123,36 @@
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+ post-native-build
+ package
+
+ exec
+
+
+ install_name_tool
+ -change lib/libmxnet.so @loader_path/libmxnet.so ${project.build.directory}/${artifactId}.jnilib
+
+
+
+ link-native-lib
+ generate-resources
+
+ exec
+
+
+ ln
+ -sf ${MXNET_DIR}/lib/libmxnet.so ${project.build.directory}/libmxnet.so
+
+
+
+
diff --git a/scala-package/native/README.md b/scala-package/native/README.md
new file mode 100644
index 000000000000..cb6dd3890dd2
--- /dev/null
+++ b/scala-package/native/README.md
@@ -0,0 +1,63 @@
+# MXNet Scala JNI
+
+MXNet Scala JNI is a thin wrapper layer of underlying libmxnet.so.
+
+## javah
+JNI native code requires a header file that matches the java/scala interface,
+this file is usually generated with javah.
+
+In our case, jni_helper_func.h is generated and will be used to compile native code.
+
+
+## Linker options
+
+Scala JNI (libmxnet-scala.so/libmxnet-scala.jnilib) is dynamically linked to libmxnet.so.
+MXNet Scala will trying to load libmxnet.so from system LD_LIBRARY_PATH first.
+If it failed, the try to resolve libmxnet.so in the same location as libmxnet-scala.so file.
+
+### Linux
+```
+-Wl,-rpath=$ORIGIN -lmxnet
+```
+Above option will tell system to looking for libmxnet.so from the same location.
+
+
+### Mac OSX
+On Mac, we have to execute install_name_tool command to change library loading path:
+```bash
+install_name_tool -change lib/libmxnet.so @loader_path/libmxnet.so libmxnet-scala.jnilib
+```
+
+Other linker options:
+* -shared : link as shared library
+* -Wl,-install_name,libmxnet-scala.jnilib : avoid use build machine's absolute path
+* -framework JavaVM : Stand jni options for mac
+* -Wl,-exported_symbol,_Java_* : Stand jni options for mac
+* -Wl,-x : Do not put non-global symbols in the output file's symbol table.
+
+
+## Compiler flags
+
+Scala JNI code technically doesn't need on any of MXNet make flags,
+however c_api.h header links to many other dependencies header file,
+which requires us to add DMSHADOW_USE_MKL and DMSHADOW_USE_CUDA to compile the JNI code.
+These flags are not actually used by JNI and won't impact Scala's behavior.
+
+
+### Linux
+
+```
+-DMSHADOW_USE_MKL=0
+-DMSHADOW_USE_CUDA=0
+-O3 -DNDEBUG=1 -fPIC -msse3 -mf16c
+-Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
+```
+
+### Mac OSX
+
+```
+-DMSHADOW_USE_MKL=0
+-DMSHADOW_USE_CUDA=0
+-g -O0 -fPIC -msse3 -mf16c
+-Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
+```
diff --git a/scala-package/native/linux-x86_64-cpu/pom.xml b/scala-package/native/linux-x86_64-cpu/pom.xml
index 500e484cbb59..ce1e04e918a4 100644
--- a/scala-package/native/linux-x86_64-cpu/pom.xml
+++ b/scala-package/native/linux-x86_64-cpu/pom.xml
@@ -32,6 +32,10 @@
so
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
@@ -78,22 +82,20 @@
-std=c++0x
- -I${project.basedir}/../../../include
- ${all_includes}
- ${cflags}
+ -I${MXNET_DIR}/include
+ -I${MXNET_DIR}/3rdparty/dmlc-core/include
+ -I${MXNET_DIR}/3rdparty/mshadow
+ -I${MXNET_DIR}/3rdparty/dlpack/include
+ -I${MXNET_DIR}/3rdparty/tvm/nnvm/include
+ -DMSHADOW_USE_MKL=0 -DMSHADOW_USE_CUDA=0
+ -O3 -DNDEBUG=1 -fPIC -msse3 -mf16c
+ -Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
-shared
-
- ${all_ldpaths}
- -Wl,--whole-archive
- ${lddeps}
- -Wl,--no-whole-archive
-
- ${ldflags}
- -fopenmp
+ -Wl,-rpath=${dollar}ORIGIN -lmxnet -L${MXNET_DIR}/lib
@@ -102,7 +104,6 @@
javah
generate-sources
- linux
default
${project.build.directory}/custom-javah
${basedir}
diff --git a/scala-package/native/linux-x86_64-gpu/pom.xml b/scala-package/native/linux-x86_64-gpu/pom.xml
index da8b5f4a8183..052140d5e07d 100644
--- a/scala-package/native/linux-x86_64-gpu/pom.xml
+++ b/scala-package/native/linux-x86_64-gpu/pom.xml
@@ -32,6 +32,10 @@
so
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
@@ -78,22 +82,20 @@
-std=c++0x
- -I${project.basedir}/../../../include
- ${all_includes}
- ${cflags}
+ -I${MXNET_DIR}/include
+ -I${MXNET_DIR}/3rdparty/dmlc-core/include
+ -I${MXNET_DIR}/3rdparty/mshadow
+ -I${MXNET_DIR}/3rdparty/dlpack/include
+ -I${MXNET_DIR}/3rdparty/tvm/nnvm/include
+ -DMSHADOW_USE_MKL=0 -DMSHADOW_USE_CUDA=0
+ -O3 -DNDEBUG=1 -fPIC -msse3 -mf16c
+ -Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
-shared
-
- ${all_ldpaths}
- -Wl,--whole-archive
- ${lddeps}
- -Wl,--no-whole-archive
-
- ${ldflags}
- -fopenmp
+ -Wl,-rpath=${dollar}ORIGIN -lmxnet -L${MXNET_DIR}/lib
@@ -102,7 +104,6 @@
javah
generate-sources
- linux
default
${project.build.directory}/custom-javah
${basedir}
diff --git a/scala-package/native/osx-x86_64-cpu/pom.xml b/scala-package/native/osx-x86_64-cpu/pom.xml
index fc367ca9bfc5..ddc358425f76 100644
--- a/scala-package/native/osx-x86_64-cpu/pom.xml
+++ b/scala-package/native/osx-x86_64-cpu/pom.xml
@@ -32,6 +32,10 @@
jnilib
+
+ ${project.parent.parent.basedir}/..
+
+
org.apache.mxnet
@@ -78,8 +82,14 @@
-std=c++0x
- -I../../../include
- ${cflags}
+ -I${MXNET_DIR}/include
+ -I${MXNET_DIR}/3rdparty/dmlc-core/include
+ -I${MXNET_DIR}/3rdparty/mshadow
+ -I${MXNET_DIR}/3rdparty/dlpack/include
+ -I${MXNET_DIR}/3rdparty/tvm/nnvm/include
+ -DMSHADOW_USE_MKL=0 -DMSHADOW_USE_CUDA=0
+ -g -O0 -fPIC -msse3 -mf16c
+ -Wall -Wsign-compare -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-local-typedefs
-shared
@@ -88,12 +98,9 @@
-framework JavaVM
-Wl,-exported_symbol,_Java_*
-Wl,-x
- ${lddeps}
- -force_load ${project.basedir}/../../../lib/libmxnet.a
- -force_load ${project.basedir}/../../../3rdparty/tvm/nnvm/lib/libnnvm.a
- ${ldflags}
+ -Wl,-install_name,libmxnet-scala.jnilib -lmxnet -L${MXNET_DIR}/lib
@@ -102,7 +109,6 @@
javah
generate-sources
- darwin
default
${project.build.directory}/custom-javah
${basedir}
@@ -117,6 +123,36 @@
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+ post-native-build
+ package
+
+ exec
+
+
+ install_name_tool
+ -change lib/libmxnet.so @loader_path/libmxnet.so ${project.build.directory}/${artifactId}.jnilib
+
+
+
+ link-native-lib
+ generate-resources
+
+ exec
+
+
+ ln
+ -sf ${MXNET_DIR}/lib/libmxnet.so ${project.build.directory}/libmxnet.so
+
+
+
+
diff --git a/scala-package/pom.xml b/scala-package/pom.xml
index fe061e22e484..f0e86ec3d630 100644
--- a/scala-package/pom.xml
+++ b/scala-package/pom.xml
@@ -55,6 +55,8 @@
2.11.8
2.11
+ g++
+ $
pom