Bug 40290 - Vala Bindings cause errors
Summary: Vala Bindings cause errors
Status: RESOLVED FIXED
Alias: None
Product: PulseAudio
Classification: Unclassified
Component: misc (show other bugs)
Version: unspecified
Hardware: x86 (IA32) Linux (All)
: medium normal
Assignee: pulseaudio-bugs
QA Contact: pulseaudio-bugs
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 40193
  Show dependency treegraph
 
Reported: 2011-08-22 09:16 UTC by bsquared
Modified: 2011-09-11 06:24 UTC (History)
3 users (show)

See Also:
i915 platform:
i915 features:


Attachments
Small vala example using introspection api (1.30 KB, text/x-vala)
2011-08-30 23:10 UTC, Arun Raghavan
Details
modified attachment 50744 (1.52 KB, text/x-vala)
2011-09-05 08:31 UTC, bsquared
Details

Description bsquared 2011-08-22 09:16:10 UTC
I reported this through Vala list and was told it was due to bindings.

I ran into a couple of issues regarding structs.  

1. When using a struct an error is raised in the c code when attempting to access the "built-in" to_string() method for an element.

                 Context.State state = ctx.get_state();
                 print (state.to_string());

/.../Source/vala/pulse-device-chooser/src/main.c:160:47: error:
‘PA_CONTEXT_TYPE_STATE’ undeclared (first use in this function)

2. What is the correct method to copy a struct?  Attempting to copy
struct by assignment to variable, or Memory.copy causes "undefined
reference to `pulse_audio_sink_info_copy'" errors in c code.

where i & si are type PulseAudio.SinkInfo

               context.get_sink_info_by_index (index, (context, i, eol) => {
                       Memory.copy(&i, &si, sizeof(SinkInfo));
                       si = i;
               });



3. Attempting to box struct from pkg in an ArrayList causes an error
in c code similar to question 1.
Gee.ArrayList<SinkInfo?> sink_info = new Gee.ArrayList<SinkInfo?>();

main.c:643:31: error: ‘PULSE_AUDIO_TYPE_SINK_INFO’ undeclared (first
use in this function)


See attachment for complete output.
Comment 1 Tanu Kaskinen 2011-08-22 10:03:38 UTC
I'm clueless about Vala, so I can't help much, but I noticed that you're copying (or at least it looks like that to someone who doesn't know Vala) SinkInfo objects. If that means that your code somehow relies on the size of the pa_sink_info struct, your code is broken, because its size can grow in future libpulse versions without notice. We don't consider it an ABI breakage if fields are added to the end of the struct.
Comment 2 bsquared 2011-08-22 11:23:24 UTC
(In reply to comment #1)

Thanks, I should have removed that code snippet from this bug report.

That code was in reference to a question on how to copy a struct in Vala, and it turns out that while that code is incorrect, the bindings are as well.
Comment 3 Arun Raghavan 2011-08-23 21:36:50 UTC
The failure occurs because to_string() is generated with the assumption that the enum is a GEnum. We either need to add a manual to_string override for all enums (which is doable, just painful), or you need to do the switch-case yourself.
Comment 4 bsquared 2011-08-24 07:12:59 UTC
(In reply to comment #3)
> The failure occurs because to_string() is generated with the assumption that
> the enum is a GEnum. We either need to add a manual to_string override for all
> enums (which is doable, just painful), or you need to do the switch-case
> yourself.

The Vala documentation sets the expectation level by stating that the to_string() method is built in.  If the code were not added, then I think it should be clearly documented. 

This was posted on the Vala list regarding list items 1 and 3.
1.
>> /.../Source/vala/pulse-device-chooser/src/main.t c:160:47: error:
>> ‘PA_CONTEXT_TYPE_STATE’ undeclared (first use in this function)
> Looks like a missing CCode annotation in the VAPI. Depending on whether
> Context.State has a GType
>
> [CCode (type_id = "pa_context_state_get_type ()")]
>
> or
>
> [CCode (has_type_id = false)]

3 . 
>> main.c:643:31: error: ‘PULSE_AUDIO_TYPE_SINK_INFO’ undeclared (first
>> use in this function)
> The solution is the same as above... either specify the correct type id
> or set has_type_id = false for SinkInfo.
Comment 5 bsquared 2011-08-24 08:43:34 UTC
In reference to list item 2.

I started with this simple code:

	public SinkInfo devinfo_to_sinkinfo (DeviceInfo* di) {
		uint32 index = di->index;
		SinkInfo si = SinkInfo ();
		context.get_sink_info_by_index (index, (context, i, eol) => {
			if (eol > 0) {return;}
			sinkinfo_copy(i, &si); // dummy method
		});

		return si;
	}

which generates the following c code:

static void _lambda0_ (pa_context* context, pa_sink_info* i, gint eol, Block1Data* _data1_) {
	Main * self;
	self = _data1_->self;
	g_return_if_fail (context != NULL);
	if (eol > 0) {
		return;
	}
	main_sinkinfo_copy (self, i, &_data1_->si);
}


static void __lambda0__pa_contextsinkinfocb (pa_context* c, pa_sink_info* i, gint eol, gpointer self) {
	_lambda0_ (c, i, eol, self);
}

void main_devinfo_to_sinkinfo (Main* self, MainDeviceInfo* di, pa_sink_info* result) {
	Block1Data* _data1_;
	guint32 index;
	pa_operation* _tmp0_ = NULL;
	pa_operation* _tmp1_;
	pa_sink_info _tmp2_ = {0};
	pa_sink_info _tmp3_;
	g_return_if_fail (self != NULL);
	_data1_ = g_slice_new0 (Block1Data);
	_data1_->_ref_count_ = 1;
	_data1_->self = g_object_ref (self);
	index = (*di).index;
	memset (&_data1_->si, 0, sizeof (pa_sink_info));
	_tmp0_ = pa_context_get_sink_info_by_index (self->priv->context, index, __lambda0__pa_contextsinkinfocb, _data1_);
	_tmp1_ = _tmp0_;
	_pa_operation_unref0 (_tmp1_);
	pulse_audio_sink_info_copy (&_data1_->si, &_tmp2_);
	_tmp3_ = _tmp2_;
	*result = _tmp3_;
	block1_data_unref (_data1_);
	_data1_ = NULL;
	return;
}


And compiling produces this output:

[...]
main.o: In function `main_devinfo_to_sinkinfo':
/home/bwinfrey/Source/vala/pulse-device-chooser/src/main.c:461: undefined reference to `pulse_audio_sink_info_copy'
main.o: In function `block1_data_unref':
/home/bwinfrey/Source/vala/pulse-device-chooser/src/main.c:423: undefined reference to `pulse_audio_sink_info_destroy'
[...]
collect2: ld returned 1 exit status
make[2]: Leaving directory `/home/bwinfrey/Source/vala/pulse-device-chooser/src'
make[1]: Leaving directory `/home/bwinfrey/Source/vala/pulse-device-chooser'
make[2]: *** [pulse_device_chooser] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

compilation end with exit status 2
Comment 6 Arun Raghavan 2011-08-30 23:09:03 UTC
Thanks a lot for following this up -- we needed to add a has_type_id=false to all our structs, classes and enums for correctness because of recent changes in vala. I've pushed a fix here:

http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=fb107fc77056b6bfcc7902d3ee048c271c212145

Now going back to your code, you're trying to make a copy of the SinkInfo struct, which is not something you should be doing. Could you explain why you need the copy? Would it be sufficient to copy the fields you need?
Comment 7 Arun Raghavan 2011-08-30 23:10:32 UTC
Created attachment 50744 [details]
Small vala example using introspection api

For reference, I'm attaching a small Vala example that uses introspection API and seems to work fine here.
Comment 8 bsquared 2011-08-31 13:52:34 UTC
(In reply to comment #6)

> 
> Now going back to your code, you're trying to make a copy of the SinkInfo
> struct, which is not something you should be doing. Could you explain why you
> need the copy? Would it be sufficient to copy the fields you need?

The code in comment #5 demonstrates that the code generated by Vala attempts to copy the struct when struct is passed as a parameter or returned by the method.

I really don't need to copy the struct at all.  It was for experimental/discovery purposes.

(In reply to comment #7)

Thanks. I will test and report back if it doesn't work after I apply update from comment #6.
Comment 9 Colin Guthrie 2011-09-05 01:37:03 UTC
I guess this works fine now and can be closed?
Comment 10 bsquared 2011-09-05 08:03:45 UTC
(In reply to comment #9)
> I guess this works fine now and can be closed?

I haven't been able to test the changes in comment #6.  I will update my vapi files to test.

I don't know if comment #5 and comment #8 are addressed or even considered issues or not. ie.
 
if passing the struct as an argument or returning it from a function the  code will generate 'pulse_audio_sink_info_copy (&_data1_->si, &_tmp2_);' see comments #5 and #8.
Comment 11 bsquared 2011-09-05 08:29:31 UTC
(In reply to comment #10)
> (In reply to comment #9)
> > I guess this works fine now and can be closed?
> 
> I haven't been able to test the changes in comment #6.  I will update my vapi
> files to test.
> 
> I don't know if comment #5 and comment #8 are addressed or even considered
> issues or not. ie.
> 
> if passing the struct as an argument or returning it from a function the  code
> will generate 'pulse_audio_sink_info_copy (&_data1_->si, &_tmp2_);' see
> comments #5 and #8.

I tested with the sample code attachment ( slightly modified to include #5 type scenario ) and there were no issues.
Comment 12 bsquared 2011-09-05 08:31:23 UTC
Created attachment 50923 [details]
modified attachment 50744 [details] 

Adding the modified file as an attachment.
Comment 13 Arun Raghavan 2011-09-11 06:24:51 UTC
Great. Thanks for following all this up!


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.