NativeBoost: Documentation Suggestion and Question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
The ESUG presentation this year was very comprehensive. I suggest making the slides and sample code more prominent/easily accessible from the code.

Using the presentation, I tried to communicate with the portaudio lib (OSX 10.8.5, lib installed with brew).

I did:
PaInitialize
 <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
 ^ self
  nbCall: #(int _Pa_Initialize())
  module: 'libportaudio.dylib'

The docs list the function name without the underscore, but nm revealed it with a leading underscore.

For the module, I tried:
- full path to dylib link above
- fill path to actual versioned dylib file i.e. ...2.dylib
- symlinking both into the VM Plugins folder

I was thinking maybe this was the indirect function thing like chipmunk, but even "self nbGetExtenalAddress: 'Pa_Initialize' module: 'libportaudio.dylib' returned nil. I tried with and without the underscore, with the module specified all four ways.

Thanks in advance for any guidance...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
Using the presentation, I tried to communicate with the portaudio lib (OSX 10.8.5, lib installed with brew).
...
Thanks in advance for any guidance...
Bump. btw I should mention that the error was "function unavailable"
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko



On 12 November 2013 02:43, Sean P. DeNigris <[hidden email]> wrote:
Sean P. DeNigris wrote
> Using the presentation, I tried to communicate with the portaudio lib (OSX
> 10.8.5, lib installed with brew).
> ...
> Thanks in advance for any guidance...

Bump. btw I should mention that the error was "function unavailable"


sorry, i was out on weekend..

first thing to do is to:

file youlib.dylib

and check it is 32-bit compatible.

and second is nbGetSymbolAddress: aName module: aModuleNameOrHandle

you can also try to use #ioLoadModule:  method
to check if library can be loaded.

with mangled symbols things are a bit tricky.. sometimes it extra underscore..
sometimes even two of them..

on mac, use otool to figure exported symbols.
 

-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805p4721184.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.




--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Igor Stasenko wrote
> sorry, i was out on weekend..
You're not allowed to have a life. You're too important ;)

Igor Stasenko wrote
and check it is 32-bit compatible.
Great! That was the first problem - 64bit only. Recompiled as universal and I'm able to communicate with the lib

Igor Stasenko wrote
you can also try to use #ioLoadModule:  method
to check if library can be loaded.
This is a good trick to know because by going to #nbGetSymbolAddress:module: right away, one can't tell whether it's the library or the symbol can't be found. This narrows it down.

Igor Stasenko wrote
on mac, use otool to figure exported symbols.
The weird thing is that "nm -g" showed the function with a leading underscore, "otool -TV" showed no exported symbols, and from NB, what actually worked was the function name without any leading underscore.

Anyway, I'm implementing one of the demos. I'll let you know how it turns out.

Thank you for the support!!!
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
I'll let you know how it turns out.
Okay, I got a little further. I can initialize and terminate the library. Yahoo!!

To load the very basic spike:
    Gofer it
        smalltalkhubUser: 'SeanDeNigris' project: 'PortAudio';
        package: 'PortAudio';
        load.

My next task is to call...
        PaError Pa_OpenDefaultStream(PaStream ** stream, "PaStream is typedef for void"
                int numInputChannels,
                int numOutputChannels,
                ulong sampleFormat,
                double sampleRate,
                ulong framesPerBuffer,
                PaStreamCallback streamCallback,
                void * userData) (see http://portaudio.com/docs/v19-doxydocs/open_default_stream.html)

The first argument is most perplexing to me. I haven't seen any NativeBoost examples of pointers to pointers. In fact, with pointers to values, it seems random whether they are derefenced when described in NB.

For example:
  cairo_t* cairo_create (cairo_surface_t *target);
becomes (from the IWST paper):
  self nbCall: #(
AthensCairoCanvas cairo_create (
                  AthensCairoSurface cairoSurface))

Notice the argument is dereferenced in the NB version.

But (also from the IWST paper):
  "void cairo_matrix_multiply (
                     cairo_matrix_t *result,
                     const cairo_matrix_t *a,
                     const cairo_matrix_t *b );"
becomes:
  self nbCall: #(void cairo_matrix_multiply (AthensCairoMatrix * self, AthensCairoMatrix * m , AthensCairoMatrix * self ) )

In this case, none of the arguments are defererenced.

Anyway, I'd reeeeeally appreciate it if someone would load the code and see what the problem is.

"PortAudio example" will run the demo script I'm translating from the library docs into Pharo.

Thanks in advance...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko
According to its manual
(http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html#a0a12735ac191200f696a43b87667b714)

stream

The address of a PaStream pointer which will receive a pointer to the newly opened stream.


So, what you need to pass is a pointer to location where pointer will be stored.
The simplest way how to do it (without explaining you how to use NBExternalValue)
just do a following:

PaError Pa_OpenDefaultStream(NBExternalAddress * stream ... )

then your call site will look like following:

streamHandle := NBExternalAddress new.

self Pa_opendefaultBlah: streamHandle  ...


The 'NBExternalAddress *' type treated specially, because usually for most cases
if you pass an instance of NBExternalAddress to any function which expects some pointer, NB will pass the value of NBExternalAddress, however if type is
NBExternalAddress * , then NB will pass a pointer where pointer value is stored (which  effectively means pointer to pointer)

that should do the trick.
But hold on, next thing you will stuck with is callback ... hehe :)
ah.. ok, according to manual, you can simply skip this one by passing NULL (nil)
for that, again you can just change the function signature and instead of putting


PaStreamCallback streamCallback

put nil. (yes, nil literal)



On 13 November 2013 06:11, Sean P. DeNigris <[hidden email]> wrote:
Sean P. DeNigris wrote
> I'll let you know how it turns out.

Okay, I got a little further. I can initialize and terminate the library.
Yahoo!!

To load the very basic spike:
    Gofer it
        smalltalkhubUser: 'SeanDeNigris' project: 'PortAudio';
        package: 'PortAudio';
        load.

My next task is to call...
        PaError Pa_OpenDefaultStream(PaStream **        stream, "PaStream is typedef for
void"
                int     numInputChannels,
                int     numOutputChannels,
                ulong   sampleFormat,
                double  sampleRate,
                ulong   framesPerBuffer,
                PaStreamCallback        streamCallback,
                void *  userData) (see
http://portaudio.com/docs/v19-doxydocs/open_default_stream.html)

The first argument is most perplexing to me. I haven't seen any NativeBoost
examples of pointers to pointers. In fact, with pointers to values, it seems
random whether they are derefenced when described in NB.

For example:
  cairo_t* cairo_create (cairo_surface_t *target);
becomes (from the IWST paper):
  self nbCall: #(
AthensCairoCanvas cairo_create (
                  AthensCairoSurface cairoSurface))

Notice the argument is dereferenced in the NB version.

But (also from the IWST paper):
  "void cairo_matrix_multiply (
                     cairo_matrix_t *result,
                     const cairo_matrix_t *a,
                     const cairo_matrix_t *b );"
becomes:
  self nbCall: #(void cairo_matrix_multiply (AthensCairoMatrix * self,
AthensCairoMatrix * m , AthensCairoMatrix * self ) )

In this case, none of the arguments are defererenced.

Anyway, I'd reeeeeally appreciate it if someone would load the code and see
what the problem is.

"PortAudio example" will run the demo script I'm translating from the
library docs into Pharo.

Thanks in advance...



-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805p4721585.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.




--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Igor Stasenko wrote
PaError Pa_OpenDefaultStream(NBExternalAddress * stream ... )
then your call site will look like following:
streamHandle := NBExternalAddress new.
Okay, one step closer. I somewhat randomly guessed to use NBExternalAddress, but didn't have the correct thing in the signature...

Igor Stasenko wrote
But hold on, next thing you will stuck with is callback ... hehe :)
...
for that, again you can just change the function signature and...
put nil. (yes, nil literal)
So you're saying the signature would become:
        nbCall: #(PaError Pa_OpenDefaultStream(NBExternalAddress * stream,
                ...
                ulong framesPerBuffer,
                nil,
                void * userData))

I made the changes as I understood them, but I'm getting a "generic failure" when I call Pa_OpenDefaultStream.

I uploaded the latest changes to the repo...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
I'm getting a "generic failure" when I call Pa_OpenDefaultStream.
Ping ;) I'm stuck...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
Sean P. DeNigris wrote
Ping ;) I'm stuck...
Perhaps Igor prefers "bump"... ;)
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Stéphane Ducasse
In reply to this post by Sean P. DeNigris
sean

could you propose something for it: adding a class ReadMe? DocuMe?
Adding it to the help?

Stef

On Nov 9, 2013, at 8:21 PM, Sean P. DeNigris <[hidden email]> wrote:

> The ESUG presentation this year was very comprehensive. I suggest making the
> slides and sample code more prominent/easily accessible from the code.
>
> Using the presentation, I tried to communicate with the portaudio lib (OSX
> 10.8.5, lib installed with brew).
>
> I did:
> PaInitialize
> <primitive: #primitiveNativeCall module: #NativeBoostPlugin>
> ^ self
>  nbCall: #(int _Pa_Initialize())
>  module: 'libportaudio.dylib'
>
> The docs list the function name without the underscore, but nm revealed it
> with a leading underscore.
>
> For the module, I tried:
> - full path to dylib link above
> - fill path to actual versioned dylib file i.e. ...2.dylib
> - symlinking both into the VM Plugins folder
>
> I was thinking maybe this was the indirect function thing like chipmunk, but
> even "self nbGetExtenalAddress: 'Pa_Initialize' module: 'libportaudio.dylib'
> returned nil. I tried with and without the underscore, with the module
> specified all four ways.
>
> Thanks in advance for any guidance...
>
>
>
> -----
> Cheers,
> Sean
> --
> View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805.html
> Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.
>


Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko
In reply to this post by Sean P. DeNigris



On 13 November 2013 18:08, Sean P. DeNigris <[hidden email]> wrote:
Igor Stasenko wrote
> PaError Pa_OpenDefaultStream(NBExternalAddress * stream ... )
> then your call site will look like following:
> streamHandle := NBExternalAddress new.

Okay, one step closer. I somewhat randomly guessed to use NBExternalAddress,
but didn't have the correct thing in the signature...


Igor Stasenko wrote
> But hold on, next thing you will stuck with is callback ... hehe :)
> ...
> for that, again you can just change the function signature and...
> put nil. (yes, nil literal)

So you're saying the signature would become:
        nbCall: #(PaError Pa_OpenDefaultStream(NBExternalAddress * stream,
                ...
                ulong   framesPerBuffer,
                nil,
                void *  userData))

I made the changes as I understood them, but I'm getting a "generic failure"
when I call Pa_OpenDefaultStream.

I uploaded the latest changes to the repo...



sorry for late reply.
 
hmm.. everything should work.
except i think nil -> void * is not accepted by default.
you should use #optCoerceNilToNull option:

self nbCall: ... options: #(+ optCoerceNilToNull)
 
or, if you don't wanna mess with options, you can always pass a null pointer by constructing it,
a simplest way is to pass dumb and stupid

NBExternalAddress null.


-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805p4721810.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.




--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko



On 21 November 2013 16:23, Igor Stasenko <[hidden email]> wrote:



On 13 November 2013 18:08, Sean P. DeNigris <[hidden email]> wrote:
Igor Stasenko wrote
> PaError Pa_OpenDefaultStream(NBExternalAddress * stream ... )
> then your call site will look like following:
> streamHandle := NBExternalAddress new.

Okay, one step closer. I somewhat randomly guessed to use NBExternalAddress,
but didn't have the correct thing in the signature...


Igor Stasenko wrote
> But hold on, next thing you will stuck with is callback ... hehe :)
> ...
> for that, again you can just change the function signature and...
> put nil. (yes, nil literal)

So you're saying the signature would become:
        nbCall: #(PaError Pa_OpenDefaultStream(NBExternalAddress * stream,
                ...
                ulong   framesPerBuffer,
                nil,
                void *  userData))

I made the changes as I understood them, but I'm getting a "generic failure"
when I call Pa_OpenDefaultStream.

I uploaded the latest changes to the repo...



sorry for late reply.
 
hmm.. everything should work.
except i think nil -> void * is not accepted by default.
you should use #optCoerceNilToNull option:

self nbCall: ... options: #(+ optCoerceNilToNull)
 
or, if you don't wanna mess with options, you can always pass a null pointer by constructing it,
a simplest way is to pass dumb and stupid

NBExternalAddress null.

... or since i doubt you will ever use userData argument, best option would be to just change the signature
and put nil in it, eliminating need to care about passing and converting useless null parameter(s).
 

-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805p4721810.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.




--
Best regards,
Igor Stasenko.



--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
In reply to this post by Igor Stasenko
Igor Stasenko wrote
a simplest way is to pass dumb and stupid
NBExternalAddress null.
Yes! That worked :) Thank you!!

Igor Stasenko wrote
except i think nil -> void * is not accepted by default.
Why is that disabled by default? It seems like a fairly common operation...
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
In reply to this post by Stéphane Ducasse
Stéphane Ducasse wrote
could you propose something for it: adding a class ReadMe? DocuMe?
Adding it to the help?
I'll organize my observations. A few that stood out:
- In signature
        - you must type "ulong", not "unsigned long"
        - when passing objects as arguments, don't need "*" unless you might pass null
- typedefs: declare in shared pool
- Pass a pointer receiving external object as an argument: NBExternalAddress new
- Pass nil as a pointer argument: NBExternalAddress null
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko
In reply to this post by Sean P. DeNigris



On 21 November 2013 17:34, Sean P. DeNigris <[hidden email]> wrote:
Igor Stasenko wrote
> a simplest way is to pass dumb and stupid
> NBExternalAddress null.

Yes! That worked :) Thank you!!


Igor Stasenko wrote
> except i think nil -> void * is not accepted by default.

Why is that disabled by default? It seems like a fairly common operation...


mm.. well, i prefer that fairly common would be to pass meaningful data back and forth rather than
dummy values.

For that best solution, IMO, would be to use 2 methods which call same function,
but one uses 'nil' in function signature (and therefore method doesn't takes extra argument),
while other takes extra argument but doesn't accepts nils, for sure.

 

-----
Cheers,
Sean
--
View this message in context: http://forum.world.st/NativeBoost-Documentation-Suggestion-and-Question-tp4720805p4724034.html
Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.




--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Sean P. DeNigris
Administrator
> mm.. well, i prefer that fairly common would be to pass meaningful data back and forth rather than
> dummy values.
I don't understand... when I say "fairly common", I mean that in the C world, it seems common to use null-passing for optional arguments. I'm not saying that it's a good idea, but we don't have control over that, so...

> For that best solution, IMO, would be to use 2 methods which call same function,
> but one uses 'nil' in function signature (and therefore method doesn't takes extra argument),
> while other takes extra argument but doesn't accepts nils, for sure.
Yuck ;)
Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: NativeBoost: Documentation Suggestion and Question

Igor Stasenko



On 21 November 2013 19:10, Sean P. DeNigris <[hidden email]> wrote:
> mm.. well, i prefer that fairly common would be to pass meaningful data back and forth rather than
> dummy values.
I don't understand... when I say "fairly common", I mean that in the C world, it seems common to use null-passing for optional arguments. I'm not saying that it's a good idea, but we don't have control over that, so...

if it would be just C world :)

Another reason for not making this default, because checking for nil is one extra check
for every piece of generated code which expects pointer, and i hope you agree that while null-value is fairly common, non-null is much more common.
 
> For that best solution, IMO, would be to use 2 methods which call same function,
> but one uses 'nil' in function signature (and therefore method doesn't takes extra argument),
> while other takes extra argument but doesn't accepts nils, for sure.
Yuck ;)

but this is quite common in smalltalk isn't? Look at Canvas - good example of overusing it i.e.:

drawThis: withThis: andThat:
drawThis: withThis: andThat: andAlsoThis:
drawThis: withThis: andThat: andAlsoThis: andAlsoThat:

:)

yes, sometimes it looks like unnecessary protocol bloating, but i think for our case it is well justified.
 
Cheers,
Sean


View this message in context: Re: NativeBoost: Documentation Suggestion and Question



--
Best regards,
Igor Stasenko.