You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@felix.apache.org by duncan <du...@gmail.com> on 2011/04/28 20:08:43 UTC

Bundle-NativeCode question.

We are accessing native libraries from Java. This works outside of
OSGi and in OSGi on Windows but not on Linux probably because the dll
and so linking behave differently.

I have tried the following experiments:

1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
top level JNI library. The dependent libraries are all linked
implicitly and the unit tests run.

2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
reverse dependency order. The libraries link but the tests fail at run
time with inscrutable errors from the C code.

3) add all libraries to Bundle-NativeCode entry . Explicitly load only
the JNI library. Fails to link with the other libraries.  [This would
have been my preferred approach]

4) add all libraries to Bundle-NativeCode entry and explicitly load
them all in reverse dependency order. The libraries link but the tests
fail at run time with inscrutable errors from the C code.

5) tried all of the above with Felix and Equinox.

So it appears that OSGi requires that I explicitly use
System.loadLibrary for all the libraries. However, the C libraries
that I am trying to use are not able to withstand this on Linux (but
they do on Windows). These are native libraries from a major vendor
and there is little chance of them patching them for me.

If the libraries can be loaded from LD_LIBRARY_PATH then you would
think that OSGi should also work. But OSGi appears to require that I
explicitly load all libraries myself which resolves the dependencies
in a subtly different way to how the LD_LIBRARY_PATH approach behaves.

So possible outcomes are:

1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
should reasonably be expected to load them as well.
2) OSGi works like this for a reason and native libraries need to be
redesigned so they can withstand being loaded explicitly.

I am considering writing a bundle that iterates through all the
resolved bundles (at start up) and copy their .so files into a common
location that I will put on the java.library.path. I believe this
would work but feels like a hack.

Any comments or suggestions would be most appreciated.

Cheers,

Duncan

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Karl Pauls <ka...@gmail.com>.
I guess that in your case the only thing you can do is to extract the
libraries yourself i.e., on Bundle start-up you would extract all
libraries via BundleContext.getEntry() into a tmp dir that you create
via BundleContext.getDataFile() and then load your top-level dll via a
System.load() call directly.

That should work alas, it doesn't get you any help from OSGi.

regards,

Karl

On Fri, Apr 29, 2011 at 12:21 AM, duncan <du...@gmail.com> wrote:
> Hi Richard,
>
> Thanks for the reply. When you said ....
>
>> Yes, to ensure your native library dependencies are met in OSGi, it is best
>> to explicitly load them in the proper order.
>
> I think the crux of the problem is that for these particular libraries
> there is no linear order that works.
>
> You can throw them all on the LD_LIBRARY_PATH and the OS manages to
> figure it out but you can't load them in a sequence.
>
> Unfortunately these native libraries are from a database vendor so I
> can't have them change them.
>
> Regards,
>
> Duncan
>
>
>
> On Thu, Apr 28, 2011 at 3:07 PM, Richard S. Hall <he...@ungoverned.org> wrote:
>> On 4/28/11 16:56, duncan wrote:
>>>
>>> Hi Angelo,
>>>
>>> Thanks for your response. I understand what you wrote but I think I am
>>> at the point where I have convinced myself that using
>>> System.loadLibrary() within OSGi can be subtly different to using it
>>> outside. The behavior might be equivalent if you have a single library
>>> but in my situation we have multiple dependent libraries.
>>>
>>> Outside of OSGi you just call System.loadLibrary() on the topmost one
>>> and leave it to the OS to resolve the dependencies (from
>>> LD_LIBRARY_PATH). To find libraries in bundles in OSGi you apparently
>>> have to call System.loadLibrary() for each of your libraries.
>>
>> Yes, to ensure your native library dependencies are met in OSGi, it is best
>> to explicitly load them in the proper order.
>>
>>> On Windows this amounts to the same thing. But on Linux the results
>>> can be different. So you can have a suite of dependent libraries that
>>> will link and run fine if you get them from LD_LIBRARY_PATH. But if
>>> you try and load each one separately from bundle(s) there are
>>> situations where they either won't resolve or will fail at run time.
>>
>> I'm not sure why this would be problematic on LInux. Seems odd. Seems like
>> it should work.
>>
>> You could try a little experiment:
>>
>>  1. First run your example according to approach (4) below to generate
>>     your Felix bundle cache. Stop the framework and keep the cache.
>>  2. Then modify your bundle to only load your JNI library a la
>>     approach (3) below.
>>  3. Copy the modified bundle directly into the bundle cache. If your
>>     bundle where installed as ID 4, for example, then you overwrite
>>     felix-cache/bundle4/version0.0/bundle.jar.
>>  4. Restart the framework and start your bundle if it doesn't
>>     automatically get restarted.
>>
>> Not sure if this will make a difference, but it basically ensures that all
>> native libraries are extracted in the same disk directory before you try to
>> load them.
>>
>> -> richard
>>
>>> Best Wishes,
>>>
>>> Duncan
>>>
>>>
>>>
>>>
>>> On Thu, Apr 28, 2011 at 12:29 PM, Angelo van der Sijpt
>>> <an...@luminis.eu>  wrote:
>>>>
>>>> Hi Duncan,
>>>>
>>>> Bundle-NativeCode will probably be your best bet: it allows you to leave
>>>> the selection of the library up to the framework, and you can quite easily
>>>> reload your library by updating the bundle.
>>>> You will have to load your libraries with System.loadLibrary, OSGi only
>>>> takes care of selecting the right library for you. Note that different os's
>>>> can have different ways of naming their libraries: for instance, you can use
>>>> loadLibrary("library") to load 'library.dll' on windows, but on Linux it
>>>> will be 'liblibrary.so' (iirc). This naming convention might be the cause of
>>>> your problem.
>>>> If loading the libraries using loadLibrary form outside OSGi, there is no
>>>> reason this shouldn't work in OSGi.
>>>>
>>>> Angelo
>>>>
>>>> On Apr 28, 2011, at 8:08 PM, duncan wrote:
>>>>
>>>>> We are accessing native libraries from Java. This works outside of
>>>>> OSGi and in OSGi on Windows but not on Linux probably because the dll
>>>>> and so linking behave differently.
>>>>>
>>>>> I have tried the following experiments:
>>>>>
>>>>> 1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
>>>>> top level JNI library. The dependent libraries are all linked
>>>>> implicitly and the unit tests run.
>>>>>
>>>>> 2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
>>>>> reverse dependency order. The libraries link but the tests fail at run
>>>>> time with inscrutable errors from the C code.
>>>>>
>>>>> 3) add all libraries to Bundle-NativeCode entry . Explicitly load only
>>>>> the JNI library. Fails to link with the other libraries.  [This would
>>>>> have been my preferred approach]
>>>>>
>>>>> 4) add all libraries to Bundle-NativeCode entry and explicitly load
>>>>> them all in reverse dependency order. The libraries link but the tests
>>>>> fail at run time with inscrutable errors from the C code.
>>>>>
>>>>> 5) tried all of the above with Felix and Equinox.
>>>>>
>>>>> So it appears that OSGi requires that I explicitly use
>>>>> System.loadLibrary for all the libraries. However, the C libraries
>>>>> that I am trying to use are not able to withstand this on Linux (but
>>>>> they do on Windows). These are native libraries from a major vendor
>>>>> and there is little chance of them patching them for me.
>>>>>
>>>>> If the libraries can be loaded from LD_LIBRARY_PATH then you would
>>>>> think that OSGi should also work. But OSGi appears to require that I
>>>>> explicitly load all libraries myself which resolves the dependencies
>>>>> in a subtly different way to how the LD_LIBRARY_PATH approach behaves.
>>>>>
>>>>> So possible outcomes are:
>>>>>
>>>>> 1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
>>>>> should reasonably be expected to load them as well.
>>>>> 2) OSGi works like this for a reason and native libraries need to be
>>>>> redesigned so they can withstand being loaded explicitly.
>>>>>
>>>>> I am considering writing a bundle that iterates through all the
>>>>> resolved bundles (at start up) and copy their .so files into a common
>>>>> location that I will put on the java.library.path. I believe this
>>>>> would work but feels like a hack.
>>>>>
>>>>> Any comments or suggestions would be most appreciated.
>>>>>
>>>>> Cheers,
>>>>>
>>>>> Duncan
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>> For additional commands, e-mail: users-help@felix.apache.org
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
>
>



-- 
Karl Pauls
karlpauls@gmail.com

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by duncan <du...@gmail.com>.
Hi Richard,

Thanks for the reply. When you said ....

> Yes, to ensure your native library dependencies are met in OSGi, it is best
> to explicitly load them in the proper order.

I think the crux of the problem is that for these particular libraries
there is no linear order that works.

You can throw them all on the LD_LIBRARY_PATH and the OS manages to
figure it out but you can't load them in a sequence.

Unfortunately these native libraries are from a database vendor so I
can't have them change them.

Regards,

Duncan



On Thu, Apr 28, 2011 at 3:07 PM, Richard S. Hall <he...@ungoverned.org> wrote:
> On 4/28/11 16:56, duncan wrote:
>>
>> Hi Angelo,
>>
>> Thanks for your response. I understand what you wrote but I think I am
>> at the point where I have convinced myself that using
>> System.loadLibrary() within OSGi can be subtly different to using it
>> outside. The behavior might be equivalent if you have a single library
>> but in my situation we have multiple dependent libraries.
>>
>> Outside of OSGi you just call System.loadLibrary() on the topmost one
>> and leave it to the OS to resolve the dependencies (from
>> LD_LIBRARY_PATH). To find libraries in bundles in OSGi you apparently
>> have to call System.loadLibrary() for each of your libraries.
>
> Yes, to ensure your native library dependencies are met in OSGi, it is best
> to explicitly load them in the proper order.
>
>> On Windows this amounts to the same thing. But on Linux the results
>> can be different. So you can have a suite of dependent libraries that
>> will link and run fine if you get them from LD_LIBRARY_PATH. But if
>> you try and load each one separately from bundle(s) there are
>> situations where they either won't resolve or will fail at run time.
>
> I'm not sure why this would be problematic on LInux. Seems odd. Seems like
> it should work.
>
> You could try a little experiment:
>
>  1. First run your example according to approach (4) below to generate
>     your Felix bundle cache. Stop the framework and keep the cache.
>  2. Then modify your bundle to only load your JNI library a la
>     approach (3) below.
>  3. Copy the modified bundle directly into the bundle cache. If your
>     bundle where installed as ID 4, for example, then you overwrite
>     felix-cache/bundle4/version0.0/bundle.jar.
>  4. Restart the framework and start your bundle if it doesn't
>     automatically get restarted.
>
> Not sure if this will make a difference, but it basically ensures that all
> native libraries are extracted in the same disk directory before you try to
> load them.
>
> -> richard
>
>> Best Wishes,
>>
>> Duncan
>>
>>
>>
>>
>> On Thu, Apr 28, 2011 at 12:29 PM, Angelo van der Sijpt
>> <an...@luminis.eu>  wrote:
>>>
>>> Hi Duncan,
>>>
>>> Bundle-NativeCode will probably be your best bet: it allows you to leave
>>> the selection of the library up to the framework, and you can quite easily
>>> reload your library by updating the bundle.
>>> You will have to load your libraries with System.loadLibrary, OSGi only
>>> takes care of selecting the right library for you. Note that different os's
>>> can have different ways of naming their libraries: for instance, you can use
>>> loadLibrary("library") to load 'library.dll' on windows, but on Linux it
>>> will be 'liblibrary.so' (iirc). This naming convention might be the cause of
>>> your problem.
>>> If loading the libraries using loadLibrary form outside OSGi, there is no
>>> reason this shouldn't work in OSGi.
>>>
>>> Angelo
>>>
>>> On Apr 28, 2011, at 8:08 PM, duncan wrote:
>>>
>>>> We are accessing native libraries from Java. This works outside of
>>>> OSGi and in OSGi on Windows but not on Linux probably because the dll
>>>> and so linking behave differently.
>>>>
>>>> I have tried the following experiments:
>>>>
>>>> 1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
>>>> top level JNI library. The dependent libraries are all linked
>>>> implicitly and the unit tests run.
>>>>
>>>> 2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
>>>> reverse dependency order. The libraries link but the tests fail at run
>>>> time with inscrutable errors from the C code.
>>>>
>>>> 3) add all libraries to Bundle-NativeCode entry . Explicitly load only
>>>> the JNI library. Fails to link with the other libraries.  [This would
>>>> have been my preferred approach]
>>>>
>>>> 4) add all libraries to Bundle-NativeCode entry and explicitly load
>>>> them all in reverse dependency order. The libraries link but the tests
>>>> fail at run time with inscrutable errors from the C code.
>>>>
>>>> 5) tried all of the above with Felix and Equinox.
>>>>
>>>> So it appears that OSGi requires that I explicitly use
>>>> System.loadLibrary for all the libraries. However, the C libraries
>>>> that I am trying to use are not able to withstand this on Linux (but
>>>> they do on Windows). These are native libraries from a major vendor
>>>> and there is little chance of them patching them for me.
>>>>
>>>> If the libraries can be loaded from LD_LIBRARY_PATH then you would
>>>> think that OSGi should also work. But OSGi appears to require that I
>>>> explicitly load all libraries myself which resolves the dependencies
>>>> in a subtly different way to how the LD_LIBRARY_PATH approach behaves.
>>>>
>>>> So possible outcomes are:
>>>>
>>>> 1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
>>>> should reasonably be expected to load them as well.
>>>> 2) OSGi works like this for a reason and native libraries need to be
>>>> redesigned so they can withstand being loaded explicitly.
>>>>
>>>> I am considering writing a bundle that iterates through all the
>>>> resolved bundles (at start up) and copy their .so files into a common
>>>> location that I will put on the java.library.path. I believe this
>>>> would work but feels like a hack.
>>>>
>>>> Any comments or suggestions would be most appreciated.
>>>>
>>>> Cheers,
>>>>
>>>> Duncan
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>>> For additional commands, e-mail: users-help@felix.apache.org
>>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>> For additional commands, e-mail: users-help@felix.apache.org
>>>
>>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by "Richard S. Hall" <he...@ungoverned.org>.
On 4/28/11 16:56, duncan wrote:
> Hi Angelo,
>
> Thanks for your response. I understand what you wrote but I think I am
> at the point where I have convinced myself that using
> System.loadLibrary() within OSGi can be subtly different to using it
> outside. The behavior might be equivalent if you have a single library
> but in my situation we have multiple dependent libraries.
>
> Outside of OSGi you just call System.loadLibrary() on the topmost one
> and leave it to the OS to resolve the dependencies (from
> LD_LIBRARY_PATH). To find libraries in bundles in OSGi you apparently
> have to call System.loadLibrary() for each of your libraries.

Yes, to ensure your native library dependencies are met in OSGi, it is 
best to explicitly load them in the proper order.

> On Windows this amounts to the same thing. But on Linux the results
> can be different. So you can have a suite of dependent libraries that
> will link and run fine if you get them from LD_LIBRARY_PATH. But if
> you try and load each one separately from bundle(s) there are
> situations where they either won't resolve or will fail at run time.

I'm not sure why this would be problematic on LInux. Seems odd. Seems 
like it should work.

You could try a little experiment:

   1. First run your example according to approach (4) below to generate
      your Felix bundle cache. Stop the framework and keep the cache.
   2. Then modify your bundle to only load your JNI library a la
      approach (3) below.
   3. Copy the modified bundle directly into the bundle cache. If your
      bundle where installed as ID 4, for example, then you overwrite
      felix-cache/bundle4/version0.0/bundle.jar.
   4. Restart the framework and start your bundle if it doesn't
      automatically get restarted.

Not sure if this will make a difference, but it basically ensures that 
all native libraries are extracted in the same disk directory before you 
try to load them.

-> richard

> Best Wishes,
>
> Duncan
>
>
>
>
> On Thu, Apr 28, 2011 at 12:29 PM, Angelo van der Sijpt
> <an...@luminis.eu>  wrote:
>> Hi Duncan,
>>
>> Bundle-NativeCode will probably be your best bet: it allows you to leave the selection of the library up to the framework, and you can quite easily reload your library by updating the bundle.
>> You will have to load your libraries with System.loadLibrary, OSGi only takes care of selecting the right library for you. Note that different os's can have different ways of naming their libraries: for instance, you can use loadLibrary("library") to load 'library.dll' on windows, but on Linux it will be 'liblibrary.so' (iirc). This naming convention might be the cause of your problem.
>> If loading the libraries using loadLibrary form outside OSGi, there is no reason this shouldn't work in OSGi.
>>
>> Angelo
>>
>> On Apr 28, 2011, at 8:08 PM, duncan wrote:
>>
>>> We are accessing native libraries from Java. This works outside of
>>> OSGi and in OSGi on Windows but not on Linux probably because the dll
>>> and so linking behave differently.
>>>
>>> I have tried the following experiments:
>>>
>>> 1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
>>> top level JNI library. The dependent libraries are all linked
>>> implicitly and the unit tests run.
>>>
>>> 2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
>>> reverse dependency order. The libraries link but the tests fail at run
>>> time with inscrutable errors from the C code.
>>>
>>> 3) add all libraries to Bundle-NativeCode entry . Explicitly load only
>>> the JNI library. Fails to link with the other libraries.  [This would
>>> have been my preferred approach]
>>>
>>> 4) add all libraries to Bundle-NativeCode entry and explicitly load
>>> them all in reverse dependency order. The libraries link but the tests
>>> fail at run time with inscrutable errors from the C code.
>>>
>>> 5) tried all of the above with Felix and Equinox.
>>>
>>> So it appears that OSGi requires that I explicitly use
>>> System.loadLibrary for all the libraries. However, the C libraries
>>> that I am trying to use are not able to withstand this on Linux (but
>>> they do on Windows). These are native libraries from a major vendor
>>> and there is little chance of them patching them for me.
>>>
>>> If the libraries can be loaded from LD_LIBRARY_PATH then you would
>>> think that OSGi should also work. But OSGi appears to require that I
>>> explicitly load all libraries myself which resolves the dependencies
>>> in a subtly different way to how the LD_LIBRARY_PATH approach behaves.
>>>
>>> So possible outcomes are:
>>>
>>> 1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
>>> should reasonably be expected to load them as well.
>>> 2) OSGi works like this for a reason and native libraries need to be
>>> redesigned so they can withstand being loaded explicitly.
>>>
>>> I am considering writing a bundle that iterates through all the
>>> resolved bundles (at start up) and copy their .so files into a common
>>> location that I will put on the java.library.path. I believe this
>>> would work but feels like a hack.
>>>
>>> Any comments or suggestions would be most appreciated.
>>>
>>> Cheers,
>>>
>>> Duncan
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>>> For additional commands, e-mail: users-help@felix.apache.org
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
>>
>>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by duncan <du...@gmail.com>.
Hi Angelo,

Thanks for your response. I understand what you wrote but I think I am
at the point where I have convinced myself that using
System.loadLibrary() within OSGi can be subtly different to using it
outside. The behavior might be equivalent if you have a single library
but in my situation we have multiple dependent libraries.

Outside of OSGi you just call System.loadLibrary() on the topmost one
and leave it to the OS to resolve the dependencies (from
LD_LIBRARY_PATH). To find libraries in bundles in OSGi you apparently
have to call System.loadLibrary() for each of your libraries.

On Windows this amounts to the same thing. But on Linux the results
can be different. So you can have a suite of dependent libraries that
will link and run fine if you get them from LD_LIBRARY_PATH. But if
you try and load each one separately from bundle(s) there are
situations where they either won't resolve or will fail at run time.

Best Wishes,

Duncan




On Thu, Apr 28, 2011 at 12:29 PM, Angelo van der Sijpt
<an...@luminis.eu> wrote:
> Hi Duncan,
>
> Bundle-NativeCode will probably be your best bet: it allows you to leave the selection of the library up to the framework, and you can quite easily reload your library by updating the bundle.
> You will have to load your libraries with System.loadLibrary, OSGi only takes care of selecting the right library for you. Note that different os's can have different ways of naming their libraries: for instance, you can use loadLibrary("library") to load 'library.dll' on windows, but on Linux it will be 'liblibrary.so' (iirc). This naming convention might be the cause of your problem.
> If loading the libraries using loadLibrary form outside OSGi, there is no reason this shouldn't work in OSGi.
>
> Angelo
>
> On Apr 28, 2011, at 8:08 PM, duncan wrote:
>
>> We are accessing native libraries from Java. This works outside of
>> OSGi and in OSGi on Windows but not on Linux probably because the dll
>> and so linking behave differently.
>>
>> I have tried the following experiments:
>>
>> 1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
>> top level JNI library. The dependent libraries are all linked
>> implicitly and the unit tests run.
>>
>> 2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
>> reverse dependency order. The libraries link but the tests fail at run
>> time with inscrutable errors from the C code.
>>
>> 3) add all libraries to Bundle-NativeCode entry . Explicitly load only
>> the JNI library. Fails to link with the other libraries.  [This would
>> have been my preferred approach]
>>
>> 4) add all libraries to Bundle-NativeCode entry and explicitly load
>> them all in reverse dependency order. The libraries link but the tests
>> fail at run time with inscrutable errors from the C code.
>>
>> 5) tried all of the above with Felix and Equinox.
>>
>> So it appears that OSGi requires that I explicitly use
>> System.loadLibrary for all the libraries. However, the C libraries
>> that I am trying to use are not able to withstand this on Linux (but
>> they do on Windows). These are native libraries from a major vendor
>> and there is little chance of them patching them for me.
>>
>> If the libraries can be loaded from LD_LIBRARY_PATH then you would
>> think that OSGi should also work. But OSGi appears to require that I
>> explicitly load all libraries myself which resolves the dependencies
>> in a subtly different way to how the LD_LIBRARY_PATH approach behaves.
>>
>> So possible outcomes are:
>>
>> 1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
>> should reasonably be expected to load them as well.
>> 2) OSGi works like this for a reason and native libraries need to be
>> redesigned so they can withstand being loaded explicitly.
>>
>> I am considering writing a bundle that iterates through all the
>> resolved bundles (at start up) and copy their .so files into a common
>> location that I will put on the java.library.path. I believe this
>> would work but feels like a hack.
>>
>> Any comments or suggestions would be most appreciated.
>>
>> Cheers,
>>
>> Duncan
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Angelo van der Sijpt <an...@luminis.eu>.
Hi Duncan,

Bundle-NativeCode will probably be your best bet: it allows you to leave the selection of the library up to the framework, and you can quite easily reload your library by updating the bundle.
You will have to load your libraries with System.loadLibrary, OSGi only takes care of selecting the right library for you. Note that different os's can have different ways of naming their libraries: for instance, you can use loadLibrary("library") to load 'library.dll' on windows, but on Linux it will be 'liblibrary.so' (iirc). This naming convention might be the cause of your problem.
If loading the libraries using loadLibrary form outside OSGi, there is no reason this shouldn't work in OSGi.

Angelo

On Apr 28, 2011, at 8:08 PM, duncan wrote:

> We are accessing native libraries from Java. This works outside of
> OSGi and in OSGi on Windows but not on Linux probably because the dll
> and so linking behave differently.
> 
> I have tried the following experiments:
> 
> 1) add libraries to LD_LIBRARY_PATH and System.loadLibrary() only the
> top level JNI library. The dependent libraries are all linked
> implicitly and the unit tests run.
> 
> 2) add libraries to LD_LIBRARY_PATH and explicitly load them all in
> reverse dependency order. The libraries link but the tests fail at run
> time with inscrutable errors from the C code.
> 
> 3) add all libraries to Bundle-NativeCode entry . Explicitly load only
> the JNI library. Fails to link with the other libraries.  [This would
> have been my preferred approach]
> 
> 4) add all libraries to Bundle-NativeCode entry and explicitly load
> them all in reverse dependency order. The libraries link but the tests
> fail at run time with inscrutable errors from the C code.
> 
> 5) tried all of the above with Felix and Equinox.
> 
> So it appears that OSGi requires that I explicitly use
> System.loadLibrary for all the libraries. However, the C libraries
> that I am trying to use are not able to withstand this on Linux (but
> they do on Windows). These are native libraries from a major vendor
> and there is little chance of them patching them for me.
> 
> If the libraries can be loaded from LD_LIBRARY_PATH then you would
> think that OSGi should also work. But OSGi appears to require that I
> explicitly load all libraries myself which resolves the dependencies
> in a subtly different way to how the LD_LIBRARY_PATH approach behaves.
> 
> So possible outcomes are:
> 
> 1) if the libraries can be loaded from LD_LIBRARY_PATH then OSGi
> should reasonably be expected to load them as well.
> 2) OSGi works like this for a reason and native libraries need to be
> redesigned so they can withstand being loaded explicitly.
> 
> I am considering writing a bundle that iterates through all the
> resolved bundles (at start up) and copy their .so files into a common
> location that I will put on the java.library.path. I believe this
> would work but feels like a hack.
> 
> Any comments or suggestions would be most appreciated.
> 
> Cheers,
> 
> Duncan
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Karl Pauls <ka...@gmail.com>.
yeah, as i said, if you want to have a solution that doesn't depend on
specific framework behaviour all you can do is the approach i outlined
before (i.e., extract the libs yourself and a do a System.load()).

However, the "extract all libs on first request" was the default
behaviour of felix for a long time for exactly this usecase. However,
we at one point of time lost it during a refactoring. For now, either
do the "extract yourself" or use the load all libs and ignore problems
and than load the toplevel one (which still depends on the framework
as it needs to extract all libs into the same folder - which felix
does and iirc equinox as well).

regards,

Karl

On Fri, Apr 29, 2011 at 4:31 PM, Daniel Faber <ma...@daniel-faber.de> wrote:
> Hey Holger,
>
> wow, awesome post with great detailed explanations which I am very
> interested in because we had a similar problem.  I have just one
> question and like to discuss a small feature request:
>
> On 29.04.2011 13:39, Holger Hoffstätte wrote:
>
>> [first part skipped, let's say we have changed our .so files to
>> include $ORIGIN in their run path]
>>
>> You see, what happens is that the OSGi runtime is at liberty to
>> unpack resources from a bundle lazily. This means that simply loading
>> a toplevel dependency is not enough, as any other bundle-included
>> dependencies may not yet have been unpacked, causing the native
>> loader to fail. The fix is easy: simply *pretend* to preload all
>> libraries (just like on Windows), but ignore any
>> UnsatisfiedLinkErrors - and then load the JNI stubs.
>
> I've read chapter 3.9 "Loading Native Code Libraries" in the OSGi spec
> again and it seems the framework is not required to unpack all of a
> bundle's native libs into the same directory.  But the procedure you
> describe relies on this, doesn't it?
>
> BTW: The spec says:
> It is not uncommon that native code libraries have dependencies on other
> native code libraries. This specification does not support these
> dependencies, it is assumed that native libraries delivered in bundles
> should not rely on other native libraries.
>
> Now the feature request I like to discuss:
>
> What if felix (or even better the OSGi spec) would recognize a new
> directive in the nativecode clause, lets call it "grouping", with this
> semantics:
>
> grouping=false
>  this is the default and it doesn't do anything
>
> grouping=true
>  this requires the framework to
>  * uncompress *all* native libs in this nativecode clause as soon as
>    the *first* of these libs is needed by System.loadLibrary()
>  * uncompress them into the same directory
>
> This will make the "pretend to preload" hack needless and although I
> didn't have a look at the felix code I guess it will be easy to implement.
>
> I am very interested in your opinion on this.
>
> Daniel Faber
>
>



-- 
Karl Pauls
karlpauls@gmail.com

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by "Richard S. Hall" <he...@ungoverned.org>.
On 4/29/11 10:31, Daniel Faber wrote:
> Hey Holger,
>
> wow, awesome post with great detailed explanations which I am very
> interested in because we had a similar problem.  I have just one
> question and like to discuss a small feature request:
>
> On 29.04.2011 13:39, Holger Hoffstätte wrote:
>
>> [first part skipped, let's say we have changed our .so files to
>> include $ORIGIN in their run path]
>>
>> You see, what happens is that the OSGi runtime is at liberty to
>> unpack resources from a bundle lazily. This means that simply loading
>> a toplevel dependency is not enough, as any other bundle-included
>> dependencies may not yet have been unpacked, causing the native
>> loader to fail. The fix is easy: simply *pretend* to preload all
>> libraries (just like on Windows), but ignore any
>> UnsatisfiedLinkErrors - and then load the JNI stubs.
> I've read chapter 3.9 "Loading Native Code Libraries" in the OSGi spec
> again and it seems the framework is not required to unpack all of a
> bundle's native libs into the same directory.  But the procedure you
> describe relies on this, doesn't it?

Yes. We had an issue on this very topic:

     https://issues.apache.org/jira/browse/FELIX-1731

We originally extracted into the same directory, then changed that, 
which broke people doing this trick, so the above issue changed it back 
to working that way.

(Technically, it might still not work in Felix if you have a fragment 
containing native libraries and it is attached to multiple hosts each of 
which are racing to extract their libraries...in such cases, the 
different hosts may not get all of their native libs in the same directory).

> BTW: The spec says:
> It is not uncommon that native code libraries have dependencies on other
> native code libraries. This specification does not support these
> dependencies, it is assumed that native libraries delivered in bundles
> should not rely on other native libraries.
>
> Now the feature request I like to discuss:
>
> What if felix (or even better the OSGi spec) would recognize a new
> directive in the nativecode clause, lets call it "grouping", with this
> semantics:
>
> grouping=false
>    this is the default and it doesn't do anything
>
> grouping=true
>    this requires the framework to
>    * uncompress *all* native libs in this nativecode clause as soon as
>      the *first* of these libs is needed by System.loadLibrary()
>    * uncompress them into the same directory
>
> This will make the "pretend to preload" hack needless and although I
> didn't have a look at the felix code I guess it will be easy to implement.
>
> I am very interested in your opinion on this.

It's possible, but I'm not sure it's worth spec'ing since there is a 
reasonable workaround. You could bring the issue up on the osgi-dev 
mailing list.

-> richard

> Daniel Faber
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by duncan <du...@gmail.com>.
Holger,

Thanks for the amazingly helpful response. We now have enough
information to get our app running.

At least this email thread will help other people understand what is
going on if they run into this issue.


Cheers

Duncan







2011/4/29 Holger Hoffstätte <ho...@googlemail.com>:
> On 29.04.2011 17:30, Richard S. Hall wrote:
>>> In that case the only way out is to first try $ORIGIN and, failing that,
>>> a fixed location like /tmp or any other directory to which your bundle
>>> can unpack the libraries and try again. It's much more difficult to get
>>> right since you really want to clean up afterwards, not clash with other
>>> instances of your bundle on the same machine (need a cooperative locking
>>> mechanism) etc.
>>
>> Could you do it in the bundle's private data area?
>
> In theory yes, but:
>
> - I'd have to know that location in advance (unless I do the crazy
> on-demand patching)
>
> - the fullly expanded path must not be longer than (I think) 14 characters
>
> ..so in practice probably not.
>
> "It's complicated". :D
>
> -h
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Holger Hoffstätte <ho...@googlemail.com>.
On 29.04.2011 17:30, Richard S. Hall wrote:
>> In that case the only way out is to first try $ORIGIN and, failing that,
>> a fixed location like /tmp or any other directory to which your bundle
>> can unpack the libraries and try again. It's much more difficult to get
>> right since you really want to clean up afterwards, not clash with other
>> instances of your bundle on the same machine (need a cooperative locking
>> mechanism) etc.
> 
> Could you do it in the bundle's private data area?

In theory yes, but:

- I'd have to know that location in advance (unless I do the crazy
on-demand patching)

- the fullly expanded path must not be longer than (I think) 14 characters

..so in practice probably not.

"It's complicated". :D

-h

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by "Richard S. Hall" <he...@ungoverned.org>.
On 4/29/11 11:21, Holger Hoffstätte wrote:
> On 29.04.2011 16:31, Daniel Faber wrote:
>> wow, awesome post with great detailed explanations which I am very
>> interested in because we had a similar problem.  I have just one
> Thanks!
>
>> I've read chapter 3.9 "Loading Native Code Libraries" in the OSGi spec
>> again and it seems the framework is not required to unpack all of a
>> bundle's native libs into the same directory.  But the procedure you
>> describe relies on this, doesn't it?
> Right! I figured I'd leave that out to not make matters worse for now. I
> actually had to develop such a fallback mechanism for just that case and
> even reported a bug when Felix changed its cache layout
> (https://issues.apache.org/jira/browse/FELIX-1731), so the problem is
> definitely real. :)
>
> In that case the only way out is to first try $ORIGIN and, failing that,
> a fixed location like /tmp or any other directory to which your bundle
> can unpack the libraries and try again. It's much more difficult to get
> right since you really want to clean up afterwards, not clash with other
> instances of your bundle on the same machine (need a cooperative locking
> mechanism) etc.

Could you do it in the bundle's private data area?

-> richard


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Daniel Faber <ma...@daniel-faber.de>.
On 29.04.2011 17:21, Holger Hoffstätte wrote:

> Probably the biggest problem is the fact that the DT_RUNPATH is very
> limited in size. A truly dynamic & secure solution would be to rewrite
> the DT_RUNPATH ELF header from Java so that the path is short, but
> private (pid or short random token)..sort of like bytecode weaving, but
> for shared libraries. :)
> Porting the necessary patchelf bits to Java as OSGi service would make
> for an awesome student project!

But that OSGi service must hook into a bundle classloader's
loadLibrary() method, so this also requires framework implementation
changes, doesn't it?

> As Richard says your best
> bet would be to bring this up on the public osgi-dev list. There was a
> long-standing bug in the OSGi bugzilla about native dependencies, but I
> think it is dormant or dead.

Thanks for the hint, it's marked as wontfix:
https://www.osgi.org/bugzilla/show_bug.cgi?id=38

I have to think again about it...

Daniel Faber


Re: Bundle-NativeCode question.

Posted by Holger Hoffstätte <ho...@googlemail.com>.
On 29.04.2011 16:31, Daniel Faber wrote:
> wow, awesome post with great detailed explanations which I am very
> interested in because we had a similar problem.  I have just one

Thanks!

> I've read chapter 3.9 "Loading Native Code Libraries" in the OSGi spec
> again and it seems the framework is not required to unpack all of a
> bundle's native libs into the same directory.  But the procedure you
> describe relies on this, doesn't it?

Right! I figured I'd leave that out to not make matters worse for now. I
actually had to develop such a fallback mechanism for just that case and
even reported a bug when Felix changed its cache layout
(https://issues.apache.org/jira/browse/FELIX-1731), so the problem is
definitely real. :)

In that case the only way out is to first try $ORIGIN and, failing that,
a fixed location like /tmp or any other directory to which your bundle
can unpack the libraries and try again. It's much more difficult to get
right since you really want to clean up afterwards, not clash with other
instances of your bundle on the same machine (need a cooperative locking
mechanism) etc.

It's also worth noting that the entire $ORIGIN workaround (it's not a
hack, it's a feature! :) does NOT work when the app is running SUID/GUID
root, but a) that's bad anyway and b) neither will LD_LIBRARY_PATH, for
security reasons.

Probably the biggest problem is the fact that the DT_RUNPATH is very
limited in size. A truly dynamic & secure solution would be to rewrite
the DT_RUNPATH ELF header from Java so that the path is short, but
private (pid or short random token)..sort of like bytecode weaving, but
for shared libraries. :)
Porting the necessary patchelf bits to Java as OSGi service would make
for an awesome student project!

> BTW: The spec says:
> It is not uncommon that native code libraries have dependencies on other
> native code libraries. This specification does not support these
> dependencies, it is assumed that native libraries delivered in bundles
> should not rely on other native libraries.

..and then reality sets in. It's outside the spec, but clearly not
feasible when you want to integrate 3rd-party libraries or even things
built in a larger context.

> Now the feature request I like to discuss:

Doesn't sound "too wrong" :) but is probably again in the area of
framework-dependant implementation details. As Richard says your best
bet would be to bring this up on the public osgi-dev list. There was a
long-standing bug in the OSGi bugzilla about native dependencies, but I
think it is dormant or dead. It's just very hard to get this right.

cheers
Holger

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Daniel Faber <ma...@daniel-faber.de>.
Hey Holger,

wow, awesome post with great detailed explanations which I am very
interested in because we had a similar problem.  I have just one
question and like to discuss a small feature request:

On 29.04.2011 13:39, Holger Hoffstätte wrote:

> [first part skipped, let's say we have changed our .so files to 
> include $ORIGIN in their run path]
> 
> You see, what happens is that the OSGi runtime is at liberty to 
> unpack resources from a bundle lazily. This means that simply loading
> a toplevel dependency is not enough, as any other bundle-included
> dependencies may not yet have been unpacked, causing the native
> loader to fail. The fix is easy: simply *pretend* to preload all
> libraries (just like on Windows), but ignore any 
> UnsatisfiedLinkErrors - and then load the JNI stubs.

I've read chapter 3.9 "Loading Native Code Libraries" in the OSGi spec
again and it seems the framework is not required to unpack all of a
bundle's native libs into the same directory.  But the procedure you
describe relies on this, doesn't it?

BTW: The spec says:
It is not uncommon that native code libraries have dependencies on other
native code libraries. This specification does not support these
dependencies, it is assumed that native libraries delivered in bundles
should not rely on other native libraries.

Now the feature request I like to discuss:

What if felix (or even better the OSGi spec) would recognize a new
directive in the nativecode clause, lets call it "grouping", with this
semantics:

grouping=false
  this is the default and it doesn't do anything

grouping=true
  this requires the framework to
  * uncompress *all* native libs in this nativecode clause as soon as
    the *first* of these libs is needed by System.loadLibrary()
  * uncompress them into the same directory

This will make the "pretend to preload" hack needless and although I
didn't have a look at the felix code I guess it will be easy to implement.

I am very interested in your opinion on this.

Daniel Faber


Re: Bundle-NativeCode question.

Posted by Peter Kriens <pe...@aqute.biz>.
Excellent post, should turn it into a blog.

Kind regards,

	Peter Kriens

On 29 apr 2011, at 13:39, Holger Hoffstätte wrote:

> 
> Sorry for writing so much but you asked for it.. :-)
> 
> On 28.04.2011 20:08, duncan wrote:
>> We are accessing native libraries from Java. This works outside of
>> OSGi and in OSGi on Windows but not on Linux probably because the dll
>> and so linking behave differently.
> 
> Yes and no. They work differently, but you must understand why.
> Instead of randomly "successful" expriments here is what happens & why,
> and what you can do to load native code from bundles regardless of platform.
> 
> First off: the Bundle-NativeCode capabilitiy/idea is absolutely
> fantastic and one of the most underrated & unknown features of OSGi. It
> works well, but is naturally affected by the capabilities of the
> underlying OS and Java's behaviour. Naturally this area is harder since
> "write once, run anywhere" does not apply any longer when you venture
> outside the JVM. Nobody just walks into native land.
> 
> I'll skip the case where you only have a single library, since that is
> easy and not a problem on either platform. Just link all your JNI stubs
> and whatever they call into one big dll/so and bingo; works everywhere.
> 
> As you have learned this is not so easy any more when you have two or
> more libraries with dependencies between them. Since loading of
> dependencies between native libraries works differently on different
> OSes, there is nothing OSGi itself can do here; but understanding what
> exactly happens will allow us to handle the differences in a transparent
> manner.
> 
> First off let's understand what happens when Java loads a dll/so.
> 
> Regardless of the platform-specific call the library is loaded, and -
> before the call returns - the OS will notice missing symbols (e.g.
> functions defined in a dependent library) and start the
> platform-dependent search for dependencies to satisfies the missing bits.
> Windows will look in the current working directory of the process
> (usually useless for OSGi) and then %PATH%, Linux will inspect
> LD_LIBRARY_PATH ([1]) and then consult the ld.so cache, usually located
> in /etc/ld.so.cache. This cache contains a cached representation of the
> system-wide search paths usually declared in /etc/ld.so.conf. This can
> be updated by e.g. an installer or system management tool; see man ldconfig.
> 
> All of these mechanisms are unfortunately not too useful for OSGi, since
> two or more libraries contained in & unpacked from a bundle are sitting
> somewhere in a bundle cache - a private directory normally not visible
> to the OS. So what can you do to trick the native platform loading into
> doing the right thing?
> 
> Let's start with Windows since that is ironically the easiest case. As
> some other posters have indicated you can indeed pre-load dependencies
> in their correct order and then load your JNI library. The preloading
> makes sure that the last loaded dependency has no missing symbols, and
> the native search machinery does not kick in - problem averted.
> 
> Then you try this on Linux or OSX and realize that it Simply Does Not
> Work (sorry Richard :). Why?
> 
> The POSIX/Unix/Linux system calls used for loading, accessing and
> closing shared objects are called dlopen(), dlsym() and dlclose(). If
> you look at dlopen(), it takes a filename (the library to load) and a
> magic flag. The way the JVM calls dlopen() is the reason why preloading
> does not work: the flag is by platform-default set to RTLD_LOCAL, which
> does NOT expose loaded symbols to subsequently loaded libraries
> (contrary to Windows, where loaded symbols become visible).
> In other words: manual preloading of dependencies on Linux fixes exactly
> nothing! Whether this is just an unfortunate default, a bug or
> deliberate is a different, complicated discussion about isolation,
> security, stability etc. but ultimately does not matter since we cannot
> influence it.
> 
> Bummer. So what now, give up? Bah!
> 
> If preloading does not work then maybe we can make the OS do the right
> thing instead. ld.so - the dynamic loader used for resolving library
> dependencies - looks at a loaded object and obviously also needs to know
> what else to load in case there are any declared dependencies. As it
> turns out shared libraries can have a search path embedded and *this
> path can be manipulated*. Quote from the ld.so man page:
> 
>   $ORIGIN and rpath
>       ld.so  understands  the  string  $ORIGIN  (or  equivalently
>       ${ORIGIN}) in an rpath specification (DT_RPATH or DT_RUNPATH) to
>       mean the directory containing the application executable.
>       Thus, an application located in somedir/app could be compiled
>       with gcc -Wl,-rpath,'$ORIGIN/../lib' so that it finds an
>       associated shared library in somedir/lib no matter where
>       somedir is located in the directory hierarchy. [..]
> 
> Awesomesauce! This means that you can build your native libraries with
> e.g. -rpath,'$ORIGIN' and loading one dependency (for example your JNI
> stubs) will now correctly find any dependencies from the same directory.
> Win!
> 
> But what if you don't have the source to the dependencies? Or even worse
> you never learned how to compile C code?
> 
> Well, old people^h^h^h^h^h^h^h enterprising individuals like me would
> probably just bring out the old hex editor, but there is a more
> civilized way: meet patchelf [2]. For anyone who wants to dive deeper
> you can also look at [3]; I managed to make the author's "rpath" tool
> build & work on Linux with just a few modifications.
> 
> patchelf is easy to build and allows you to inspect & modify the runpath
> of any library. For an example let's find a library that has dependencies:
> 
> (readelf is part of binutils, which you should have installed already)
> 
> $readelf -d /usr/lib/libpcrecpp.so.0.0.0
> 
> Dynamic section at offset 0x8dd4 contains 28 entries:
>  Tag        Type                  Name/Value
> 0x00000001 (NEEDED)              Shared library: [libpcre.so.0]
> 0x00000001 (NEEDED)              Shared library:[libstdc++.so.6]
> 0x00000001 (NEEDED)              Shared library: [libm.so.6]
> 0x00000001 (NEEDED)              Shared library: [libc.so.6]
> 0x00000001 (NEEDED)              Shared library: [libgcc_s.so.1]
> 0x0000000e (SONAME)              Library soname: [libpcrecpp.so.0]
> 0x0000000c (INIT)                0x2af8
> 
> That should do: the C++ wrapper for pcre needs the core C pcre library
> as dependency. Let's modify it!
> 
> $cp /usr/lib/libpcrecpp.so.0.0.0 .
> $patchelf --set-rpath '.:$ORIGIN' libpcrecpp.so.0.0.0
> $patchelf --print-rpath libpcrecpp.so.0.0.0
> .:$ORIGIN
> 
> And indeed:
> 
> holger>readelf -d libpcrecpp.so.0.0.0
> 
> Dynamic section at offset 0xa100 contains 29 entries:
>  Tag        Type                  Name/Value
> 0x0000001d (RUNPATH)             Library runpath: [.:$ORIGIN]
> 0x00000001 (NEEDED)              Shared library: [libpcre.so.0]
> [..]
> 
> This means that loading this library would make the ld.so loader look
> for dependencies first in the current directory of the process (which
> btw is a questionable practice, mostly for security reasons), and then
> in the directory where the originating library is located..which could
> be the completely unknown and anonymous bundle cache of the OSGi
> runtime. Win!
> 
> So you modify all your .so libraries, package them into the bundle
> and..OH NOES! It STILL does not work! Depending on the OSGi runtime you
> still get errors about the native dependency not being found, despite
> $ORIGIN.
> 
> "You didn't think it would be that easy, did you? Silly Rabbit."
> 
> You see, what happens is that the OSGi runtime is at liberty to unpack
> resources from a bundle lazily. This means that simply loading a
> toplevel dependency is not enough, as any other bundle-included
> dependencies may not yet have been unpacked, causing the native loader
> to fail. The fix is easy: simply *pretend* to preload all libraries
> (just like on Windows), but ignore any UnsatisfiedLinkErrors - and then
> load the JNI stubs.
> 
> Et voilà: angels will sing, and your bundle will work.
> 
> To make this robust don't just sprinkle the System.loadLibrary() calls
> throughout your classes; make a central Initializer class (bound to the
> bundle's Activator or not..your choice) and refer to it. Then in that
> activator you can have differetn loading strategies for Windows
> (preloading nicely in-order), Linux (fake preloading) OSX (same as
> Linux) or any other platform. It's also a good idea not to refer to the
> classes in this bundle as "library" (i.e. passive code); make the native
> code a service and properly track it from client bundles.
> 
> I hope this answers all your questions and gives you more rope to hang
> yourself than you asked for. If not..just ask. :-)
> 
> Holger
> 
> [1] http://blogs.sun.com/rie/entr /tt_ld_library_path_tt
> [2] http://nixos.org/patchelf.html
> [3] http://blogs.sun.com/ali/entry/changing_elf_runpaths
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: Bundle-NativeCode question.

Posted by Holger Hoffstätte <ho...@googlemail.com>.
Sorry for writing so much but you asked for it.. :-)

On 28.04.2011 20:08, duncan wrote:
> We are accessing native libraries from Java. This works outside of
> OSGi and in OSGi on Windows but not on Linux probably because the dll
> and so linking behave differently.

Yes and no. They work differently, but you must understand why.
Instead of randomly "successful" expriments here is what happens & why,
and what you can do to load native code from bundles regardless of platform.

First off: the Bundle-NativeCode capabilitiy/idea is absolutely
fantastic and one of the most underrated & unknown features of OSGi. It
works well, but is naturally affected by the capabilities of the
underlying OS and Java's behaviour. Naturally this area is harder since
"write once, run anywhere" does not apply any longer when you venture
outside the JVM. Nobody just walks into native land.

I'll skip the case where you only have a single library, since that is
easy and not a problem on either platform. Just link all your JNI stubs
and whatever they call into one big dll/so and bingo; works everywhere.

As you have learned this is not so easy any more when you have two or
more libraries with dependencies between them. Since loading of
dependencies between native libraries works differently on different
OSes, there is nothing OSGi itself can do here; but understanding what
exactly happens will allow us to handle the differences in a transparent
manner.

First off let's understand what happens when Java loads a dll/so.

Regardless of the platform-specific call the library is loaded, and -
before the call returns - the OS will notice missing symbols (e.g.
functions defined in a dependent library) and start the
platform-dependent search for dependencies to satisfies the missing bits.
Windows will look in the current working directory of the process
(usually useless for OSGi) and then %PATH%, Linux will inspect
LD_LIBRARY_PATH ([1]) and then consult the ld.so cache, usually located
in /etc/ld.so.cache. This cache contains a cached representation of the
system-wide search paths usually declared in /etc/ld.so.conf. This can
be updated by e.g. an installer or system management tool; see man ldconfig.

All of these mechanisms are unfortunately not too useful for OSGi, since
two or more libraries contained in & unpacked from a bundle are sitting
somewhere in a bundle cache - a private directory normally not visible
to the OS. So what can you do to trick the native platform loading into
doing the right thing?

Let's start with Windows since that is ironically the easiest case. As
some other posters have indicated you can indeed pre-load dependencies
in their correct order and then load your JNI library. The preloading
makes sure that the last loaded dependency has no missing symbols, and
the native search machinery does not kick in - problem averted.

Then you try this on Linux or OSX and realize that it Simply Does Not
Work (sorry Richard :). Why?

The POSIX/Unix/Linux system calls used for loading, accessing and
closing shared objects are called dlopen(), dlsym() and dlclose(). If
you look at dlopen(), it takes a filename (the library to load) and a
magic flag. The way the JVM calls dlopen() is the reason why preloading
does not work: the flag is by platform-default set to RTLD_LOCAL, which
does NOT expose loaded symbols to subsequently loaded libraries
(contrary to Windows, where loaded symbols become visible).
In other words: manual preloading of dependencies on Linux fixes exactly
nothing! Whether this is just an unfortunate default, a bug or
deliberate is a different, complicated discussion about isolation,
security, stability etc. but ultimately does not matter since we cannot
influence it.

Bummer. So what now, give up? Bah!

If preloading does not work then maybe we can make the OS do the right
thing instead. ld.so - the dynamic loader used for resolving library
dependencies - looks at a loaded object and obviously also needs to know
what else to load in case there are any declared dependencies. As it
turns out shared libraries can have a search path embedded and *this
path can be manipulated*. Quote from the ld.so man page:

   $ORIGIN and rpath
       ld.so  understands  the  string  $ORIGIN  (or  equivalently
       ${ORIGIN}) in an rpath specification (DT_RPATH or DT_RUNPATH) to
       mean the directory containing the application executable.
       Thus, an application located in somedir/app could be compiled
       with gcc -Wl,-rpath,'$ORIGIN/../lib' so that it finds an
       associated shared library in somedir/lib no matter where
       somedir is located in the directory hierarchy. [..]

Awesomesauce! This means that you can build your native libraries with
e.g. -rpath,'$ORIGIN' and loading one dependency (for example your JNI
stubs) will now correctly find any dependencies from the same directory.
Win!

But what if you don't have the source to the dependencies? Or even worse
you never learned how to compile C code?

Well, old people^h^h^h^h^h^h^h enterprising individuals like me would
probably just bring out the old hex editor, but there is a more
civilized way: meet patchelf [2]. For anyone who wants to dive deeper
you can also look at [3]; I managed to make the author's "rpath" tool
build & work on Linux with just a few modifications.

patchelf is easy to build and allows you to inspect & modify the runpath
of any library. For an example let's find a library that has dependencies:

(readelf is part of binutils, which you should have installed already)

$readelf -d /usr/lib/libpcrecpp.so.0.0.0

Dynamic section at offset 0x8dd4 contains 28 entries:
  Tag        Type                  Name/Value
 0x00000001 (NEEDED)              Shared library: [libpcre.so.0]
 0x00000001 (NEEDED)              Shared library:[libstdc++.so.6]
 0x00000001 (NEEDED)              Shared library: [libm.so.6]
 0x00000001 (NEEDED)              Shared library: [libc.so.6]
 0x00000001 (NEEDED)              Shared library: [libgcc_s.so.1]
 0x0000000e (SONAME)              Library soname: [libpcrecpp.so.0]
 0x0000000c (INIT)                0x2af8

That should do: the C++ wrapper for pcre needs the core C pcre library
as dependency. Let's modify it!

$cp /usr/lib/libpcrecpp.so.0.0.0 .
$patchelf --set-rpath '.:$ORIGIN' libpcrecpp.so.0.0.0
$patchelf --print-rpath libpcrecpp.so.0.0.0
.:$ORIGIN

And indeed:

holger>readelf -d libpcrecpp.so.0.0.0

Dynamic section at offset 0xa100 contains 29 entries:
  Tag        Type                  Name/Value
 0x0000001d (RUNPATH)             Library runpath: [.:$ORIGIN]
 0x00000001 (NEEDED)              Shared library: [libpcre.so.0]
[..]

This means that loading this library would make the ld.so loader look
for dependencies first in the current directory of the process (which
btw is a questionable practice, mostly for security reasons), and then
in the directory where the originating library is located..which could
be the completely unknown and anonymous bundle cache of the OSGi
runtime. Win!

So you modify all your .so libraries, package them into the bundle
and..OH NOES! It STILL does not work! Depending on the OSGi runtime you
still get errors about the native dependency not being found, despite
$ORIGIN.

"You didn't think it would be that easy, did you? Silly Rabbit."

You see, what happens is that the OSGi runtime is at liberty to unpack
resources from a bundle lazily. This means that simply loading a
toplevel dependency is not enough, as any other bundle-included
dependencies may not yet have been unpacked, causing the native loader
to fail. The fix is easy: simply *pretend* to preload all libraries
(just like on Windows), but ignore any UnsatisfiedLinkErrors - and then
load the JNI stubs.

Et voilà: angels will sing, and your bundle will work.

To make this robust don't just sprinkle the System.loadLibrary() calls
throughout your classes; make a central Initializer class (bound to the
bundle's Activator or not..your choice) and refer to it. Then in that
activator you can have differetn loading strategies for Windows
(preloading nicely in-order), Linux (fake preloading) OSX (same as
Linux) or any other platform. It's also a good idea not to refer to the
classes in this bundle as "library" (i.e. passive code); make the native
code a service and properly track it from client bundles.

I hope this answers all your questions and gives you more rope to hang
yourself than you asked for. If not..just ask. :-)

Holger

[1] http://blogs.sun.com/rie/entr /tt_ld_library_path_tt
[2] http://nixos.org/patchelf.html
[3] http://blogs.sun.com/ali/entry/changing_elf_runpaths

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org