-
-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OSGi native libraries take 3 #277
Comments
This is a bug and easily fixable. The current implementation indeed assumes that in order for
This cannot be fixed with In theory they could be built as JNI libraries, but this would defeat a very important feature of LWJGL: being able to replace those libraries with custom builds. You may want to do that for a few reasons: enable debugging or stricter validation (all LWJGL libraries are built for top performance), include a fix or feature not present in the LWJGL release, or simply because you don't trust the LWJGL binaries. There are two ways to resolve this:
I'm not sure how 2) could be implemented. Maybe the OSGi's |
Well, reflection works on Java 8, but not on Java 9 without Is there an OSGi API that can be used instead? |
I'm still giving it some consideration, but I suspect that 2 is impossible. The reason being is that OSGi doesn't seem to have any APIs at all related to native code; the native code is supposed to be configured entirely via static metadata with the only interface being the standard Java I think handling the JNI libraries via There is still the issue of actually accessing resources when there are multiple classloaders involved, but could this be as simple as just passing in a reference to the right classloader? For example, the code that loads |
…progress This lets the ClassLoader find the library if possible, useful for example with OSGi bundles.
Please try the next snapshot (3.1.2 build 14). The first issue should be fixed and I have added an option to enable
Could you explain this a bit more? Do you mean that different LWJGL bindings are loaded from different ClassLoaders? Currently LWJGL uses |
I'll give it a go today, thanks!
Let's assume that I create one bundle per LWJGL module. For example, I put lwjgl-jemalloc and all of its natives into one bundle, and then I put lwjgl and its natives into a separate bundle. Then, I've put together a small example of resource lookups across bundles here: https://github.com/io7m/osgi-resource-lookups-20170205 There's a class in the Going by the results obtained above, I think what needs to happen is for One alternative to this stuff is to pack literally every LWJGL module into one large bundle. But the reasons for not doing this are the same reasons that you don't currently pack all of the LWJGL modules into one large jar the way you used to. 😄 |
A bit of experimentation appears to show that the JNI libraries are loaded correctly in an OSGi context in the 3.1.2 snapshot. 👍 I'm currently investigating a failure to load non-JNI libraries via the new reflection path which I think may actually be a bug in the OSGi runtime I'm using, but from the results I posted in the example code above, I suspect that there's an issue in the LWJGL code too: Loading should fail because you're invoking the |
Nice! Any chance you could push a snapshot so that I can verify this? |
Sorry for the delay, the CI builds broke last night and it was too late to fix them. 3.1.2 build 15 is available now. |
Thanks! I'll be giving this a go tomorrow. Couldn't get to it today. From reading the changes, I'm optimistic that it'll work. |
Hi. Small issue discovered when testing the latest snapshot:
This is a bug in the |
Er, by "they", I mean the |
Hi! Well, there's still something not quite right: It seems like in the code path I end up taking via OSGi, there are no calls made to either The actual symptom I'm seeing is that everything appears to work correctly right up until the first call to
|
Yes,
Has |
I don't get any errors when loading
Are there any methods I can call that would provoke an error had it not been loaded correctly? |
I cannot reproduce this. Could you please try a simple non-OSGi test on your system to see if it triggers the same error? |
Oh, it works correctly outside of OSGi; that's never been an issue! Running the same code with the latest snapshot outside of OSGi works without issue. I'm still trying to work out exactly what assumption the OSGi environment changes that LWJGL apparently depends on. What I'm really looking for right now is a method that would raise some sort of error if and only if |
It appears to be a classloader issue. If I pack all of the LWJGL libraries and classes into a single bundle (so that they're all loaded via the same classloader), everything works correctly. This is less than ideal (and makes some of the work you did on LWJGL kind of pointless) but it's at least available as a last resort if I can't work out why LWJGL doesn't like multiple classloaders. |
The problem may be related to |
I'm not sure. I think I may need to enlist the help of someone who knows the OSGi internals a little better. I'll send a message to the |
Still not completely working due to LWJGL/lwjgl3#277, but this is certainly an improvement over the previous attempts.
You are missing this in your org.lwjgl repo's pom.xml: <repositories>
<repository>
<id>oss.sonatype.org</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories> People with a clean Maven local repository are otherwise not able to build your project. |
Good point, I had this configured as a local profile. I'll add it to the |
Could you please test if there's a difference with 3.1.2 build 16? |
I'll give it a shot today, thanks! |
No change, unfortunately, but I think your suspicion about I suspect that the only way to work around this is going to be by subverting package-private accessibility and calling the |
The code path that leads to There was a bug in the previous commit, which I fixed. But then I realized that any reflection-based solution does not work under Java 9 with the default JVM settings. I ended up using method references so that |
Still no luck with build 17, unfortunately.
This is actually the only code path that's taken when attempting to load I've tried to build the bindings myself to try out a few things, but unfortunately they don't compile at the moment:
I'm curious what will happen if the following change is made to
|
Oh, I see. No, this is not expected if you use OSGi bundles for all libraries. Not sure what is happening exactly, but I would recommend cleaning up your setup so that we can test each issue separately. Delete the snapshot folder and make sure the application is launched without
You need to regenerate the bindings. Running
This is effectively what was done in the previous commit. As I said, it should have worked in theory (if it didn't have the bug), but I want to avoid reflection on |
Agreed. To be clear, I'm running the program with:
I have to run a Maven task to repackage the published LWJGL jars into OSGi bundles each time, so I'll be sure to routinely nuke
Got it. Seemed like I needed an
Yes, definitely best to avoid this stuff if at all possible. |
Hah, making the change I described instead gave me:
I can't help but be amused by how awkward this problem is. |
Eliminating the second call to
This code is wrong, obviously: Assuming that the call was going to be made reflectively, then presumably there should be an attempt made to call |
Again, this right here makes no sense to me: Have you cleared that folder before testing the latest build?
The
Could you please verify the above? |
This assumption is incorrect. Thanks to the change you made a couple of commits back:
For |
To clarify: Yes, I'm deleting the temporary directory between each build/run. I think the main issues up to this point have been:
|
Build 18 is up. The call sites are a bit ridiculous now, if this works I'll try to figure out a cleaner implementation when I have more time. |
SUCCESS! 🎉 Nice work, thank you! This has certainly been one of the best responses I've had to a bug report in recent memory. It's very life-affirming when developers work to assist with use-cases that they themselves don't have. Right now, my plan is to maintain a set of OSGi bundles published to Maven Central under the |
Thanks to LWJGL/lwjgl3#277, the bundles are now fully working with the latest LWJGL snapshots.
Awesome! Thanks for the great feedback and for having the patience to go through this process. I have created the Lets use the new repository for further discussions. |
Filed a ticket for this, just for future reference: LWJGL/lwjgl3-osgi#4 |
Doing it now! |
It works correctly. I had to introduce a couple of small bundle metadata fixes for OSGi containers that are running on Java 9 VMs, but other than that, the bundles continue to work on both OpenJDK 8 and OpenJDK 9. |
Hello again!
It seems that I may have spoken too soon at the end of #216: What I had was actually working by accident due to a quirk of the OS I was using at the time.
Currently, LWJGL still can't be made to work on OSGi due to the way it looks up native libraries. I'll try to walk through what happens.
Firstly, I'm working from the assumption that I'll be repackaging the existing LWJGL jar files such that they become OSGi bundles, and therefore native libraries relative to each bundle will be embedded into each bundle. So, for example, the
libjemalloc.so
library will be inserted into anlwjgl-jemalloc
bundle. Because OSGi (in addition to languages like Ceylon, and systems such as JBoss modules) uses a "peer to peer" classloading model, each bundle is loaded in its own classloader. This means that code can't pick an essentially arbitrary classloader and try to load a library from that classloader as if it were a resource; the file will most likely not be accessible via that specific classloader.With that in mind, let's follow the execution path of
Library.loadSystem("lwjgl")
...The
isAbsolute
path won't be taken, because"lwjgl"
isn't absolute. Therefore...The returned
libName
will beliblwjgl.so
on this platform. Due to the peer-to-peer classloading described above,libURL
will benull
, so we jump to another overload ofloadSystem
...Now this is conditional based on the current configuration, but in an OSGi context, I would expect the property to be unset, therefore we return
false
here. As a result, we end up...Now, again, in an OSGi context, we'd expect
JAVA_LIBRARY_PATH
not to be set. This means that the call toSystem.loadLibrary
won't happen and an exception is raised. We can setJAVA_LIBRARY_PATH
to some nonsense value such as/nonexistent
, but this is pretty damn ugly and I've no idea if it would even work properly across platforms.The situation is slightly worse for libraries loaded via
loadNative
because although most of the above logic is the same, the method doesn't fall back toSystem.loadLibrary
and therefore the library will be loaded from the host's filesystem, even though we've bundled a guaranteed-compatible native library for libraries such asjemalloc
andglfw
!I think I'd like to restate my position that the cleanest way to deal with all of this is to provide a property that can be enabled that simply bypasses all of the above and uses
System.loadLibrary
directly. I appreciate that you've had support problems with this in the past as it's not really traceable, but it's currently required to work in systems like OSGi and languages like Ceylon and is reliable in the context of those systems (because they have standardized, well-understood ways of including native code).The text was updated successfully, but these errors were encountered: