2015-11-05 2 views
2

Я пытаюсь использовать Gradle с LWJGL 3, но у меня возникла проблема при создании. Файл build.gradle содержит следующее:java.lang.UnsatisfiedLinkError при использовании lwjgl с градиентом

apply plugin: 'application' 
mainClassName = "HelloWorld" 
repositories { 
    mavenCentral() 
    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } 
} 
project.ext.lwjglVersion = "3.0.0a" 
dependencies { 
    compile "org.lwjgl:lwjgl:${lwjglVersion}" 
    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-windows" 
    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-linux" 
    compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-osx" 
} 

Когда я бегу gradle run я получаю следующий вывод:

:compileJava UP-TO-DATE 
:processResources UP-TO-DATE 
:classes UP-TO-DATE 
:runjava.lang.UnsatisfiedLinkError: no lwjgl in java.library.path 
     at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) 
     at java.lang.Runtime.loadLibrary0(Runtime.java:870) 
     at java.lang.System.loadLibrary(System.java:1119) 
     at org.lwjgl.LWJGLUtil.loadLibrarySystem(LWJGLUtil.java:337) 
     at org.lwjgl.Sys$1.run(Sys.java:36) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at org.lwjgl.Sys.<clinit>(Sys.java:33) 
     at org.lwjgl.LWJGLUtil.initialize(LWJGLUtil.java:309) 
     at org.lwjgl.system.MemoryUtil.<clinit>(MemoryUtil.java:35) 
     at org.lwjgl.Pointer.<clinit>(Pointer.java:22) 
     at org.lwjgl.PointerBuffer.<init>(PointerBuffer.java:24) 
     at org.lwjgl.PointerBuffer.allocateDirect(PointerBuffer.java:281) 
     at org.lwjgl.BufferUtils.createPointerBuffer(BufferUtils.java:190) 
     at org.lwjgl.system.libffi.Closure.<clinit>(Closure.java:45) 
     at org.lwjgl.glfw.Callbacks.errorCallbackPrint(Callbacks.java:129) 
     at HelloWorld.<clinit>(HelloWorld.java:29) 
Exception in thread "main" FAILED 

FAILURE: Build failed with an exception. 

HelloWorld.java содержит следующее (пример кода из учебника):

import java.nio.ByteBuffer; 
import java.nio.IntBuffer; 
import org.lwjgl.BufferUtils; 
import org.lwjgl.glfw.Callbacks; 
import org.lwjgl.glfw.GLFWErrorCallback; 
import org.lwjgl.glfw.GLFWKeyCallback; 
import org.lwjgl.opengl.GLContext; 
import org.lwjgl.glfw.GLFWvidmode; 

import static org.lwjgl.glfw.GLFW.*; 
import static org.lwjgl.opengl.GL11.*; 
import static org.lwjgl.system.MemoryUtil.NULL; 

public class HelloWorld { 
    private static GLFWErrorCallback errorCallback 
      = Callbacks.errorCallbackPrint(System.err); 

    private static GLFWKeyCallback keyCallback = new GLFWKeyCallback() { 

     @Override 
     public void invoke(long window, int key, int scancode, int action, int mods) { 
      if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { 
       glfwSetWindowShouldClose(window, GL_TRUE); 
      } 
     } 
    }; 
    public static void main(String[] args) { 
     long window; 

     /* Set the error callback */ 
     glfwSetErrorCallback(errorCallback); 

     /* Initialize GLFW */ 
     if (glfwInit() != GL_TRUE) { 
      throw new IllegalStateException("Unable to initialize GLFW"); 
     } 

     /* Create window */ 
     window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL); 
     if (window == NULL) { 
      glfwTerminate(); 
      throw new RuntimeException("Failed to create the GLFW window"); 
     } 

     /* Center the window on screen */ 
     ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor()); 
     glfwSetWindowPos(window, 
       (GLFWvidmode.width(vidmode) - 640)/2, 
       (GLFWvidmode.height(vidmode) - 480)/2 
     ); 

     glfwMakeContextCurrent(window); 
     GLContext.createFromCurrent(); 
     glfwSwapInterval(1); 

     glfwSetKeyCallback(window, keyCallback); 
     IntBuffer width = BufferUtils.createIntBuffer(1); 
     IntBuffer height = BufferUtils.createIntBuffer(1); 
     while (glfwWindowShouldClose(window) != GL_TRUE) { 
      float ratio; 
      glfwGetFramebufferSize(window, width, height); 
      ratio = width.get()/(float) height.get(); 
      width.rewind(); 
      height.rewind(); 
      glViewport(0, 0, width.get(), height.get()); 
      glClear(GL_COLOR_BUFFER_BIT); 
      glMatrixMode(GL_PROJECTION); 
      glLoadIdentity(); 
      glOrtho(-ratio, ratio, -1f, 1f, 1f, -1f); 
      glMatrixMode(GL_MODELVIEW); 
      glLoadIdentity(); 
      glRotatef((float) glfwGetTime() * 50f, 0f, 0f, 1f); 
      glBegin(GL_TRIANGLES); 
      glColor3f(1f, 0f, 0f); 
      glVertex3f(-0.6f, -0.4f, 0f); 
      glColor3f(0f, 1f, 0f); 
      glVertex3f(0.6f, -0.4f, 0f); 
      glColor3f(0f, 0f, 1f); 
      glVertex3f(0f, 0.6f, 0f); 
      glEnd(); 
      glfwSwapBuffers(window); 
      glfwPollEvents(); 
      width.flip(); 
      height.flip(); 
     } 
     glfwDestroyWindow(window); 
     keyCallback.release(); 
     glfwTerminate(); 
     errorCallback.release(); 
    } 
} 

Что вызывает ошибку и как я могу ее исправить?

ответ

-1

От documentation:

Брошенный, если виртуальная машина Java не может найти подходящее определение на родном языке метода объявлен родным.

Так что, учитывая no lwjgl in java.library.path, по какой-то причине он не может найти родную библиотеку. Извините, нет опыта работы с градиентом, чтобы помочь вам там ...

0

Как вы, наверное, уже заметили, в папке lwjgl, которую вы загрузили (тот, у которого есть файл jar), должна быть директория с именем «native». В этом каталоге должно быть три подпапки с системными именами (windows, macos ...). Эта собственная папка должна находиться в папке внутри вашего проекта (я создал один из них с именем lwjgl). Затем в первой строке вашей программы вы пишете System.setProperty("java.library.path", "./lwjgl"). Эта строка сообщает java, чтобы искать там все собственные файлы.

+1

Это не сработает, вы должны указать имя свойства, которое вы хотите установить: 'System.setProperty (" java.library.path "," ./lwjgl/native/")'. – javac

+1

Я не загружал папку LWJGL. Я использую Gradle. –

1

Вы должны связать собственные библиотеки Lwjgl с вашим приложением во время выполнения. Благодаря градиенту, родные библиотеки находятся в пути к классам ... где-то.

Вы можете пойти и найти их, извлечь их во временное место, а затем связать их, но уже есть example project, делая это за вас.

Все, что вам нужно сделать, это включить в проект свой класс SharedLibraryLoader и вызвать метод load().

В случае этой связи умирающих, вот полное содержание класса вам нужно:

/******************************************************************************* 
* Copyright 2011 See AUTHORS file. 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
******************************************************************************/ 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.lang.reflect.Method; 
import java.util.HashSet; 
import java.util.UUID; 
import java.util.zip.CRC32; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipFile; 

/** Loads shared libraries from JAR files. Call {@link SharedLibraryLoader#load() to load the 
* required LWJGL 3 native shared libraries. 
* @author mzechner 
* @author Nathan Sweet */ 
public class SharedLibraryLoader { 
    static public boolean isWindows = System.getProperty("os.name").contains("Windows"); 
    static public boolean isLinux = System.getProperty("os.name").contains("Linux"); 
    static public boolean isMac = System.getProperty("os.name").contains("Mac"); 
    static public boolean isIos = false; 
    static public boolean isAndroid = false; 
    static public boolean isARM = System.getProperty("os.arch").startsWith("arm"); 
    static public boolean is64Bit = System.getProperty("os.arch").equals("amd64") 
     || System.getProperty("os.arch").equals("x86_64"); 

    // JDK 8 only. 
    static public String abi = (System.getProperty("sun.arch.abi") != null ? System.getProperty("sun.arch.abi") : ""); 

    static { 
     String vm = System.getProperty("java.runtime.name"); 
     if (vm != null && vm.contains("Android Runtime")) { 
      isAndroid = true; 
      isWindows = false; 
      isLinux = false; 
      isMac = false; 
      is64Bit = false; 
     } 
     if (!isAndroid && !isWindows && !isLinux && !isMac) { 
      isIos = true; 
      is64Bit = false; 
     } 
    } 

    static boolean load = true; 

    static { 
     // Don't extract natives if using JWS. 
     try { 
      Method method = Class.forName("javax.jnlp.ServiceManager").getDeclaredMethod("lookup", new Class[] {String.class}); 
      method.invoke(null, "javax.jnlp.PersistenceService"); 
      load = false; 
     } catch (Throwable ex) { 
      load = true; 
     } 
    } 

    /** Extracts the LWJGL native libraries from the classpath and sets the "org.lwjgl.librarypath" system property. */ 
    static public synchronized void load() { 
     load(false); 
    } 

    /** Extracts the LWJGL native libraries from the classpath and sets the "org.lwjgl.librarypath" system property. */ 
    static public synchronized void load (boolean disableOpenAL) {  
     if (!load) return; 

     SharedLibraryLoader loader = new SharedLibraryLoader(); 
     File nativesDir = null; 
     try { 
      if (SharedLibraryLoader.isWindows) { 
       nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "lwjgl.dll" : "lwjgl32.dll", null).getParentFile(); 
       if (!disableOpenAL) 
        loader.extractFile(SharedLibraryLoader.is64Bit ? "OpenAL.dll" : "OpenAL32.dll", nativesDir.getName()); 
      } else if (SharedLibraryLoader.isMac) { 
       nativesDir = loader.extractFile("liblwjgl.dylib", null).getParentFile(); 
       if (!disableOpenAL) loader.extractFile("libopenal.dylib", nativesDir.getName()); 
      } else if (SharedLibraryLoader.isLinux) { 
       nativesDir = loader.extractFile(SharedLibraryLoader.is64Bit ? "liblwjgl.so" : "liblwjgl32.so", null).getParentFile(); 
       if (!disableOpenAL) 
        loader.extractFile(SharedLibraryLoader.is64Bit ? "libopenal.so" : "libopenal32.so", nativesDir.getName()); 
      } 
     } catch (Throwable ex) { 
      throw new RuntimeException("Unable to extract LWJGL natives.", ex); 
     } 
     System.setProperty("org.lwjgl.librarypath", nativesDir.getAbsolutePath()); 
     load = false; 
    } 

    static private final HashSet<String> loadedLibraries = new HashSet<String>(); 

    private String nativesJar; 

    public SharedLibraryLoader() { 
    } 

    /** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly. 
    * @param nativesJar */ 
    public SharedLibraryLoader (String nativesJar) { 
     this.nativesJar = nativesJar; 
    } 

    /** Returns a CRC of the remaining bytes in the stream. */ 
    public String crc (InputStream input) { 
     if (input == null) throw new IllegalArgumentException("input cannot be null."); 
     CRC32 crc = new CRC32(); 
     byte[] buffer = new byte[4096]; 
     try { 
      while (true) { 
       int length = input.read(buffer); 
       if (length == -1) break; 
       crc.update(buffer, 0, length); 
      } 
     } catch (Exception ex) { 
      if(input != null) { 
       try { 
        input.close(); 
       } catch (IOException e) { 
       } 
      } 
     } 
     return Long.toString(crc.getValue(), 16); 
    } 

    /** Maps a platform independent library name to a platform dependent name. */ 
    public String mapLibraryName (String libraryName) { 
     if (isWindows) return libraryName + (is64Bit ? "64.dll" : ".dll"); 
     if (isLinux) return "lib" + libraryName + (isARM ? "arm" + abi : "") + (is64Bit ? "64.so" : ".so"); 
     if (isMac) return "lib" + libraryName + (is64Bit ? "64.dylib" : ".dylib"); 
     return libraryName; 
    } 

    /** Loads a shared library for the platform the application is running on. 
    * @param libraryName The platform independent library name. If not contain a prefix (eg lib) or suffix (eg .dll). */ 
    public synchronized void load (String libraryName) { 
     // in case of iOS, things have been linked statically to the executable, bail out. 
     if (isIos) return; 

     libraryName = mapLibraryName(libraryName); 
     if (loadedLibraries.contains(libraryName)) return; 

     try { 
      if (isAndroid) 
       System.loadLibrary(libraryName); 
      else 
       loadFile(libraryName); 
     } catch (Throwable ex) { 
      throw new RuntimeException("Couldn't load shared library '" + libraryName + "' for target: " 
       + System.getProperty("os.name") + (is64Bit ? ", 64-bit" : ", 32-bit"), ex); 
     } 
     loadedLibraries.add(libraryName); 
    } 

    private InputStream readFile (String path) { 
     if (nativesJar == null) { 
      InputStream input = SharedLibraryLoader.class.getResourceAsStream("/" + path); 
      if (input == null) throw new RuntimeException("Unable to read file for extraction: " + path); 
      return input; 
     } 

     // Read from JAR. 
     ZipFile file = null; 
     try { 
      file = new ZipFile(nativesJar); 
      ZipEntry entry = file.getEntry(path); 
      if (entry == null) throw new RuntimeException("Couldn't find '" + path + "' in JAR: " + nativesJar); 
      return file.getInputStream(entry); 
     } catch (IOException ex) { 
      throw new RuntimeException("Error reading '" + path + "' in JAR: " + nativesJar, ex); 
     } finally { 
      if(file != null) { 
       try { 
        file.close(); 
       } catch (IOException e) { 
       } 
      } 
     } 
    } 

    /** Extracts the specified file into the temp directory if it does not already exist or the CRC does not match. If file 
    * extraction fails and the file exists at java.library.path, that file is returned. 
    * @param sourcePath The file to extract from the classpath or JAR. 
    * @param dirName The name of the subdirectory where the file will be extracted. If null, the file's CRC will be used. 
    * @return The extracted file. */ 
    public File extractFile (String sourcePath, String dirName) throws IOException { 
     try { 
      String sourceCrc = crc(readFile(sourcePath)); 
      if (dirName == null) dirName = sourceCrc; 

      File extractedFile = getExtractedFile(dirName, new File(sourcePath).getName()); 
      return extractFile(sourcePath, sourceCrc, extractedFile); 
     } catch (RuntimeException ex) { 
      // Fallback to file at java.library.path location, eg for applets. 
      File file = new File(System.getProperty("java.library.path"), sourcePath); 
      if (file.exists()) return file; 
      throw ex; 
     } 
    } 

    /** Returns a path to a file that can be written. Tries multiple locations and verifies writing succeeds. */ 
    private File getExtractedFile (String dirName, String fileName) { 
     // Temp directory with username in path. 
     File idealFile = new File(System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" 
      + dirName, fileName); 
     if (canWrite(idealFile)) return idealFile; 

     // System provided temp directory. 
     try { 
      File file = File.createTempFile(dirName, null); 
      if (file.delete()) { 
       file = new File(file, fileName); 
       if (canWrite(file)) return file; 
      } 
     } catch (IOException ignored) { 
     } 

     // User home. 
     File file = new File(System.getProperty("user.home") + "/.libgdx/" + dirName, fileName); 
     if (canWrite(file)) return file; 

     // Relative directory. 
     file = new File(".temp/" + dirName, fileName); 
     if (canWrite(file)) return file; 

     return idealFile; // Will likely fail, but we did our best. 
    } 

    /** Returns true if the parent directories of the file can be created and the file can be written. */ 
    private boolean canWrite (File file) { 
     File parent = file.getParentFile(); 
     File testFile; 
     if (file.exists()) { 
      if (!file.canWrite() || !canExecute(file)) return false; 
      // Don't overwrite existing file just to check if we can write to directory. 
      testFile = new File(parent, UUID.randomUUID().toString()); 
     } else { 
      parent.mkdirs(); 
      if (!parent.isDirectory()) return false; 
      testFile = file; 
     } 
     try { 
      new FileOutputStream(testFile).close(); 
      if (!canExecute(testFile)) return false; 
      return true; 
     } catch (Throwable ex) { 
      return false; 
     } finally { 
      testFile.delete(); 
     } 
    } 

    private boolean canExecute (File file) { 
     try { 
      Method canExecute = File.class.getMethod("canExecute"); 
      if ((Boolean)canExecute.invoke(file)) return true; 

      Method setExecutable = File.class.getMethod("setExecutable", boolean.class, boolean.class); 
      setExecutable.invoke(file, true, false); 

      return (Boolean)canExecute.invoke(file); 
     } catch (Exception ignored) { 
     } 
     return false; 
    } 

    private File extractFile (String sourcePath, String sourceCrc, File extractedFile) throws IOException { 
     String extractedCrc = null; 
     if (extractedFile.exists()) { 
      try { 
       extractedCrc = crc(new FileInputStream(extractedFile)); 
      } catch (FileNotFoundException ignored) { 
      } 
     } 

     // If file doesn't exist or the CRC doesn't match, extract it to the temp dir. 
     if (extractedCrc == null || !extractedCrc.equals(sourceCrc)) { 
      try { 
       InputStream input = readFile(sourcePath); 
       extractedFile.getParentFile().mkdirs(); 
       FileOutputStream output = new FileOutputStream(extractedFile); 
       byte[] buffer = new byte[4096]; 
       while (true) { 
        int length = input.read(buffer); 
        if (length == -1) break; 
        output.write(buffer, 0, length); 
       } 
       input.close(); 
       output.close(); 
      } catch (IOException ex) { 
       throw new RuntimeException("Error extracting file: " + sourcePath + "\nTo: " + extractedFile.getAbsolutePath(), ex); 
      } 
     } 

     return extractedFile; 
    } 

    /** Extracts the source file and calls System.load. Attemps to extract and load from multiple locations. Throws runtime 
    * exception if all fail. */ 
    private void loadFile (String sourcePath) { 
     String sourceCrc = crc(readFile(sourcePath)); 

     String fileName = new File(sourcePath).getName(); 

     // Temp directory with username in path. 
     File file = new File(System.getProperty("java.io.tmpdir") + "/libgdx" + System.getProperty("user.name") + "/" + sourceCrc, 
      fileName); 
     Throwable ex = loadFile(sourcePath, sourceCrc, file); 
     if (ex == null) return; 

     // System provided temp directory. 
     try { 
      file = File.createTempFile(sourceCrc, null); 
      if (file.delete() && loadFile(sourcePath, sourceCrc, file) == null) return; 
     } catch (Throwable ignored) { 
     } 

     // User home. 
     file = new File(System.getProperty("user.home") + "/.libgdx/" + sourceCrc, fileName); 
     if (loadFile(sourcePath, sourceCrc, file) == null) return; 

     // Relative directory. 
     file = new File(".temp/" + sourceCrc, fileName); 
     if (loadFile(sourcePath, sourceCrc, file) == null) return; 

     // Fallback to java.library.path location, eg for applets. 
     file = new File(System.getProperty("java.library.path"), sourcePath); 
     if (file.exists()) { 
      System.load(file.getAbsolutePath()); 
      return; 
     } 

     throw new RuntimeException(ex); 
    } 

    /** @return null if the file was extracted and loaded. */ 
    private Throwable loadFile (String sourcePath, String sourceCrc, File extractedFile) { 
     try { 
      System.load(extractFile(sourcePath, sourceCrc, extractedFile).getAbsolutePath()); 
      return null; 
     } catch (Throwable ex) { 
      ex.printStackTrace(); 
      return ex; 
     } 
    } 
} 

Этот пример проект работает с LWJGL 3 (по запросу OP). Однако, если вы используете Lwjgl 2.9.x, он по-прежнему работает, вам просто нужно изменить имя библиотек в методе load.

Смежные вопросы