Stack, Struct and DL

Discussion in 'Ruby' started by Luc Heinrich, Mar 23, 2005.

  1. Luc Heinrich

    Luc Heinrich Guest

    Greetings,

    Suppose that I have the following C code:

    typedef struct FOO
    {
    int bar;
    int baz;
    };

    FOO make_a_foo( void )
    {
    FOO foo;
    foo.bar = 42;
    foo.baz = 1;

    return foo;
    }

    I'm struggling to find the correct way (if it's even possible) to get my
    hands on the struct returned by 'make_a_foo', using ruby/dl.

    I smell some troubles.

    --
    Luc Heinrich -
    Luc Heinrich, Mar 23, 2005
    #1
    1. Advertising

  2. Luc Heinrich

    Eric Hodel Guest

    --Apple-Mail-12-156090484
    Content-Transfer-Encoding: 7bit
    Content-Type: text/plain; charset=US-ASCII; format=flowed

    On 23 Mar 2005, at 08:49, Luc Heinrich wrote:

    > Greetings,
    >
    > Suppose that I have the following C code:
    >
    > typedef struct FOO
    > {
    > int bar;
    > int baz;
    > };
    >
    > FOO make_a_foo( void )
    > {
    > FOO foo;
    > foo.bar = 42;
    > foo.baz = 1;
    >
    > return foo;
    > }
    >
    > I'm struggling to find the correct way (if it's even possible) to get
    > my
    > hands on the struct returned by 'make_a_foo', using ruby/dl.
    >
    > I smell some troubles.


    I had just this problem a few days ago [ruby-talk:134052].

    Takaaki Tateishi had the solution in [ruby-talk:134057].

    module Stuff
    FOO = struct [
    "int bar",
    "int baz"
    ]

    extern "FOO make_a_foo(void)"

    def my_make_a_foo
    return FOO.new(make_a_foo)
    end

    end

    I think.

    --
    Eric Hodel - - http://segment7.net
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

    --Apple-Mail-12-156090484
    content-type: application/pgp-signature; x-mac-type=70674453;
    name=PGP.sig
    content-description: This is a digitally signed message part
    content-disposition: inline; filename=PGP.sig
    content-transfer-encoding: 7bit

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.4 (Darwin)

    iD8DBQFCQcfsMypVHHlsnwQRAvgwAJ9g/pSNcBvV6v2GqpqRqissr3mf8ACgudo0
    JrXSXSCc+kLPtT6R/uPQSzc=
    =+WOb
    -----END PGP SIGNATURE-----

    --Apple-Mail-12-156090484--
    Eric Hodel, Mar 23, 2005
    #2
    1. Advertising

  3. Luc Heinrich

    Luc Heinrich Guest

    Eric Hodel <> wrote:

    > module Stuff
    > FOO = struct [
    > "int bar",
    > "int baz"
    > ]
    >
    > extern "FOO make_a_foo(void)"
    >
    > def my_make_a_foo
    > return FOO.new(make_a_foo)
    > end
    >
    > end


    Interesting, but that didn't work for me:

    /usr/local/lib/ruby/1.8/dl/import.rb:125:in `symbol': can't find the
    symbol `make_a_foo' (RuntimeError)

    --
    Luc Heinrich -
    Luc Heinrich, Mar 23, 2005
    #3
  4. Luc Heinrich

    Luc Heinrich Guest

    Luc Heinrich <> wrote:

    > /usr/local/lib/ruby/1.8/dl/import.rb:125:in `symbol': can't find the
    > symbol `make_a_foo' (RuntimeError)


    And to make sure we're on the same page, here's exactly what I do (this,
    of course, is just a test case to reproduce a problem that I have in a
    bigger project ;) ):

    [ ------- foo.c ------ ]

    typedef struct
    {
    int bar;
    int baz;
    } FOO;

    FOO make_a_foo( void )
    {
    FOO foo;
    foo.bar = 42;
    foo.baz = 1;

    return foo;
    }

    [ -------------------- ]


    [ ------ foo.rb ------ ]

    require 'dl/import'
    require 'dl/struct'

    module Foo
    extend DL::Importable
    dlload 'foo.dylib'

    FOO = struct [ "int bar", "int baz" ]
    extern 'FOO make_a_foo(void)' # this fails
    extern 'FOO make_a_foo()' # this fails too

    def my_make_a_foo
    return FOO.new( make_a_foo )
    end

    end

    [ -------------------- ]

    The library is compiled as a dylib (I'm on OSX) using:
    $ cc -c foo.c
    $ libtool -dynamic -o foo.dylib foo.o

    If I then do:
    $ ruby foo.rb

    I get:

    /usr/local/lib/ruby/1.8/dl/import.rb:125:in `symbol': can't find the
    symbol `make_a_foo' (RuntimeError)
    from /usr/local/lib/ruby/1.8/dl/import.rb:144:in `import'
    from /usr/local/lib/ruby/1.8/dl/import.rb:61:in `extern'
    from foo.rb:9

    --
    Luc Heinrich -
    Luc Heinrich, Mar 23, 2005
    #4
  5. Luc Heinrich

    Eric Hodel Guest

    --Apple-Mail-13-160996181
    Content-Transfer-Encoding: 7bit
    Content-Type: text/plain; charset=US-ASCII; format=flowed

    On 23 Mar 2005, at 12:59, Luc Heinrich wrote:

    > Luc Heinrich <> wrote:
    >
    >> /usr/local/lib/ruby/1.8/dl/import.rb:125:in `symbol': can't find the
    >> symbol `make_a_foo' (RuntimeError)

    >
    > And to make sure we're on the same page, here's exactly what I do
    > (this,
    > of course, is just a test case to reproduce a problem that I have in a
    > bigger project ;) ):


    You'll have to teach DL what type FOO is. Unfortunately, DL doesn't
    barf on you in a friendly way when it can't recognize a type.

    > [ ------ foo.rb ------ ]
    >
    > require 'dl/import'
    > require 'dl/struct'
    >
    > module Foo
    > extend DL::Importable
    > dlload 'foo.dylib'


    typealias "FOO", "void *"

    Something like this should do it. (Yeah, void * is probably the wrong
    type, see dl/types for what types dl knows about.)

    > FOO = struct [ "int bar", "int baz" ]
    > extern 'FOO make_a_foo(void)' # this fails
    > extern 'FOO make_a_foo()' # this fails too
    >
    > def my_make_a_foo
    > return FOO.new( make_a_foo )
    > end
    >
    > end
    >
    > [ -------------------- ]
    >
    > The library is compiled as a dylib (I'm on OSX) using:
    > $ cc -c foo.c
    > $ libtool -dynamic -o foo.dylib foo.o
    >
    > If I then do:
    > $ ruby foo.rb
    >
    > I get:
    >
    > /usr/local/lib/ruby/1.8/dl/import.rb:125:in `symbol': can't find the
    > symbol `make_a_foo' (RuntimeError)
    > from /usr/local/lib/ruby/1.8/dl/import.rb:144:in `import'
    > from /usr/local/lib/ruby/1.8/dl/import.rb:61:in `extern'
    > from foo.rb:9
    >
    > --
    > Luc Heinrich -
    >


    --
    Eric Hodel - - http://segment7.net
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

    --Apple-Mail-13-160996181
    content-type: application/pgp-signature; x-mac-type=70674453;
    name=PGP.sig
    content-description: This is a digitally signed message part
    content-disposition: inline; filename=PGP.sig
    content-transfer-encoding: 7bit

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.4 (Darwin)

    iD4DBQFCQdsWMypVHHlsnwQRAtJQAJQMBNYH5g2hNqNQup0HxunDnzXHAJ9SpzPe
    DUsrTMKdWPkDBDFh8o9OpQ==
    =Kb66
    -----END PGP SIGNATURE-----

    --Apple-Mail-13-160996181--
    Eric Hodel, Mar 23, 2005
    #5
  6. Luc Heinrich

    Ben Giddings Guest

    Eric Hodel wrote:
    > You'll have to teach DL what type FOO is. Unfortunately, DL doesn't
    > barf on you in a friendly way when it can't recognize a type.


    Nicely phrased. ;)

    >> [ ------ foo.rb ------ ]
    >>
    >> require 'dl/import'
    >> require 'dl/struct'
    >>
    >> module Foo
    >> extend DL::Importable
    >> dlload 'foo.dylib'

    >
    >
    > typealias "FOO", "void *"
    >
    > Something like this should do it. (Yeah, void * is probably the wrong
    > type, see dl/types for what types dl knows about.)


    Actually, "void *" is probably right. When I wrapped my DLL using
    Ruby/DL I just used "void *" whenever I came across a type that I hadn't
    taught DL about. That seemed to do the trick for me.

    Also (I'm no DLL expert or anything) but with GCC I think you have to
    specify position independent code (-fPIC) and some other nifty things.
    Make sure the problem is a DL problem, not a problem with the original DLL.

    Ben
    Ben Giddings, Mar 23, 2005
    #6
  7. Luc Heinrich

    Luc Heinrich Guest

    Eric Hodel <> wrote:

    > typealias "FOO", "void *"
    >
    > Something like this should do it. (Yeah, void * is probably the wrong
    > type, see dl/types for what types dl knows about.)


    Right, typealias-ing to 'void*' seems to do the trick for this case,
    although I'm not sure if it's really the correct way or just a
    coincidence. dl/types (mostly) knows about primitive types and pointers
    to primitive types, and I'm not sure how structs passed on the stack can
    relate to these.

    Because if we now consider this:

    Adding this function to foo.c:

    void dump_foo( FOO foo )
    {
    printf( "foo.bar = %d\n", foo.bar );
    printf( "foo.baz = %d\n", foo.baz );
    }

    And then adding this to foo.rb:

    extern 'void dump_foo(FOO)'

    And then doing:

    foo = Foo.my_make_a_foo
    Foo.dump_foo( foo )

    Gives:

    foo.bar = -1073791088
    foo.baz = 891578649

    Instead of:

    foo.bar = 42
    foo.baz = 1

    That's why I'm a bit suspicious about the 'void*' thing ;)

    --
    Luc Heinrich -
    Luc Heinrich, Mar 23, 2005
    #7
  8. Luc Heinrich

    ES Guest

    In data 3/23/2005, "(Luc Heinrich)" <> ha scritto:

    >Eric Hodel <> wrote:
    >
    >> typealias "FOO", "void *"
    >>
    >> Something like this should do it. (Yeah, void * is probably the wrong
    >> type, see dl/types for what types dl knows about.)

    >
    >Right, typealias-ing to 'void*' seems to do the trick for this case,
    >although I'm not sure if it's really the correct way or just a
    >coincidence. dl/types (mostly) knows about primitive types and pointers
    >to primitive types, and I'm not sure how structs passed on the stack can
    >relate to these.
    >
    >Because if we now consider this:
    >
    >Adding this function to foo.c:
    >
    > void dump_foo( FOO foo )
    > {
    > printf( "foo.bar = %d\n", foo.bar );
    > printf( "foo.baz = %d\n", foo.baz );
    > }
    >
    >And then adding this to foo.rb:
    >
    > extern 'void dump_foo(FOO)'
    >
    >And then doing:
    >
    > foo = Foo.my_make_a_foo
    > Foo.dump_foo( foo )
    >
    >Gives:
    >
    > foo.bar = -1073791088
    > foo.baz = 891578649
    >
    >Instead of:
    >
    > foo.bar = 42
    > foo.baz = 1
    >
    >That's why I'm a bit suspicious about the 'void*' thing ;)


    Normally you'd cast from void*, of course, but I don't know
    if it's possible in DL. Maybe pass around a struct FOO* instead?

    That or just write a C extension.

    >Luc Heinrich -


    E
    ES, Mar 23, 2005
    #8
  9. Luc Heinrich

    Luc Heinrich Guest

    ES <> wrote:

    > Normally you'd cast from void*, of course, but I don't know
    > if it's possible in DL. Maybe pass around a struct FOO* instead?


    That's precisely the problem: I'm wrapping a system library so I can't
    change it.

    > That or just write a C extension.


    Yeah, I guess I'll have to go that way. That's too bad because DL is
    actually pretty fun and productive.

    --
    Luc Heinrich -
    Luc Heinrich, Mar 24, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Fogelklou
    Replies:
    36
    Views:
    1,356
    Chris Fogelklou
    Apr 20, 2004
  2. Surinder Singh
    Replies:
    1
    Views:
    1,177
    Richard Bos
    Dec 20, 2007
  3. Casey Hawthorne
    Replies:
    3
    Views:
    1,068
    Flash Gordon
    Nov 1, 2009
  4. Debajit Adhikary
    Replies:
    36
    Views:
    2,253
    Andre Kaufmann
    Feb 10, 2011
  5. Sam Roberts
    Replies:
    1
    Views:
    213
    Yukihiro Matsumoto
    Feb 11, 2005
Loading...

Share This Page