8

Is there a way to configure OpenJFX 11 to extract their DLLs into a different user-specified directory?

While trying to migrate an existing Java 10/Maven project to Java 11, I tried using OpenJDK 11. To get the code build working, I needed to add the JavaFX JARs into the Maven pom.xml configuration files (because JavaFX is no longer a built-in part of Java 11).

However, at runtime I discovered errors due to OpenJFX extracting DLL files into a user directory and then having access failures (see errors, below). I've had many projects over the years that had errors when working with the C:\Users* directories (from Microsoft Windows interfering with file locks and directory permissions, anti-virus scans, etc), so I try to avoid those directories whenever possible. The Java project works properly under Java 10 on Windows 7 and on RedHat 7, which seems to imply that the Oracle's JavaFX 10 JARs are not extracting DLLs into the C:\Users* directories. OpenJFX seems to have no troubles writing the DLLs into those directories, but it cannot read those same files afterwards.

I am running on Microsoft Windows 7 Professional 64-bit with service-pack 1. I haven't tried running on Linux yet with OpenJDK 11 and OpenJFX, but I would imagine OpenJFX would try to extract its DLLs on that platform as well.

Example runtime Java errors caused by OpenJFX:

Loading library prism_d3d from resource failed: java.lang.UnsatisfiedLinkError: C:\Users\MyUserName\.openjfx\cache\11\prism_d3d.dll: Access is denied

java.lang.UnsatisfiedLinkError: C:\Users\MyUserName\.openjfx\cache\11\prism_d3d.dll: Access is denied

Loading library prism_sw from resource failed: java.lang.UnsatisfiedLinkError: C:\Users\MyUserName\.openjfx\cache\11\prism_sw.dll: Access is denied

java.lang.UnsatisfiedLinkError: C:\Users\MyUserName\.openjfx\cache\11\prism_sw.dll: Access is denied

Graphics Device initialization failed for : d3d, sw

Error initializing QuantumRenderer: no suitable pipeline found

java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
navySV
  • 223
  • 4
  • 12
  • 3
    You can find [here](https://github.com/javafxports/openjdk-jfx/blob/a42b5841674ab7cd2704e0ea5fbcc94934d91c83/modules/javafx.graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java#L43) the native lib loader class. There are four different ways to load the native libraries, being the one that uses cache into the user's folder the last one. Maybe you can try (manually) setting the native libraries to a different folder and use `-Djava.library.path`? Also you can enable `javafx.verbose` to true. – José Pereda Nov 19 '18 at 23:18
  • I appreciate your suggestions so far, but no success yet. I've added -Djavafx.verbose=true into my runtime java command, and I see a huge list of Microsoft Windows kernel DLLs not being found but then the system announced they were successfully loaded. Here is one example: WARNING: java.lang.UnsatisfiedLinkError: Can't load library: D:\code\MyProjectDir\bin\api-ms-win-core-console-l1-1-0.dll System.loadLibrary(api-ms-win-core-console-l1-1-0) succeeded – navySV Nov 20 '18 at 21:35
  • I studied the weblink you provided. The NativeLibLoader.java class appears to be trying to locate the DLLs based on the JAR file's location (and some of the code comments mention things like "// Location of native libraries relative to jar file"). However, the runtime behavior doesn't seem to agree with that, because OpenJFX is extracting the DLLs from the JARs into C:\Users\MyUserName\.openjfx\cache\11\, and there are no prism*.JAR files anywhere within C:\Users\MyUserName\. – navySV Nov 20 '18 at 21:36
  • It must be using some other behavior to decide where to extract the DLLs into, because they are in a completely different location than the JARs they came out of. – navySV Nov 20 '18 at 21:36
  • I already have -Djava.library.path=libs (which is a local directory containing project JARs) but OpenJFX is not using that parameter for its DLL extraction. I would love to be able to "(manually) setting the native libraries to a different folder" but I have no idea how to get OpenJFX to do that. – navySV Nov 20 '18 at 21:36
  • What I meant with that is that as quick test you could copy the dlls that you have in `.openjfx\cache\11` to the `lib` folder you have created, and then use something like `-Djava.library.path=lib`, so those required dll libraries are found by the loader before it needs to use the cache. And since all the dlls are packed into the JavaFX SDK `bin` folder, you can [download the sdk](https://gluonhq.com/products/javafx/), unzip it and set `-Djava.library.path=\path\to\javafx-sdk-11.0.1\bin`, and try again. – José Pereda Nov 20 '18 at 21:43
  • Good test! After downloading-and-unzipping javafx-sdk-11.0.1 and then using -Djava.library.path to include both that OpenJFX location and my local libs directory, the application now runs. I am still receiving lots of runtime warnings about UnsatisfiedLinkErrors for the api-ms-win*.dll files (each followed by a message stating it did load the file), but this time it is complaining about the OpenJFX location (and not C:\Users\*). – navySV Nov 21 '18 at 14:07
  • Unless you have other ideas, this means we cannot reply on Maven to auto-downloaded the OpenJFX JARs without needing to manually extract the DLLs (and modify the -Djava.library.path) for our app. – navySV Nov 21 '18 at 14:07
  • No, the test proves that you can modify the libraries path at your convenience. Maven resolves the JavaFX artifacts to the `.m2` repository, so you can maybe point to that direction. Anyway, you might want to file an issue [here](https://github.com/javafxports/openjdk-jfx/issues), in order to allow a different cache location not based in `user.home` but `java.io.tmpdir` or alike. – José Pereda Nov 21 '18 at 14:15
  • FYI, an issue has been already [filed](https://github.com/javafxports/openjdk-jfx/issues/295). – José Pereda Nov 21 '18 at 20:54
  • When my app allows OpenJFX to extract its DLLs, the app fails, as it cannot open the DLL files no matter which directory they are extracted into. Maybe OpenJFX cannot open them due to a file lock? If I copy the DLLs into a local directory and run the app with -Djava.library.path (i.e. ignore the extracted DLLs and just use my own copy of them), the app works. However, -Djavafx.verbose=true shows many DLL loading failures with both approaches; oddly, each one complains that it cannot open the DLL, and then the next message says it has loaded the same DLL file. – navySV Nov 26 '18 at 21:19
  • In short, I have a work-around by manually extracting the DLL files (or copying the DLLs from an OpenJFX installation) and having my launch scripts point to the DLL location. In other words, our app cannot rely upon OpenJFX to extract its DLLs. – navySV Nov 26 '18 at 21:19
  • Is it possible that you could add a full stacktrace to the [issue](https://github.com/javafxports/openjdk-jfx/issues/295)? A fix is already on its way, but it is still necessary to find out about the errors you get when the libraries are added but you don't have read permissions. Thank you. – José Pereda Nov 27 '18 at 20:39
  • Sure... How can I attach a text file to a StackOverflow comment? The comment is limited to @600 characters and certainly won't fit a stack trace. I also have a working NetBeans9/OpenJDK11/OpenJFX11 project which exhibits the behavior, but I don't know how to post it here. – navySV Nov 28 '18 at 21:20
  • I meant if you could add it to the OpenJFX issue tracker https://github.com/javafxports/openjdk-jfx/issues/295. Thanks, – José Pereda Nov 28 '18 at 21:21
  • I am not able to create a GiHub account (to add the stacktrace to the issue you mentioned). GitHub's create-personal-account never gets past the verify-account (it cycles endlessly), perhaps due to our security firewall settings. – navySV Nov 30 '18 at 13:54
  • Ok, no problem. There has been a [release](https://gluonhq.com/products/javafx/#ea) today of JavaFX 12-ea+3, maybe you can give it a try? Now there is a system property you can use to modify the cache dir: `javafx.cacheDir`. – José Pereda Nov 30 '18 at 14:06
  • My project still has the same errors unless I use -Djava.library.path=lib to point to a location with the DLLs. I used the JavaFX 12-ea+3 JARs and DLLs. The DLL-extraction-from-JAR is still failing to read the DLL files. – navySV Dec 04 '18 at 17:19
  • How should the new javafx.cacheDir parameter be used? Does this point to the directory containing the DLL files? Or is this meant to point to a temp directory (for extracting the DLLs from the JARs)? Or something else? – navySV Dec 04 '18 at 17:20
  • Yes, the error will be the same unless you use the new flag. You can do it from command line, like `-Djavafx.cacheDir="D:\Path\to\your\temp\unrestricted\folder"`, or you can set it as System property on your code. – José Pereda Dec 04 '18 at 23:33
  • I tried running my app but got the same errors. I pointed the new cacheDir parameter to the location where my DLL files are located... is that correct? I also tried pointing it to an empty "tmp" directory and also got the same errors. java --module-path %MODPATH% --add-modules=%MODULES% -Djavafx.verbose=true -Djavafx.cacheDir="lib/bin" -classpath %CLASSPATH% %MAINCLASS% – navySV Dec 06 '18 at 18:46
  • The cache dir should be a valid existing path, like "C:\temp\", and there the dlls will be extracted, so don't use the SDK one. – José Pereda Dec 06 '18 at 18:49
  • Yes, I had done that (my second test had used -Djavafx.cacheDir="tmp" to point to an existing directory but it also caused the runtime errors). No DLL files were extracted into that directory. – navySV Dec 07 '18 at 20:07
  • That is not a valid directory. Use a full path, like "C:\tmp". – José Pereda Dec 07 '18 at 20:08
  • So you're saying that the -Djavafx.cacheDir does not work with relative pathnames? I had created a "tmp" empty directory in the same place that I ran the java command from, so it should have no trouble locating this directory. – navySV Dec 10 '18 at 17:14
  • Did you try the full path? You can check the fix that was [made](https://github.com/javafxports/openjdk-jfx/pull/300/files#diff-f07eeb0dbf846940455dbe51122ffba0R225): You need an absolute path, otherwise `new File(userCache)` will fail. – José Pereda Dec 10 '18 at 17:41
  • Sorry, but with the absolute path, the command still fails: java --module-path lib --add-modules=javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.swing,javafx.web,javafx.swt -Djavafx.verbose=true -Djavafx.cacheDir="D:\code\MyProject\OpenJFX11_DLL_Extraction_TestB\dist\tmp" -classpath OpenJFX11_DLL_Extraction_TestA.jar openJFX11_DLL_Extraction_Test1.OpenJFX11_DLL_Extraction_TestA – navySV Dec 12 '18 at 15:21
  • The main error from the command: Graphics Device initialization failed for : d3d, sw Error initializing QuantumRenderer: no suitable pipeline found java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found – navySV Dec 12 '18 at 15:22
  • What is `lib` in module path? If it is a custom lib with just the JavaFX jars, you are missing the dlls. You need to point to the JavaFX SDK/lib folder. – José Pereda Dec 12 '18 at 15:26
  • "lib" contains the OpenJFX 11 JARs, and the "lib/bin" subdirectory with all of the DLL files. For this test app, there are no other dependent JARs or DLLs for the project. The app runs only when I add -Djava.library.path=lib/bin to the java command, but that requires the app to have already-extracted DLL files in a known location. – navySV Dec 13 '18 at 18:17
  • You can't do that. The current `SDK/lib` and `SDK/bin` folders can not be rearranged into `SDK/lib` and `SDK/lib/bin`, or any other change you want, that won't ever work. Stick to the `--module-path /FullPath/To/SDK/lib`. – José Pereda Dec 13 '18 at 19:52
  • Please help me understand. Our projects will not be pointing to an OpenJFX directory at runtime because the users will not have that. At best, I can copy the OpenJFX JARs and DLLs into project folders to be used during a project build and runtime execution. Why can't the JARs be in "lib" and the DLLs be in "lib/bin"? The DLLs are only being located with the -Djava.library.path parameter (when I choose to use it), and the OpenJFX JARs are trying to extract the DLLs into some other directory so there should not be any conflict. – navySV Dec 14 '18 at 20:32
  • As an experiment, I copied the "lib/bin" directory into a new "bin" directory. The java command without the -Djava.library.path parameter is not working. How can OpenJFX possibly locate the DLLs without this parameter? Is it using a hard-coded default path to the DLLs? I can also use the -Djava.library.path parameter to override this (and point to "lib/bin") and this also works. – navySV Dec 14 '18 at 20:38

1 Answers1

3

Summary of the previous discussion and the linked resources

Since OpenJFX 12 you can use the system property javafx.cachedir to tell OpenJFX where to extract it's native libraries. Take care not to use camel-case notion in the 'cacheDir' part of the system property (like used in previous comments and in the pull-request comments).

See this Pull-Request for the details.

In versions prior 12, OpenJFX will extract it's native libraries to a fixed path based on user.home (System.getProperty("user.home") + "/.openjfx/cache/" + jfxVersion).

There are two ways to modify the path OpenJFX will use as cache location

  1. Provide the native libraries by yourself and store it in a custom location. Then use the java.library.path system property to tell OpenJFX to load it from your custom location (this will avoid the extraction into the fixed cache location).
  2. Modify user.home to modify the cache location.

See this Code for details.

lgraf
  • 596
  • 7
  • 13