diff --git a/CHANGELOG.md b/CHANGELOG.md index f853dfe871a7d68c3e4bee9eb8c497bd693c07ec..37376b9713824dcbe9591babe8f014282c84b961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.4.3 +* Enforces Kernel and Device max work group size limitations and provides query functions for clGetKernelWorkGroupInfo(...) +* Support for armhf and aarch64 architectures for Linux OS +* Support for loading MingW compiled DLLs + ## 1.4.2 * Fixed Potential JVM crash when using multi-dimensional arrays (> 1D) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 938828ab7d9b0fadd6686f06eee76a55a356bf9b..3dddd0c7bc032ac37930130823e5a59b12bd977f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,4 +1,5 @@ # Contributors * Jeffrey Phillips Freeman <jeffrey.freeman@syncleus.com> -* Adam Heinrich <adam@adamh.cz> \ No newline at end of file +* Adam Heinrich <adam@adamh.cz> +* LuÃs Mendes <luis.p.mendes@gmail.com> \ No newline at end of file diff --git a/src/main/java/com/aparapi/natives/NativeLoader.java b/src/main/java/com/aparapi/natives/NativeLoader.java index 4f58b2c28a8cb83ac1dd7a4f7a302a3d3bb4cc76..b26918fa93f378b6e9b62fea85c5605a534c0831 100644 --- a/src/main/java/com/aparapi/natives/NativeLoader.java +++ b/src/main/java/com/aparapi/natives/NativeLoader.java @@ -23,6 +23,17 @@ public class NativeLoader { private static final String ARCH = System.getProperty("os.arch").toLowerCase(); private static final String OS = System.getProperty("os.name").toLowerCase(); + /** + * Ensure that libraries are loaded in proper order even if in presence of optimizing compilers. + * @param librariesAndJars a two dimensional array containing one more entries of a pair: jar package filename, target library name + * @throws IOException if libraries fail to load + */ + private static void loadLibrariesFromJarsInProperOrder(String[][] librariesAndJars) throws IOException { + for (String[] libraryAndJar : librariesAndJars) { + NativeUtils.loadLibraryFromJar(libraryAndJar[0], libraryAndJar[1]); + } + } + public static void load() throws IOException { // String arch = System.getenv("PROCESSOR_ARCHITECTURE"); // String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432"); @@ -31,19 +42,35 @@ public class NativeLoader { // || wow64Arch != null && wow64Arch.endsWith("64") // ? "64" : "32"; if( isUnix() ) { - if( is64Bit() ) - NativeUtils.loadLibraryFromJar("/linux/libaparapi_x86_64.so"); - else - NativeUtils.loadLibraryFromJar("/linux/libaparapi_x86.so"); - } - else if( isMac() && is64Bit() ) - NativeUtils.loadLibraryFromJar("/osx/libaparapi_x86_64.dylib"); - else if( isWindows() && is64Bit() ) - NativeUtils.loadLibraryFromJar("/win/libaparapi_x86_64.dll"); - else if( isWindows() && is32Bit() ) - NativeUtils.loadLibraryFromJar("/win/libaparapi_x86.dll"); - else - throw new IOException("System is not compatable with any of the known native libraries."); + if ( isArm() ) { + if ( is64Bit() ) + NativeUtils.loadLibraryFromJar("/linux/libaparapi_aarch64.so", "libaparapi.so"); + else + NativeUtils.loadLibraryFromJar("/linux/libaparapi_armhf.so", "libaparapi.so"); + } else { + if( is64Bit() ) + NativeUtils.loadLibraryFromJar("/linux/libaparapi_x86_64.so", "libaparapi.so"); + else + NativeUtils.loadLibraryFromJar("/linux/libaparapi_x86.so", "libaparapi.so"); + } + } else if( isMac() && is64Bit() ) { + NativeUtils.loadLibraryFromJar("/osx/libaparapi_x86_64.dylib", "libaparapi.dylib"); + } else if( isWindows() && is64Bit() ) { + String[][] librariesAndJars = new String[][] { + {"/win/libgcc_s_seh_x86_64.dll", "libgcc_s_seh-1.dll"}, + {"/win/libstdc++-6_x86_64.dll", "libstdc++-6.dll"}, + {"/win/libaparapi_x86_64.dll", "libaparapi.dll"} + }; + loadLibrariesFromJarsInProperOrder(librariesAndJars); + } else if( isWindows() && is32Bit() ) { + String[][] librariesAndJars = new String[][] { + {"/win/libgcc_s_sjlj_x86.dll", "libgcc_s_sjlj-1.dll"}, + {"/win/libstdc++-6_x86.dll", "libstdc++-6.dll"}, + {"/win/libaparapi_x86.dll", "libaparapi.dll"} + }; + loadLibrariesFromJarsInProperOrder(librariesAndJars); + } else + throw new IOException("System is not compatible with any of the known native libraries."); } private static boolean isWindows() { @@ -61,6 +88,13 @@ public class NativeLoader { private static boolean isSolaris() { return OS.contains("sunos"); } + + private static boolean isArm() { + if ( ARCH.startsWith("arm") || ARCH.startsWith("aarch64") ) { + return true; + } + return false; + } private static boolean is64Bit() { return ARCH.contains("64"); diff --git a/src/main/java/com/aparapi/natives/util/NativeUtils.java b/src/main/java/com/aparapi/natives/util/NativeUtils.java index 53934746beca8f54cc7d693ad3a383302106ddb2..0742e621a00eab30d7aaf7bc52e4ae99c04d64c0 100644 --- a/src/main/java/com/aparapi/natives/util/NativeUtils.java +++ b/src/main/java/com/aparapi/natives/util/NativeUtils.java @@ -16,10 +16,13 @@ package com.aparapi.natives.util; import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; /** * A simple library class which helps with loading dynamic libraries stored in the - * JAR archive. These libraries usualy contain implementation of some methods in + * JAR archive. These libraries usually contain implementation of some methods in * native code (using JNI - Java Native Interface). * */ @@ -34,7 +37,7 @@ public class NativeUtils { /** * 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. + * The file from JAR is copied into system temporary directory and then loaded. The temporary file and folder are deleted after exiting. * Method uses String as filename because the pathname is "abstract", not system-dependent. * * @param path The path of file inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext @@ -42,7 +45,7 @@ public class NativeUtils { * @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 { + public static void loadLibraryFromJar(String path, String libraryTargetFileName) throws IOException { if (!path.startsWith("/")) { throw new IllegalArgumentException("The path has to be absolute (start with '/')."); @@ -52,13 +55,11 @@ public class NativeUtils { String[] parts = path.split("/"); String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - // Split filename to prexif and suffix (extension) + // Split filename to prefix 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 @@ -66,12 +67,18 @@ public class NativeUtils { throw new IllegalArgumentException("The filename has to be at least 3 characters long."); } - // Prepare temporary file - File temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - - if (!temp.exists()) { - throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist."); + // Prepare temporary file in a temporary folder, to keep names consistent, or Windows will unexpectedly fail to load the DLLs + Path tempDir = Files.createTempDirectory("Aparapi", new FileAttribute<?>[] {}); + tempDir.toFile().deleteOnExit(); + if (!tempDir.toFile().exists()) { + throw new FileNotFoundException("Directory " + tempDir.toAbsolutePath() + " does not exist."); + } + + Path libraryFilePath = tempDir.resolve(libraryTargetFileName); + Path temp = Files.createFile(libraryFilePath, new FileAttribute<?>[] {}); + temp.toFile().deleteOnExit(); + if (!temp.toFile().exists()) { + throw new FileNotFoundException("File " + temp.toAbsolutePath() + " does not exist."); } // Prepare buffer for data copying @@ -85,7 +92,7 @@ public class NativeUtils { } // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = new FileOutputStream(temp); + OutputStream os = new FileOutputStream(temp.toFile()); try { while ((readBytes = is.read(buffer)) != -1) { os.write(buffer, 0, readBytes); @@ -95,8 +102,8 @@ public class NativeUtils { os.close(); is.close(); } - + // Finally, load the library - System.load(temp.getAbsolutePath()); + System.load(temp.toAbsolutePath().toString()); } } diff --git a/src/main/resources/linux/libaparapi_aarch64.so b/src/main/resources/linux/libaparapi_aarch64.so new file mode 100644 index 0000000000000000000000000000000000000000..e23072da8c346b90889c24ad38c23c8d1ea85d52 Binary files /dev/null and b/src/main/resources/linux/libaparapi_aarch64.so differ diff --git a/src/main/resources/linux/libaparapi_armhf.so b/src/main/resources/linux/libaparapi_armhf.so new file mode 100644 index 0000000000000000000000000000000000000000..403e9c861995e589cc377bcf2d0dc9e0f671dbd5 Binary files /dev/null and b/src/main/resources/linux/libaparapi_armhf.so differ diff --git a/src/main/resources/linux/libaparapi_x86.so b/src/main/resources/linux/libaparapi_x86.so old mode 100755 new mode 100644 index 3df7ef388686b07d19159862dadecbd10e0ea1fb..b372582e6733834d585fabdeb313f152e5862369 Binary files a/src/main/resources/linux/libaparapi_x86.so and b/src/main/resources/linux/libaparapi_x86.so differ diff --git a/src/main/resources/linux/libaparapi_x86_64.so b/src/main/resources/linux/libaparapi_x86_64.so old mode 100755 new mode 100644 index e3b0c7c0f74a6b4a92b008f2f7b85c35396c0dec..a45a2c158629b4f7722c4ef6e284c66b5b7e0914 Binary files a/src/main/resources/linux/libaparapi_x86_64.so and b/src/main/resources/linux/libaparapi_x86_64.so differ diff --git a/src/main/resources/win/libaparapi_x86.dll b/src/main/resources/win/libaparapi_x86.dll index 899016cdf31a02f600ec406540f5d38dfcdd5a57..cfe7bdd50a0f7275a5004a8fe497eeda44226b8d 100644 Binary files a/src/main/resources/win/libaparapi_x86.dll and b/src/main/resources/win/libaparapi_x86.dll differ diff --git a/src/main/resources/win/libaparapi_x86_64.dll b/src/main/resources/win/libaparapi_x86_64.dll index e539135338b597f4239ad4193b463281286593e9..ea65eac959cfa3b00cf21d835e68258478c0da1f 100644 Binary files a/src/main/resources/win/libaparapi_x86_64.dll and b/src/main/resources/win/libaparapi_x86_64.dll differ diff --git a/src/main/resources/win/libgcc_s_seh_x86_64.dll b/src/main/resources/win/libgcc_s_seh_x86_64.dll new file mode 100644 index 0000000000000000000000000000000000000000..66a92cf51768b781b04d9ca03109a4d05b5382ac Binary files /dev/null and b/src/main/resources/win/libgcc_s_seh_x86_64.dll differ diff --git a/src/main/resources/win/libgcc_s_sjlj_x86.dll b/src/main/resources/win/libgcc_s_sjlj_x86.dll new file mode 100644 index 0000000000000000000000000000000000000000..d90886795729ff7a2de9dce185bcda3a39450a9e Binary files /dev/null and b/src/main/resources/win/libgcc_s_sjlj_x86.dll differ diff --git a/src/main/resources/win/libstdc++-6_x86.dll b/src/main/resources/win/libstdc++-6_x86.dll new file mode 100644 index 0000000000000000000000000000000000000000..a7037e31546e3510a824e62b71d2bd06703ea18e Binary files /dev/null and b/src/main/resources/win/libstdc++-6_x86.dll differ diff --git a/src/main/resources/win/libstdc++-6_x86_64.dll b/src/main/resources/win/libstdc++-6_x86_64.dll new file mode 100644 index 0000000000000000000000000000000000000000..98fe098deb5018d4d8b52596a2b6e02d00d48fbe Binary files /dev/null and b/src/main/resources/win/libstdc++-6_x86_64.dll differ