mvz / gir_ffi

Auto-generate bindings for GObject based libraries at run time using FFI

Home Page:https://github.com/mvz/gir_ffi/wiki

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can't figure out method signature...

grimmy opened this issue · comments

Any help in this would be greatly appreciated. I'm trying to call into a library of mine that works in other languages with the given gir, I just can't seem to figure out the syntax to make it right or if it's even supported. My knowledge of ruby is very poor, so I have tried a bunch of different combinations and can't seem to get it right.

Currently I'm running 0.7.7. I saw you just released 0.7.8 but it's not in Debian SID yet but I'll compile it if you think it'll help...

$ dpkg -s ruby-gir-ffi | grep Version
Version: 0.7.7-1

Anyways here's the run down... I have a two functions in my library defined as follows

/**                        
 * gplugin_plugin_info_new: (skip)
 * @id: The id of the plugin
 * @abi_version: The GPlugin ABI version that the plugin uses
 * @...: name/value pairs of properties to set, followed by %NULL.
 *
 * Creates a new GPluginPluginInfo instance.
 *
 * Returns: The new GPluginPluginInfo instance.
 */
GPluginPluginInfo * 
gplugin_plugin_info_new(const gchar *id, guint32 abi_version, ...) {
...
}

/**
 * gplugin_plugin_info_newv: (rename-to gplugin_plugin_info_new)
 * @id: The id of the plugin
 * @abi_version: The GPlugin ABI version that the plugin uses
 * @n_parameters: the length of the @parameters array
 * @parameters: (array length=n_parameters): an array of #GParameter
 *
 * Creates a new GPluginPluginInfo instance.
 *
 * Returns: (type GPlugin.PluginInfo) (transfer full): The new
 *  GPluginPluginInfo instance.
 */
GPluginPluginInfo *
gplugin_plugin_info_newv(const gchar *id, guint32 abi_version,
                         guint n_parameters, GParameter *parameters)
{
...
}

In the gir it looks like

      <constructor name="new"
                   c:identifier="gplugin_plugin_info_new"
                   shadowed-by="newv"
                   introspectable="0">
        <doc xml:space="preserve">Creates a new GPluginPluginInfo instance.</doc>
        <return-value transfer-ownership="full">
          <doc xml:space="preserve">The new GPluginPluginInfo instance.</doc>
          <type name="PluginInfo" c:type="GPluginPluginInfo*"/>
        </return-value>
        <parameters>
          <parameter name="id" transfer-ownership="none">
            <doc xml:space="preserve">The id of the plugin</doc>
            <type name="utf8" c:type="const gchar*"/>
          </parameter>
          <parameter name="abi_version" transfer-ownership="none">
            <doc xml:space="preserve">The GPlugin ABI version that the plugin uses</doc>
            <type name="guint32" c:type="guint32"/>
          </parameter>
          <parameter name="..." transfer-ownership="none">
            <doc xml:space="preserve">name/value pairs of properties to set, followed by %NULL.</doc>
            <varargs/>
          </parameter>
        </parameters>
      </constructor>
      <constructor name="newv"
                   c:identifier="gplugin_plugin_info_newv"
                   shadows="new">
        <doc xml:space="preserve">Creates a new GPluginPluginInfo instance.</doc>
        <return-value transfer-ownership="full">
          <doc xml:space="preserve">The new
 GPluginPluginInfo instance.</doc>
          <type name="PluginInfo" c:type="GPluginPluginInfo*"/>
        </return-value>
        <parameters>
          <parameter name="id" transfer-ownership="none">
            <doc xml:space="preserve">The id of the plugin</doc>
            <type name="utf8" c:type="const gchar*"/>
          </parameter>
          <parameter name="abi_version" transfer-ownership="none">
            <doc xml:space="preserve">The GPlugin ABI version that the plugin uses</doc>
            <type name="guint32" c:type="guint32"/>
          </parameter>
          <parameter name="n_parameters" transfer-ownership="none">
            <doc xml:space="preserve">the length of the @parameters array</doc>
            <type name="guint" c:type="guint"/>
          </parameter>
          <parameter name="parameters" transfer-ownership="none">
            <doc xml:space="preserve">an array of #GParameter</doc>
            <array length="2" zero-terminated="0" c:type="GParameter*">
              <type name="GObject.Parameter" c:type="GParameter"/>
            </array>
          </parameter>
        </parameters>
      </constructor>

I have tried a ton of different ways to actually create an instance with no success...

    return GPlugin::PluginInfo.new(
        'ruby/ruby-basic-plugin',
        0x01020304,
        {:name => 'basic plugin'}
    )

Results in

/usr/lib/ruby/vendor_ruby/gir_ffi/struct_base.rb:26:in `copy_value_to_pointer': undefined method `to_ptr' for [:name, "basic plugin"]:Array (NoMethodError)
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:87:in `block in from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each_with_index'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:19:in `from_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:83:in `from_enumerable'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:69:in `from'
    from (eval):6:in `new'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/class_base.rb:37:in `setup_and_call'
    from (eval):2:in `new'
    from basic.rb:6:in `gplugin_query'
    from basic.rb:28:in `<main>'
    return GPlugin::PluginInfo.new(
        'ruby/ruby-basic-plugin',
        0x01020304,
        :name => 'basic plugin'
    )

Results in

/usr/lib/ruby/vendor_ruby/gir_ffi/struct_base.rb:26:in `copy_value_to_pointer': undefined method `to_ptr' for [:name, "basic plugin"]:Array (NoMethodError)
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:87:in `block in from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each_with_index'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:19:in `from_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:83:in `from_enumerable'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:69:in `from'
    from (eval):6:in `new'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/class_base.rb:37:in `setup_and_call'
    from (eval):2:in `new'
    from basic.rb:6:in `gplugin_query'
    from basic.rb:28:in `<main>'
    return GPlugin::PluginInfo.new(
        :id=>'ruby/ruby-basic-plugin',
        :abi_version=>0x01020304,
        :name => 'basic plugin'
    )

Results in

(eval):1:in `new': wrong number of arguments (1 for 3) (ArgumentError)
    from /usr/lib/ruby/vendor_ruby/gir_ffi/class_base.rb:37:in `setup_and_call'
    from (eval):2:in `new'
    from basic.rb:6:in `gplugin_query'
    from basic.rb:28:in `<main>'
    return GPlugin::PluginInfo.new(
        'ruby/ruby-basic-plugin',
        0x01020304,
        ["name", "basic plugin"]
    )

Results in

/usr/lib/ruby/vendor_ruby/gir_ffi/struct_base.rb:26:in `copy_value_to_pointer': undefined method `to_ptr' for "name":String (NoMethodError)
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:87:in `block in from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each_with_index'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:19:in `from_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:83:in `from_enumerable'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:69:in `from'
    from (eval):6:in `new'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/class_base.rb:37:in `setup_and_call'
    from (eval):2:in `new'
    from basic.rb:6:in `gplugin_query'
    from basic.rb:28:in `<main>'

And

    return GPlugin::PluginInfo.new(
        'ruby/ruby-basic-plugin',
        0x01020304,
        [{:name => "basic plugin"}]
    )

Results in

/usr/lib/ruby/vendor_ruby/gir_ffi/struct_base.rb:26:in `copy_value_to_pointer': undefined method `to_ptr' for {:name=>"basic plugin"}:Hash (NoMethodError)
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:87:in `block in from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `each_with_index'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:86:in `from_struct_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/in_pointer.rb:19:in `from_array'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:83:in `from_enumerable'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/sized_array.rb:69:in `from'
    from (eval):6:in `new'
    from /usr/lib/ruby/vendor_ruby/gir_ffi/class_base.rb:37:in `setup_and_call'
    from (eval):2:in `new'
    from basic.rb:6:in `gplugin_query'
    from basic.rb:28:in `<main>'

Hi @grimmy,

GirFFI currently doesn't automatically convert hashes to GParameters. This means you would have to provide an array of GObject::Parameter objects, which is a rather tedious affair. For most classes this is not a problem, since the class-specific constructors don't take GParameters.

Can you tell me which other languages you have tried and how you would call new there?

Python that's using py-gobject

from gi.repository import GPlugin

def gplugin_query():
    return GPlugin.PluginInfo(
        id='gplugin/python-basic-plugin',
        abi_version=0x01020304,
        name='basic plugin',
        authors=['author1'],
        category='test',
        version='version',
        license_id='license',
        summary='summary',
        website='website',
        description='description',
    )

def gplugin_load(plugin):
    return True


def gplugin_unload(plugin):
    return True

print gplugin_query()
$ python basic.py 
<PluginInfo object at 0x7f8849436b40 (GPluginPluginInfo at 0x19f50a0)>

Lua using lgi

local lgi = require 'lgi'
local GPlugin = lgi.GPlugin

function gplugin_query()
    return GPlugin.PluginInfo {
        id = "gplugin/lua-basic-plugin",
        abi_version = 0x01020304,
        name = "basic plugin",
        category = "test",
        version = "version",
        license_id = "license",
        summary = "summary",
        description = "description",
        authors = { "author1" },
        website = "website"
    }
end

function gplugin_load(plugin)
    return true
end

function gplugin_unload(plugin)
    return true
end

print(gplugin_query())
$ lua basic.lua 
lgi.obj 0x148d890:GPlugin.PluginInfo(GPluginPluginInfo)

Thanks! That'll help me figure out how this should work in GirFFI.

For the record, it looks like the default constructor for lua and python just call g_object_new using a dictionary as the params. I added gplugin_plugin_info_new and gplugin_plugin_info_newv to try and make gir-ffi figure it out.

Well, just started looking at this again with someone and turns out it's working now, so yay! :-D