Portmidi header change breaks old code
Opened this issue · 10 comments
Hello, I work on maintaining pygame-ce, which uses portmidi for the pygame.midi
module
We've recently seen compiles start to fail in our autogenerated pypm.c
src_c/pypm.c:7236:81: error: incompatible function pointer types passing 'PtTimestamp (*)(void)' (aka 'int (*)(void)') to parameter of type 'PmTimeProcPtr' (aka 'int (*)(void *)') [-Wincompatible-function-pointer-types]
7236 | __pyx_v_err = Pm_OpenInput((&__pyx_v_self->midi), __pyx_t_2, NULL, __pyx_t_3, (&Pt_Time), NULL);
| ^~~~~~~~~~
/data/data/com.termux/files/usr/include/portmidi.h:399:31: note: passing argument to parameter 'time_proc' here
399 | PmTimeProcPtr time_proc,
| ^
1 error generated.
From my research, it looks like the function Pt_Time
used to be compatible with PmTimeProcPtr
, but now it is not.
I think this broke here: 64314cc#diff-a92ece8a1b564c101a59ed27031b813d53906570f99c4f12bd09ac5f3b65fd82L79-R84
Apparently, in C, a function declaration with no args does not mean the function has no args-- https://stackoverflow.com/a/5929736/13816541. So Pt_Time() and Pt_Time(void) are different.
We have a PR to insert a shim to make Pt_Time
used to be compatible with PmTimeProcPtr
on any version of portmidi, but I wanted to send in this bug report as an FYI.
I don't see the PR - maybe that was to fix pypm.c? One way to handle this is to cast Pt_Time to PmTimeProcPtr if you want to use it as a PmTimeProcPtr. Pt_Time does not require a parameter. I'm not too clear on whether this is still correct C or it just works (it was certainly correct on earlier C compilers). But, it's certainly not the cleanest approach. Changing the type signature of Pt_Time is really an incompatible change, but I think it's the right thing to do. It means any direct call to Pt_Time should change to Pt_Time(NULL).
Here's the PR on our end if you're curious about our fix: pygame-community/pygame-ce#2863
One way to handle this is to cast Pt_Time to PmTimeProcPtr if you want to use it as a PmTimeProcPtr
This was my first instinct too, but I couldn't figure out how to generate that C code out of Cython (the Python-esque language that generates into pypm.c)
We still get an error when trying to case Pt_Time
to PmTimeProcPtr
because the typedef of PmTimeProcPtr
says it needs a void*
argument
https://github.com/PortMidi/portmidi/blob/master/pm_common/portmidi.h#L339
You tried (PmTimeProcPtr) &Pt_Time
?
Yes, here's exactly what the code looks like:
err = Pm_OpenInput(&(self.midi), input_device, NULL, buffersize,
<PmTimeProcPtr>&Pt_Time, NULL)
And the compiler error
Error compiling Cython file:
------------------------------------------------------------
...
cdef PmError err
self.device = input_device
self.debug = 0
err = Pm_OpenInput(&(self.midi), input_device, NULL, buffersize,
<PmTimeProcPtr>&Pt_Time, NULL)
^
------------------------------------------------------------
C:\Users\andre\Projects\pygame-ce\src_c\cython\pygame\pypm.pyx:545:27: Cannot assign type 'PmTimeProcPtr' (alias of 'PmTimestamp (*)(void *) noexcept') to 'long (*)(void) noexcept'
This is not C or C++. I guess you are saying the solution for C programs: (PmTimeProcPtr) &PtTime
does not have an equivalent in Cython.
That is the Cython equivalent, the <PmTimeProcPtr>&Pt_Time
I'll try to manually compile the cython without the cast, then do the C-style cast in the C manually to see what happens
Ok, yeah, manually casting it in the generated C does fix the problem. I've opened an issue with cython to report a potential bug in casting here
Thanks for doing the test. Although it does sound like cython should work differently, I now also think Pt_Time should match PmTimeProcPtr and I should change all PmTimeProcPtr to PtTimeProcPtr so that the type of the time function will be declared in porttime.h. That will eliminate some casts, enable more type checking, but probably break something else. It shouldn't affect any binaries though.