Sharing constants between C and Ruby code

N

Nathaniel Trellice

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
 
S

Simen Edvardsen

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).
 
J

Jan Svitok

----- Original Message -----
From: Nathaniel Trellice
Date: Thursday, January 11, 2007 1:02 pm
Subject: Sharing constants between C and Ruby code
To: (e-mail address removed) (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
end

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

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.
 
A

Alexandru E. Ungur

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
 
N

Nathaniel Trellice

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
 
G

gwtmp01

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!

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
 
R

Rob Biedenharn

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

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
(e-mail address removed)
 
G

gwtmp01

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
 
R

Rob Biedenharn

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


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

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
(e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,614
Members
45,288
Latest member
Top CryptoTwitterChannels

Latest Threads

Top