Sharing constants between C and Ruby code

Hello,

I'm new to ruby, but fairly experienced in C. I am using Ruby on Rails
to chat to a postgres database. I have some C functions that I can run
in the database backend. I would like to use constants defined in C
header files, e.g "#define MY_CONSTANT 100" within ruby code. I know I
can similarly define a constant in ruby, i.e. "MY_CONSTANT=100", but
given that I have quite a few of these, and synchronising the two files
could become tricky, is there some (preferably simple) clever way/hack
that I can define constants in a single file and use them both in C and
in Ruby?

Thanks,
Nat

···

--
Posted via http://www.ruby-forum.com/.

Hello,

I'm new to ruby, but fairly experienced in C. I am using Ruby on Rails
to chat to a postgres database. I have some C functions that I can run
in the database backend. I would like to use constants defined in C
header files, e.g "#define MY_CONSTANT 100" within ruby code. I know I
can similarly define a constant in ruby, i.e. "MY_CONSTANT=100", but
given that I have quite a few of these, and synchronising the two files
could become tricky, is there some (preferably simple) clever way/hack
that I can define constants in a single file and use them both in C and
in Ruby?

I don't see how you'd share C preprocessor constants between Ruby and
C, since they're not available at runtime, unless you run the C
preprocessor on both Ruby and C files (oh, the horror).

···

On 1/11/07, Nathaniel Trellice <naptrel@yahoo.co.uk> wrote:

Thanks,
Nat

--
Posted via http://www.ruby-forum.com/\.

--
- Simen

I think the best way is the following: have all you C defines in a separate .h file (and only those). Write a small ruby script taking all the lines in your header through something like (untested):

open(file) do |f|
for line in f
if line =~ /#define\s+(\w+)\s+(\S+)/
puts “#{$1} = #[$2}”
end
end
end

Use this to create a .rb file, and have it regenerated through a Makefile.

Cheers,

  Vince
···

----- Original Message -----
From: Nathaniel Trellice
Date: Thursday, January 11, 2007 1:02 pm
Subject: Sharing constants between C and Ruby code
To: ruby-talk@ruby-lang.org (ruby-talk ML)

Hello,

I’m new to ruby, but fairly experienced in C. I am using Ruby on Rails
to chat to a postgres database. I have some C functions that I can run
in the database backend. I would like to use constants defined in C
header files, e.g “#define MY_CONSTANT 100” within ruby code. I
know I
can similarly define a constant in ruby, i.e. “MY_CONSTANT=100”, but
given that I have quite a few of these, and synchronising the two
filescould become tricky, is there some (preferably simple) clever
way/hackthat I can define constants in a single file and use them
both in C and
in Ruby?

sender: "Nathaniel Trellice" date: "Thu, Jan 11, 2007 at 09:01:50PM +0900" <<<EOQ

Hello,

I'm new to ruby, but fairly experienced in C. I am using Ruby on Rails
to chat to a postgres database. I have some C functions that I can run
in the database backend. I would like to use constants defined in C
header files, e.g "#define MY_CONSTANT 100" within ruby code. I know I
can similarly define a constant in ruby, i.e. "MY_CONSTANT=100", but
given that I have quite a few of these, and synchronising the two files
could become tricky, is there some (preferably simple) clever way/hack
that I can define constants in a single file and use them both in C and
in Ruby?

Hello,

I've had a similar problem to solve when I had a mixed PHP/Ruby project.
I ended up using a separate file from both PHP and Ruby, like:

0 = some_constant
1 = some_other_constant
etc.

which was trivial to parse and turn into constants into either of them.
It actually made the project cleaner to have the constants defined like
that so I ended up putting all the constants there not just the common
ones between PHP and Ruby scripts.

Later, for parsing that same definitions file from C, I found a nice
library: http://sbooth.org/ccl/index.html

All the best,
Alex

This is seems to me as the best approach - you could create extension
that you'd require, and that would define those constants, but it will
be unnecessarily complicated.
Just write your header to be easily parsable and you're done.

···

On 1/11/07, vincent.fourmond@9online.fr <vincent.fourmond@9online.fr> wrote:

----- Original Message -----
From: Nathaniel Trellice
Date: Thursday, January 11, 2007 1:02 pm
Subject: Sharing constants between C and Ruby code
To: ruby-talk@ruby-lang.org (ruby-talk ML)

> Hello,
>
> I'm new to ruby, but fairly experienced in C. I am using Ruby on Rails
> to chat to a postgres database. I have some C functions that I can run
> in the database backend. I would like to use constants defined in C
> header files, e.g "#define MY_CONSTANT 100" within ruby code. I
> know I
> can similarly define a constant in ruby, i.e. "MY_CONSTANT=100", but
> given that I have quite a few of these, and synchronising the two
> filescould become tricky, is there some (preferably simple) clever
> way/hackthat I can define constants in a single file and use them
> both in C and
> in Ruby?

I think the best way is the following: have all you C defines in a separate
.h file (and only those). Write a small ruby script taking all the lines in
your header through something like (untested):

open(file) do |f|
for line in f
if line =~ /#define\s+(\w+)\s+(\S+)/
puts "#{$1} = #[$2}"
end
end

Use this to create a .rb file, and have it regenerated through a Makefile.

Thanks for the ideas.

What I was thinking of doing was writing a Ruby class (in C) which has
the constants as class constants. This way, compiling the class will
pull in the #defines from the C header file, and they'll be available
within Ruby from my class. But, being new to ruby, I was hoping to avoid
having to figure out how to write a Ruby class in C at this stage of my
ruby development!
Thanks again
Nat

···

--
Posted via http://www.ruby-forum.com/.

I don't think that approach would buy you much. You would still have
to maintain (by hand) a C file that mapped the C constants (from the .h
file) into Ruby constants. I'm not a Ruby's internal programmer but
I imagine you would have to have something like:

  rb_constant_set( klass, 'MY_CONSTANT', MY_CONSTANT)

for every single constant. Note: I made up the function name and API, but
you would have to explicitly bind the string 'MY_CONSTANT' to the value
represented by the MY_CONSTANT macro via some sort of function call.

I can't imagine that maintaining that C file by hand is any easier than
the simple parsing suggestion that has already been described to generate
a pure Ruby class. Alternatively, you could describe your constants
via something like YAML and write (in Ruby!) code to generate a C header
file for the constants and Ruby class for your use in the Ruby side of things.

Even easier, something like:

class Constants
   A = 100
   B = 200
   C = A + B

   def self.to_h
     constants.sort.inject("") { |t,c|
       t << "#define #{c} #{const_get(c)}\n"
     }
   end
end

Now you can maintain this class directly and have it generate your C .h file
via:

  open("constants.h", "w") { |f|
    f.write Constants.to_h
         }

Anyway, I think there are lots of ways to handle your situation without having
to dive into writing Ruby extensions and/or classes in C.

Gary Wright

···

On Jan 11, 2007, at 8:23 AM, Nathaniel Trellice wrote:

What I was thinking of doing was writing a Ruby class (in C) which has
the constants as class constants. This way, compiling the class will
pull in the #defines from the C header file, and they'll be available
within Ruby from my class. But, being new to ruby, I was hoping to avoid
having to figure out how to write a Ruby class in C at this stage of my
ruby development!

Thanks for the ideas.

What I was thinking of doing was writing a Ruby class (in C) which has
the constants as class constants. This way, compiling the class will
pull in the #defines from the C header file, and they'll be available
within Ruby from my class. But, being new to ruby, I was hoping to avoid
having to figure out how to write a Ruby class in C at this stage of my
ruby development!
Thanks again
Nat

--
Posted via http://www.ruby-forum.com/\.

It's really not as hard as you think. In fact, I whipped this up in 15 minutes (and that's because I had to look up the functions!)

If the set of constants is fixed, you need only create the C file once. If not, then a script to generate your version of "rb_my_constants.c" with the right set of rb_define_const(...) lines would be a slightly better way to go than having to parse and generate the ruby module directly. (Note, module rather than class since you didn't indicate there was any methods to share, but calling a C function as a Ruby method is almost just as easy.)

-Rob

rab:c $ mkdir my_constants
rab:c $ cd my_constants/
rab:my_constants $ head -100 my_constants.h rb_my_constants.c extconf.rb
==> my_constants.h <==
#define MY_CONSTANT 100
#define YOUR_CONSTANT 102
#define HIS_CONSTANT 0xCAFE

==> rb_my_constants.c <==
#include "ruby.h"

#include "my_constants.h"

static int id_my_constants;

VALUE mMyConstants;

void Init_my_constants()
{
     mMyConstants = rb_define_module("MyConstants");
     rb_define_const(mMyConstants, "MY_CONSTANT", INT2NUM(MY_CONSTANT));
     rb_define_const(mMyConstants, "YOUR_CONSTANT", INT2NUM(YOUR_CONSTANT));
     rb_define_const(mMyConstants, "HIS_CONSTANT", INT2NUM(HIS_CONSTANT));
}

==> extconf.rb <==
require 'mkmf'
create_makefile("my_constants")

rab:my_constants $ ruby extconf.rb
creating Makefile
rab:my_constants $ make
gcc -I. -I/opt/local/lib/ruby/1.8/i686-darwin8.8.1 -I/opt/local/lib/ruby/1.8/i686-darwin8.8.1 -I. -O -pipe -I/opt/local/include -fno-common -O -pipe -I/opt/local/include -fno-common -pipe -fno-common -c rb_my_constants.c
cc -dynamic -bundle -undefined suppress -flat_namespace -L/opt/local/lib -L"/opt/local/lib" -o my_constants.bundle rb_my_constants.o -lruby -lpthread -ldl -lobjc
/usr/bin/ld: warning multiple definitions of symbol _setregid
/opt/local/lib/libruby.dylib(process.o) definition of _setregid
/usr/lib/gcc/i686-apple-darwin8/4.0.1/../../../libpthread.dylib(setregid.So) definition of _setregid
/usr/bin/ld: warning multiple definitions of symbol _setreuid
/opt/local/lib/libruby.dylib(process.o) definition of _setreuid
/usr/lib/gcc/i686-apple-darwin8/4.0.1/../../../libpthread.dylib(setreuid.So) definition of _setreuid

rab:my_constants $ ls -l
total 72
-rw-r--r-- 1 rab rab 3585 Jan 11 08:50 Makefile
-rw-r--r-- 1 rab rab 47 Jan 11 08:38 extconf.rb
-rwxr-xr-x 1 rab rab 13296 Jan 11 08:51 my_constants.bundle
-rw-r--r-- 1 rab rab 83 Jan 11 08:38 my_constants.h
-rw-r--r-- 1 rab rab 402 Jan 11 08:49 rb_my_constants.c
-rw-r--r-- 1 rab rab 1304 Jan 11 08:51 rb_my_constants.o

rab:my_constants $ irb -rmy_constants
>> MyConstants
=> MyConstants
>> MyConstants.constants
=> ["MY_CONSTANT", "HIS_CONSTANT", "YOUR_CONSTANT"]
>> MyConstants::MY_CONSTANT
=> 100
>> MyConstants::YOUR_CONSTANT
=> 102
>> MyConstants::HIS_CONSTANT
=> 51966
>> MyConstants::HIS_CONSTANT.to_s(16)
=> "cafe"
>> exit

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Jan 11, 2007, at 8:23 AM, Nathaniel Trellice wrote:

    rb_define_const(mMyConstants, "MY_CONSTANT", INT2NUM(MY_CONSTANT));
    rb_define_const(mMyConstants, "YOUR_CONSTANT", INT2NUM(YOUR_CONSTANT));
    rb_define_const(mMyConstants, "HIS_CONSTANT", INT2NUM(HIS_CONSTANT));

Hah! I wasn't too far off with my guess of:

  rb_constant_set( klass, 'MY_CONSTANT', MY_CONSTANT)

Anyway, you are still stuck with having to keep the C .h file and the Ruby
.c extension in sync by hand. I'd pick any other scheme that allowed you
to only worry about maintaining a single file with the constant definitions.

Gary Wright

···

On Jan 11, 2007, at 9:04 AM, Rob Biedenharn wrote:

It depends on whether the OP is adding new constants to the file (#define HER_CONSTANT 105) or just changing the values (#define MY_CONSTANT 42).

You could always generate the .c file from the .h if that were a problem -- and that's what others suggested doing from .h to .rb directly. This solution however, lets the C preprocessor and/or compiler do the dirty work of parsing the value of the #define. If they are non-trivial, this might be a big win. If these constants are always numbers, hand-coding the rb_my_constants.c file may be the way to go (or you'd have to make parsing the .h file smarter (or give it hints?)).

Besides, if new constants are added, you'd have to know they existed to use them in the Ruby code anyway.

Perhaps Nathaniel can clear up the mystery for us by telling us what assumptions *he* is making and what solutions will work better for his situation.

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Jan 11, 2007, at 10:01 AM, gwtmp01@mac.com wrote:

On Jan 11, 2007, at 9:04 AM, Rob Biedenharn wrote:

    rb_define_const(mMyConstants, "MY_CONSTANT", INT2NUM(MY_CONSTANT));
    rb_define_const(mMyConstants, "YOUR_CONSTANT", INT2NUM(YOUR_CONSTANT));
    rb_define_const(mMyConstants, "HIS_CONSTANT", INT2NUM(HIS_CONSTANT));

Hah! I wasn't too far off with my guess of:

  rb_constant_set( klass, 'MY_CONSTANT', MY_CONSTANT)

Anyway, you are still stuck with having to keep the C .h file and the Ruby
.c extension in sync by hand. I'd pick any other scheme that allowed you
to only worry about maintaining a single file with the constant definitions.

Gary Wright