error: use of undeclared identifier 'LP_c_uint' - cppyy

I am using cppyy in my project to call C APIs.
I get below error log captured by capfd plugin in pytest, when an exception happens:
input_line_33:2:11: error: use of undeclared identifier 'LP_c_uint'
(sizeof (LP_c_uint))
It is coming from below code block, specifically logger.error() call:
try:
....
except Exception as e:
out, err = capfd.readouterr()
if err:
logger.error(err)
Now, if I grep my python source code, I don't any hits to 'LP_c_uint'.
Any pointers on how to debug this (like what may be causing this)?
Edit:
simple reproducer:
from ctypes import c_uint32, pointer, byref
import cppyy
from cppyy import sizeof
cppyy.cppdef(
"""
void func(uint32_t *param) {
std::cout << "param: " << *param << std::endl;
}
"""
)
if __name__ == "__main__":
param = pointer(c_uint32(17))
cppyy.gbl.func(param)
print(sizeof(param))
Output:
param: 17
input_line_22:2:11: error: use of undeclared identifier 'LP_c_uint'
(sizeof (LP_c_uint))
^
0

Yes, using ctypes.sizeof would solve it. I see the need for using ctypes.c_uint32 here (although using ctypes.pointer is not necessary) as there is no way of creating a pointer type from cppyy.gbl.uint32_t (which is basically Python's int, so internals to take a pointer to are not exposed).
cppyy.sizeof is now changed to forward to ctypes.sizeof as necessary. That'll make your code work and will be part of next release. As a current workaround, you can do something similar. For example:
def my_sizeof(tt):
try:
return ctypes.sizeof(tt)
except TypeError:
pass
return cppyy.sizeof(tt)

Related

Using a default value for a function parameter which depends of other parameter

I'd like to create an script which takes an input file and optionally an output file. When you don't pass an output file, the script uses the same filename as the input but with the extension changed. I don't know how to write a default parameter which changes the extension.
#!/usr/bin/env raku
unit sub MAIN(
Str $input where *.IO.f, #= input file
Str $output = $input.IO.extension("txt"), #= output file
Bool :$copy, #= copy file
Bool :$move, #= move file
);
Unfortunately that doesn't work:
No such method 'IO' for invocant of type 'VMNull'
in block <unit> at ./copy.raku line 5
How can I do something like that?
error message is less than awesome but program not working is expected because you have in the signature
Str $output = $input.IO.extension("txt")
but the right hand side returns an IO::Path object with that extension but $output is typed to be a String. That is an error:
>>> my Str $s := "file.csv".IO.extension("txt")
Type check failed in binding; expected Str but got IO::Path (IO::Path.new("file.t...)
in block <unit> at <unknown file> line 1
>>> sub fun(Str $inp, Str $out = $inp.IO.extension("txt")) { }
&fun
>>> fun "file.csv"
Type check failed in binding to parameter '$out'; expected Str but got IO::Path (IO::Path.new("file.t...)
in sub fun at <unknown file> line 1
in block <unit> at <unknown file> line 1
Sometimes compiler detects incompatible default values:
>>> sub yes(Str $s = 3) { }
===SORRY!=== Error while compiling:
Default value '3' will never bind to a parameter of type Str
------> sub yes(Str $s = 3⏏) { }
expecting any of:
constraint
but what you have is far from a literal, so runtime detection.
To fix it, you can either
change to Str() $output = $inp.IO.extension("txt") where Str() means "accept Any object and then cast it to Str". So $output will end up being a string like "file.txt" available in MAIN.
similar alternative: Str $output = $inp.IO.extension("txt").Str but it's repetitive in Str.
change to IO::Path() $output = $inp.IO.extension("txt"). Similarly, this casts to whatever recieved to an IO::Path object, so, e.g., you'll have "file.txt".IO available in $output. If you do this, you might want to do the same for $input as well for consistency. Since IO::Path objects are idempotent to .IO (in eqv sense), no other part of the code needs changing.

What's the minimum code required to make a NativeCall to the md_parse function in the md4c library?

Note: This post is similar, but not quite the same as a more open-ended questions asked on Reddit: https://www.reddit.com/r/rakulang/comments/vvpikh/looking_for_guidance_on_getting_nativecall/
I'm trying to use the md4c c library to process a markdown file with its md_parse function. I'm having no success, and the program just quietly dies. I don't think I'm calling it with the right arguments.
Documentation for the function is here: https://github.com/mity/md4c/wiki/Embedding-Parser%3A-Calling-MD4C
I'd like to at least figure out the minimum amount of code needed to do this without error. This is my latest attempt, though I've tried many:
use v6.d;
use NativeCall;
sub md_parse(str, int32, Pointer is rw ) is native('md4c') returns int32 { * }
md_parse('hello', 5, Pointer.new());
say 'hi'; # this never gets printed
md4c is a SAX-like streaming parser that calls your functions when it encounters markdown elements. If you call it with an uninitialised Pointer, or with an uninitialised CStruct then the code will SEGV when the md4c library tries to call a null function pointer.
The README says:
The main provided function is md_parse(). It takes a text in the
Markdown syntax and a pointer to a structure which provides pointers
to several callback functions.
As md_parse() processes the input, it calls the callbacks (when
entering or leaving any Markdown block or span; and when outputting
any textual content of the document), allowing application to convert
it into another format or render it onto the screen.
The function signature of md_parse is:
int md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata);
In order for md_parse() to work, you will need to:
define a native CStruct that matches the MD_PARSER type definition
create an instance of this CStruct
initialise all the function pointers with Raku functions that have the right function signature
call md_parse() with the initialised CStruct instance as the third parameter
The 4th parameter to md_parse() is void* userdata which is a pointer that you provide which gets passed back to you as the last parameter of each of the callback functions. My guess is that it's optional and if you pass a null value then you'll get called back with a null userdata parameter in each callback.
Followup
This turned into an interesting rabbit hole to fall down.
The code that makes it possible to pass a Raku sub as a callback parameter to a native function is quite complex and relies on MoarVM ops to build and cache the FFI callback trampoline. This is a piece of code that marshals the C calling convention parameters into a call that MoarVM can dispatch to a Raku sub.
It will be a sizeable task to implement equivalent functionality to provide some kind of nativecast that will generate the required callback trampoline and return a Pointer that can be assigned into a CStruct.
But we can cheat
We can use a simple C function to return the pointer to a generated callback trampoline as if it was for a normal callback sub. We can then store this pointer in our CStruct and our problem is solved. The generated trampoline is specific to the function signature of the Raku sub we want to call, so we need to generate a different NativeCall binding for each function signature we need.
The C function:
void* get_pointer(void* p)
{
return p;
}
Binding a NativeCall sub for the function signature we need:
sub get_enter_leave_fn(&func (uint32, Pointer, Pointer))
is native('./getpointer') is symbol('get_pointer') returns Pointer { * }
Initialising a CStruct attribute:
$!enter_block := get_enter_leave_fn(&enter_block);
Putting it all together:
use NativeCall;
enum BlockType < DOC QUOTE UL OL LI HR H CODE HTML P TABLE THEAD TBODY TR TH TD >;
enum SpanType < EM STRONG A IMG SPAN_CODE DEL SPAN_LATEXMATH LATEXMATH_DISPLAY WIKILINK SPAN_U >;
enum TextType < NORMAL NULLCHAR BR SOFTBR ENTITY TEXT_CODE TEXT_HTML TEXT_LATEXMATH >;
sub enter_block(uint32 $type, Pointer $detail, Pointer $userdata --> int32) {
say "enter block { BlockType($type) }";
}
sub leave_block(uint32 $type, Pointer $detail, Pointer $userdata --> int32) {
say "leave block { BlockType($type) }";
}
sub enter_span(uint32 $type, Pointer $detail, Pointer $userdata --> int32) {
say "enter span { SpanType($type) }";
}
sub leave_span(uint32 $type, Pointer $detail, Pointer $userdata --> int32) {
say "leave span { SpanType($type) }";
}
sub text(uint32 $type, str $text, uint32 $size, Pointer $userdata --> int32) {
say "text '{$text.substr(0..^$size)}'";
}
sub debug_log(str $msg, Pointer $userdata --> int32) {
note $msg;
}
#
# Cast functions that are specific to the required function signature.
#
# Makes use of a utility C function that returns its `void*` parameter, compiled
# into a shared library called libgetpointer.dylib (on MacOS)
#
# gcc -shared -o libgetpointer.dylib get_pointer.c
#
# void* get_pointer(void* p)
# {
# return p;
# }
#
# Each cast function uses NativeCall to build an FFI callback trampoline that gets
# cached in an MVMThreadContext. The generated callback code is specific to the
# function signature of the Raku function that will be called.
#
sub get_enter_leave_fn(&func (uint32, Pointer, Pointer))
is native('./getpointer') is symbol('get_pointer') returns Pointer { * }
sub get_text_fn(&func (uint32, str, uint32, Pointer))
is native('./getpointer') is symbol('get_pointer') returns Pointer { * }
sub get_debug_fn(&func (str, Pointer))
is native('./getpointer') is symbol('get_pointer') returns Pointer { * }
class MD_PARSER is repr('CStruct') {
has uint32 $!abi_version; # unsigned int abi_version
has uint32 $!flags; # unsigned int flags
has Pointer $!enter_block; # F:int ( )* enter_block
has Pointer $!leave_block; # F:int ( )* leave_block
has Pointer $!enter_span; # F:int ( )* enter_span
has Pointer $!leave_span; # F:int ( )* leave_span
has Pointer $!text; # F:int ( )* text
has Pointer $!debug_log; # F:void ( )* debug_log
has Pointer $!syntax; # F:void ( )* syntax
submethod TWEAK() {
$!abi_version = 0;
$!flags = 0;
$!enter_block := get_enter_leave_fn(&enter_block);
$!leave_block := get_enter_leave_fn(&leave_block);
$!enter_span := get_enter_leave_fn(&enter_span);
$!leave_span := get_enter_leave_fn(&leave_span);
$!text := get_text_fn(&text);
$!debug_log := get_debug_fn(&debug_log);
}
}
sub md_parse(str, uint32, MD_PARSER, Pointer is rw) is native('md4c') returns int { * }
my $parser = MD_PARSER.new;
my $md = '
# Heading
## Sub Heading
hello *world*
';
md_parse($md, $md.chars, $parser, Pointer.new);
The output:
./md4c.raku
enter block DOC
enter block H
text 'Heading'
leave block H
enter block H
text 'Sub Heading'
leave block H
enter block P
text 'hello '
enter span EM
text 'world'
leave span EM
leave block P
leave block DOC
In summary, it's possible. I'm not sure if I'm proud of this or horrified by it. I think a long-term solution will require refactoring the callback trampoline generator into a separate nqp op that can be exposed to Raku as a nativewrap style operation.

How do I take a reference to new?

Suppose I have the following code:
my constant #suits = <Clubs Hearts Spades Diamonds>;
my constant #values = 2..14;
class Card {
has $.suit;
has $.value;
# order is mnemonic of "$value of $suit", i.e. "3 of Clubs"
multi method new($value, $suit) {
return self.bless(:$suit, :$value);
}
}
It defines some suits and some values and what it means to be a card.
Now, to build a deck, I essentially need to take the cross product of the suits and the values and apply that to the constructor.
The naiive approach to do this, would of course be to just iterate with a loop:
my #deck = gather for #values X #suits -> ($v, $c) {
take Card.new($v, $c);
}
But this is Raku, we have a cross function that can take a function as an optional argument!, so of course I'm gonna do that!
my #deck = cross(#values, #suits, :with(Card.new));
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
... wait no.
What about this?
my #deck = cross(#values, #suits):with(Card.new);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
Still nothing. Reference maybe?
my #deck = cross(#values, #suits):with(&Card.new);
# ===SORRY!=== Error while compiling D:\Code\Raku/.\example.raku
# Illegally post-declared type:
# Card used at line 36
I read somewhere I can turn a function into an infix operator with []
my #deck = cross(#values, #suits):with([Card.new]);
# Unexpected named argument 'with' passed
# in block <unit> at .\example.raku line 36
That also doesn't work.
If classes are supposed to just be modules, shouldn't I then be able to pass a function reference?
Also why is it saying 'with' is that's unexpected? If I'm intuiting this right, what it's actually complaining about is the type of the input, rather than the named argument.
The error message is indeed confusing.
The :with parameter expects a Callable. Card.new is not a Callable. If you write it as :with( { Card.new($^number, $^suit) } ), it appears to work.
Note that I did not use $^value, $^suit, because they order differently alphabetically, so would produce the values in the wrong order. See The ^ twigil for more information on that syntax.
The error is LTA, this makes it a little bit better.
To get back to your question: you can find the code object that corresponds to Card.new with ^find_method. However, that will not work, as Card.new actually expects 3 arguments: the invocant (aka self), $value and $suit. Whereas the cross function will only pass the value and the suit.
The title of your question is “How do I take a reference to new?”, but that is not really what you want to do.
Raku being Raku, you can actually get a reference to new.
my $ref = Card.^lookup('new');
You can't use it like you want to though.
$ref(2,'Clubs'); # ERROR
The problem is that methods take a class or instance as the first argument.
$ref(Card, 2,'Clubs');
You could use .assuming to add it in.
$ref .= assuming(Card);
$ref(2,'Clubs');
But that isn't really any better than creating a block lambda
$ref = { Card.new( |#_ ) }
$ref(2,'Clubs');
All of these work:
cross( #values, #suits ) :with({Card.new(|#_)}) # adverb outside
cross( #values, #suits, :with({Card.new(|#_)}) ) # inside at end
cross( :with({Card.new(|#_)}), #values, #suits ) # inside at beginning
#values X[&( {Card.new(|#_)} )] #suits # cross meta-op with fake infix op
do {
sub new-card ($value,$suit) { Card.new(:$value,:$suit) }
#values X[&new-card] #suits
}
do {
sub with ($value,$suit) { Card.new(:$value,:$suit) }
cross(#values,#suits):&with
}

PyGObject, hex color to Gdk.RGBA

i found this code
gdk_rgba_parse ()
which should allow me to do something like
Gdk.RGBA.parse(#7F7F7F)
Error:
TypeError: unbound method parse() must be called with RGBA instance as first argument (got str instance instead)
using the RGBA color ( in percent, from 0 to 1 )
Docs:
https://developer.gnome.org/gdk3/stable/gdk3-RGBA-Colors.html#gdk-rgba-parse
http://www.crategus.com/books/cl-cffi-gtk/pages/gdk_fun_gdk-rgba-parse.html
But I'm kinda lost, i struggle to translate from C to PyGOBject and understanding the arguments of the function.. any help would be appreciated!
Since i didn't find the right solution, i made this converter:
def hex_to_rgba(value):
value = value.lstrip('#')
if len(value) == 3:
value = ''.join([v*2 for v in list(value)])
(r1,g1,b1,a1)=tuple(int(value[i:i+2], 16) for i in range(0, 6, 2))+(1,)
(r1,g1,b1,a1)=(r1/255.00000,g1/255.00000,b1/255.00000,a1)
return (r1,g1,b1,a1)
It works..
The function requires an instance of a GdkRGBA struct:
gboolean
gdk_rgba_parse (GdkRGBA *rgba,
const gchar *spec);
This translates to Python as a method on a Gdk.RGBA instance which mutates the structs contents:
color = Gdk.RGBA()
color.parse('#7F7F7F')
color.to_string() # 'rgb(127,127,127)'
It's not a very nice API for Python but every once in a while you have to deal with these kind of things with introspection based bindings. lazka's docs should be more helpful than the C ones:
http://lazka.github.io/pgi-docs/#Gdk-3.0/structs/RGBA.html#Gdk.RGBA.parse

Is g++ 4.5.3 broken when it comes to pointers to lamba functions?

I was trying out lambda functions and making a jump table to execute them, but I found g++ didn't recognize the type of the lambda function such that I could assign them to an array or tuple container.
One such attempt was this:
auto x = [](){};
decltype(x) fn = [](){};
decltype(x) jmpTable[] = { [](){}, [](){} };
On compilation I get these errors:
tst.cpp:53:27: error: conversion from ‘main()::<lambda()>’ to non-scalar type ‘main()::<lambda()>’ requested
tst.cpp:54:39: error: conversion from ‘main()::<lambda()>’ to non-scalar type ‘main()::<lambda()>’ requested
Hmmmm, can't convert from type A to non-scalar type A? What's that mean? o.O
I can use std::function to get this to work, but a problem with that is it doesn't seem to work with tuple:
function<void()> jmpTable[] = [](){}; // works
struct { int i; function<void()>> fn; } myTuple = {1, [](){}}; // works
tuple<int, function<void()>> stdTuple1 = {1, [](){}}; // fails
tuple<int, function<void()>> stdTuple2 = make_tuple(1, [](){}); // works
tst.cpp:43:58: error: converting to ‘std::tuple<int, std::function<void()> >’ from initializer list would use explicit constructor ‘std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = int, _U2 = main()::<lambda()>, _T1 = int, _T2 = std::function<void()>]’
Constructor marked explicit? Why?
So my question is if I am doing something invalid or is this version just not quite up to the task?
Hmmmm, can't convert from type A to non-scalar type A? What's that mean? o.O
No, that's not a conversion to the same type. Despite having identical bodies, the different lambdas have different types. Newer versions of GCC make this clearer, and give the error message:
error: conversion from '__lambda1' to non-scalar type '__lambda0' requested
clang does even better:
error: no viable conversion from '<lambda at test.cc:2:18>' to 'decltype(x)' (aka '<lambda at test.cc:1:10>')
I can use std::function to get this to work, but a problem with that is it doesn't seem to work with tuple:
It does (with 4.5.4, at least, I don't have 4.5.3 to test), but your initialisation isn't quite right.
tuple<int, function<void()>> stdTuple1 {1, [](){}}; // lose the = to initialise stdTuple1 directly
I'm not sure about the state of n3043 in 4.5.3, but you should be able to use function pointer conversion. If I'm not misunderstanding your usage intentions, this may work for you;
void (*x)();
decltype(x) fn = [](){};
decltype(x) jmpTable[] = { [](){}, [](){} };