Compiling Ruby Inline C code - resolving errors


#1

I am trying to get this Ruby inline C code http://pastie.org/2825882 to
work. The code works in vanilla C, but here I get errors and warnings.
What causes this error?

./backtrack_inline.rb:67: error: lvalue required as unary ‘&’ operand

Also, why do I get the following error?

./backtrack_inline.rb:73: error: too few arguments to function
‘backtrack’

Inspecting the resulting C code ( http://pastie.org/2826036) I fail to
see anything wrong with the arguments. But I do also get the following
warnings:

./backtrack_inline.rb:73: warning: passing argument 1 of ‘backtrack’
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 2 of ‘backtrack’
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 3 of ‘backtrack’
makes integer from pointer without a cast

Cheers,

Martin


#2

It is generally best to send these types of questions to a more targeted
medium, like writing the author directly or filing a support ticket on
github.

On Nov 8, 2011, at 00:04 , Martin H. wrote:

I am trying to get this Ruby inline C code http://pastie.org/2825882 to
work. The code works in vanilla C, but here I get errors and warnings.
What causes this error?

./backtrack_inline.rb:67: error: lvalue required as unary ‘&’ operand

This one took me a bit…

#define StringValuePtr(v) rb_string_value_ptr(&(v))

and you’re using it in:

char* s = StringValuePtr(rb_iv_get(self, "@seq"));

so you’re essentially doing:

char* s = rb_string_value_ptr(&rb_iv_get(self, "@seq"));

which you can’t really do in C.

Also, why do I get the following error?

./backtrack_inline.rb:73: error: too few arguments to function
‘backtrack’

Because you’re passing too few arguments to the function (6 to 7 arity
function):

static
VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm,
VALUE _ins, VALUE _del)

vs:

backtrack(ss, s + 1, p + 1, mm - 1, ins, del)))

Since you’re not actually using self for anything, there is no reason
for this to be a registered method. You might want to add this to the
prefix section.

Inspecting the resulting C code ( http://pastie.org/2826036) I fail to
see anything wrong with the arguments. But I do also get the following
warnings:

./backtrack_inline.rb:73: warning: passing argument 1 of ‘backtrack’
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 2 of ‘backtrack’
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 3 of ‘backtrack’
makes integer from pointer without a cast

This is simply because of the above lack of self, I assume.

I changed your code (with the above) like so:

# above w/ prefixens
builder.add_static "id_seq", 'rb_intern("@seq")', "ID"

# in patscan:
VALUE seq = rb_ivar_get(self, id_seq);
char* s = StringValuePtr(seq);

and got ‘14’ as the output (off by 1?).


#3

I was in doubt whether to use:

char* s = StringValuePtr(rb_iv_get(self, “@seq”));

or

char* s = RSTRING_PTR(rb_iv_get(self, “@seq”))

I see now that the first is plain wrong, but what about the latter? When
is that used?

I tried to apply the suggested changes, but the C code still have “VALUE
self” as first argument in the functions. How did you get rid of that?


#4

On Nov 8, 2011, at 12:10 PM, Martin H. wrote:

I tried to apply the suggested changes, but the C code still have “VALUE
self” as first argument in the functions. How did you get rid of that?

Did you change line 38 in http://pastie.org/2825882 from

“builder.c %{” to “builder.prefix %{”

?

If you don’t define backtrack as an instance method, self will not be
expected to be passed as first argument.


#5

On Nov 8, 2011, at 03:10 , Martin H. wrote:

I was in doubt whether to use:

char* s = StringValuePtr(rb_iv_get(self, “@seq”));

or

char* s = RSTRING_PTR(rb_iv_get(self, “@seq”))

I see now that the first is plain wrong, but what about the latter? When
is that used?

No… it is NOT plain wrong. Trying to use the result of a return value
as an lvalue is plain wrong. By putting it in it’s own variable, you can
use StringValuePtr just fine (and should).

I tried to apply the suggested changes, but the C code still have “VALUE
self” as first argument in the functions. How did you get rid of that?

As Sylvester pointed out, you missed my suggestion to make that function
a prefixed function.


#6

On Nov 8, 2011, at 06:50 , Martin H. wrote:

Sylvester K. wrote in post #1030842:

How could I know that bulder.c -> builder.prefix changed the function an
instance method to a “function”?

Well, first, because I showed you:

Because you’re passing too few arguments to the function (6 to 7 arity
function):

static
VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm, VALUE
_ins, VALUE _del)

vs:

backtrack(ss, s + 1, p + 1, mm - 1, ins, del)))

Since you’re not actually using self for anything, there is no reason for this
to be a registered method. You might want to add this to the prefix section.

I am pretty desperate for some reading

  • and examples - on this matter! Something modern (i. e. Ruby 1.9) and
    something that is about inline C and not necessarily all of Ruby’s API.

If you find the documentation insufficient in some way, please file a
ticket. I can only improve what I know about.

false
I don’t. Here is what I wound up with:

#!/usr/bin/env ruby

require ‘pp’
require ‘inline’

class Scan
def initialize(seq)
@seq = seq
end

inline do |builder|
builder.prefix %{
#define MATCH(A,B) ((equal[(A)] & equal[(B)]) != 0)
}

builder.add_static "id_seq", 'rb_intern("@seq")', "ID"

builder.prefix %{
  int equal[256] = {
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 1,14, 4,11, 0, 0, 8, 7, 0, 0,10, 0, 5,15, 0,
      0, 0, 9,12, 2, 2,13, 3, 0, 6, 0, 0, 0, 0, 0, 0,
      0, 1,14, 4,11, 0, 0, 8, 7, 0, 0,10, 0, 5,15, 0,
      0, 0, 9,12, 2, 2,13, 3, 0, 6, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
}

# ss is the start of the string, used only for reporting the match 

endpoints.
builder.prefix %{
int backtrack(char* ss, char* s, char* p, int mm, int ins, int
del)
{
int r = 0;

      while (*s && MATCH(*s, *p)) ++s, ++p;    // OK to always match 

longest segment

      if (!*p)
          return (s - ss) - 1;
      else
      {
          if (mm && *s && *p && (r = backtrack(ss, s + 1, p + 1, mm 
  • 1, ins, del))) return r;
    if (ins && *s && (r = backtrack(ss, s + 1, p, mm, ins

  • 1, del))) return r;
    if (del && *p && (r = backtrack(ss, s, p + 1, mm,
    ins, del - 1))) return r;
    }

        return 0;
    }
    

    }

    Find all occurrences of p starting at any position in s, with at

most
# mm mismatches, ins insertions and del deletions.
builder.c %{
int patscan(char* p, int mm, int ins, int del)
{
VALUE seq = rb_ivar_get(self, id_seq);
char* s = StringValuePtr(seq);
char* ss;
int nnd;

      for (ss = s; *s; ++s)
      {
          nnd = backtrack(ss, s, p, mm, ins, del);

          if (nnd)
             return nnd;
      }
   }
}

end
end

seq = “tcatcgagtcatcgatcgatcgatcgatcga”
pat = “gtcatcga”

scanner = Scan.new(seq)

puts scanner.patscan(pat, 0, 0, 0)


#7

Sylvester K. wrote in post #1030842:

How could I know that bulder.c -> builder.prefix changed the function an
instance method to a “function”? I am pretty desperate for some reading

  • and examples - on this matter! Something modern (i. e. Ruby 1.9) and
    something that is about inline C and not necessarily all of Ruby’s API.

I changed the code and cleaned up a few things:

Ruby code: http://pastie.org/2831055
Inline code: http://pastie.org/2831058

Now I get a warning - and the wrong output:

/Users/maasha/.ruby_inline/Inline_Scan_5319.c: In function ‘backtrack’:
/Users/maasha/.ruby_inline/Inline_Scan_5319.c:38: warning: implicit
conversion shortens 64-bit value into a 32-bit value
false

Cheers,

Martin

On Nov 8, 2011, at 12:10 PM, Martin H. wrote:

I tried to apply the suggested changes, but the C code still have “VALUE
self” as first argument in the functions. How did you get rid of that?

Did you change line 38 in http://pastie.org/2825882 from

“builder.c %{” to “builder.prefix %{”

?

If you don’t define backtrack as an instance method, self will not be
expected to be passed as first argument.


#8

On Nov 9, 2011, at 10:25 AM, Martin H. wrote:

OK, it works now. However, I still get a warning:

warning: implicit conversion shortens 64-bit value into a 32-bit
value

The offending line is return (s - ss) - 1; where I expect an int. How
to make this portable?

IIRC s and ss are pointers to a (the same?) string, right? If they are,
then this difference here will easily fit into 32bit so you could cast
to int explicitly:

return (int)((s - ss) - 1)

Or you could change the function definition to return a long instead of
int and return a 64bit value on 64bit systems.


#9

OK, it works now. However, I still get a warning:

warning: implicit conversion shortens 64-bit value into a 32-bit 

value

The offending line is return (s - ss) - 1; where I expect an int. How
to make this portable?

And I’d like to contribute with suggestions and ideas. Where is the best
place? Github, rubyforge, a mailing list?

Many thanks!

Martin


#10

IIRC s and ss are pointers to a (the same?) string, right? If they are,
then this difference here will easily fit into 32bit so you could cast
to int explicitly:

return (int)((s - ss) - 1)

Or you could change the function definition to return a long instead of
int and return a 64bit value on 64bit systems.

Yes, that will do. Thanks!

Martin


#11

On Nov 9, 2011, at 01:25 , Martin H. wrote:

OK, it works now. However, I still get a warning:

warning: implicit conversion shortens 64-bit value into a 32-bit
value

The offending line is return (s - ss) - 1; where I expect an int. How
to make this portable?

It shouldn’t expect an int. You’re returning a measurement. They can’t
be negative. You should be returning a size_t if anything.

And I’d like to contribute with suggestions and ideas. Where is the best
place? Github, rubyforge, a mailing list?

All my stuff is mirrored to github.