Extending ruby with crypto++

Hello everybody,

I'd like to use some encryption functions from the crypto++ library
from within ruby.
To achieve this, I tried to make C-Wrapper functions around the C++
library archive.
But to link it against the C++ Archive, I have to use the g++
compiler, otherwise the linker doesn't find symbols (any workaround
for this?!?)
The bad thing is that g++ doesn't compile the ruby extension properly.
I'm very new to C++, so I've no idea how to solve this.
Does anybody know of a ruby extension that wraps C++ libs where I can
spoof a little bit?

bye!
Dominik

I haven't tried this myself, but have you looked at ruby's dl package? This may save you from having to deal with g++ and linking all together.

http://raa.ruby-lang.org/project/ruby-dl/

There's not home page mentioned, but a quick search turned up

http://ttsky.net/ruby/ruby-dl.html

hope this helps.

J.

···

On 08/09/2004, at 9:30 AM, Dominik Werder wrote:

Hello everybody,

I'd like to use some encryption functions from the crypto++ library
from within ruby.
To achieve this, I tried to make C-Wrapper functions around the C++
library archive.
But to link it against the C++ Archive, I have to use the g++
compiler, otherwise the linker doesn't find symbols (any workaround
for this?!?)
The bad thing is that g++ doesn't compile the ruby extension properly.
I'm very new to C++, so I've no idea how to solve this.
Does anybody know of a ruby extension that wraps C++ libs where I can
spoof a little bit?

bye!
Dominik

Hi,

At Wed, 8 Sep 2004 08:30:08 +0900,
Dominik Werder wrote in [ruby-talk:111808]:

But to link it against the C++ Archive, I have to use the g++
compiler, otherwise the linker doesn't find symbols (any workaround
for this?!?)

Add have_library("stdc++") to extconf.rb.

The bad thing is that g++ doesn't compile the ruby extension properly.
I'm very new to C++, so I've no idea how to solve this.
Does anybody know of a ruby extension that wraps C++ libs where I can
spoof a little bit?

How doesn't it work properly?

···

--
Nobu Nakada

Dominik Werder ha scritto:

Hello everybody,

I'd like to use some encryption functions from the crypto++ library
from within ruby.

I won't help you, but are you sure you could'nt mock up something with the openssl binding? It could svae you lot of work..

Add have_library("stdc++") to extconf.rb.

I don't use any build system for this little wrapper, or do you mean I
should add this to the ruby source and recompile ruby? I guess no :slight_smile:

How doesn't it work properly?

I'll try to explain:
I have two Files:

- The first one is a cpp file that wraps the functionality I want into
a function. I compile this one with g++ to an object file

- The second file is a .c file (my ruby extension). I compile this
with gcc because g++ gives errors like:

   bash-2.05b$ g++ -c cRubyTest.c
   cRubyTest.c: In function `void Init_cRubyTest()':
   cRubyTest.c:56: error: invalid conversion from `VALUE (*)(long
unsigned int)'
      to `VALUE (*)(...)'

I got the code from the pickaxe book and don't know with this doesn't
work with g++. gcc compiles correctly to an object file.

- But if I try to link (with g++ cRubyTest.o cr.o -lcryptopp) ld sais:
cRubyTest.o(.text+0x1b): In function `cfunc':
: undefined reference to `GenerateRSAKey'
collect2: ld returned 1 exit status

where GenerateRSAKey is the wrapper function from the cpp file.....

I tried also linking with g++ cruse.o cr.o -lcryptopp -lstdc++ because
you said I should include the libstdc++

I'm stuck.

If I strip away anything from cRubyTest.c that has to do with ruby, it
compiles with g++ and links properly, but doesn't do anything useful
of course :((

It should be possible to take a object made with gcc and one made with
g++ and link them together properly, shouldn't it?

Please help me!
Dominik

Hi,

I did some work to make a test case.
The following is a uuencoded problem.tar.gz
which contains two really small files (3 lines) and a README with a
detailed description of the problem. You can try it on every gcc/g++,
it depends on nothing, just demonstrates the problem.
It would be great if you could take a look..

thank you very much!
Dominik

Save this to a file and run "uudecode <thefilename>", then untar..

begin 644 problem.tar.gz
M'XL(`$#5/D$``^V746_;.`R`\ZQ?P?,&-%D:5W:2%4B+#</687TX''"WQSU,
MEN58J"T9DMPT&/;?1RE.ESL<UJ=D&*8/!6Q9$DF1(<5V1A>-:"]&1X32!;U<
M+O&);\M%>&:+W7-@E-$LPS7Y(L]&-,OIY7P$RV,:m:>WCAF`4;D1IA3F!^N$
ML:<PZ+1T0_Q96A]-!\TH?3G$^W_CGS_&'R?F/OX+G`9Z-(L.^,WC?Z]E";SK
MJE[Q\>2*_&Q[(J=EG_]%RH^FXZG\S[+E8_[/\SSD_Y+&_#\%SZ3B35\*2/`&
M2`B1RD'+I!K[%V;6_!QXS<R+%WYP/X$O!`[+!8`1KC<*Z!7Y&HO'K\?W^Q^C

B0=3^4_WO;[_,_F"^P3L[EO"6+^GX#_Y/_C\-JZ4NJT?G7P26KKC&#M*T)Z

M*]4:%&N%[1@7@*NO"/EW,Q%J16>PD%3CY&,M+>#?,/M)):%Z<-T[N+Z&Y*.P
MSHO<:;")_RA4V<2R<ESV^?_WS9MW?]X<1\<3^9_-EY??__^C/O_SRY<Q_T_"
M!]$T^@]";J%F]P+<1D,E&V%79`;A3H#QV^ET@B/L$`%P!#`A!--9W8&NAC7,
M`H.-85TG##8*NE<E6-T*P+V8TGU5@:N9@UO8,.6(TX#NA,KH%KK>X+(4I[AN
M.U0]B-Q(5Z]0(:Q1Q(SOOA+BK<`RXFH1[(1-+7GMI5E('BM/LA.]V[+3":AS
MKR!!(4E0`&N.#4XA.//VM%OL9E@SS`?QI196G3FRT>9NV#&=G@>;K!"M]6(+
M`9WD=U*8E/RC\2#.2%$>*@QG0=N9K6=Y2I?%<Z\89K@WN)6E&F8-UE`^G9(+
MUW87G%/ZU_;].M7CU(D'-Z4/6399P:T"?T0GM8+/OD\[6Y$5H+M%)14J-:(2
M1BBLR*C^\^"0,\)UTPCN\A4TY="QX>(,Q(-T&!_F>NMC*M`*6:`=_GAH-'JV
M97?H6F\M*BB!-4WP?8CKMBUT8[WS2RBV@[L++.B;>@N<H=\`Q8=]^]@D0\`P
MA'N3I=KM/$?AKM;]NH9;TC%K@UOP&%[?X$GSFI"WX=7?%2$>N]_'H2?!!\N&
F67^[#!7.IDB\2B*12"02B40BD4@D$HE$(I'([\,W7$T6+@`H````
`
end

   bash-2.05b$ g++ -c cRubyTest.c
   cRubyTest.c: In function `void Init_cRubyTest()':
   cRubyTest.c:56: error: invalid conversion from `VALUE (*)(long
unsigned int)'
      to `VALUE (*)(...)'

It's best if you give the complete example, but try it with
RUBY_METHOD_FUNC()

Guy Decoux

which contains two really small files (3 lines) and a README with a
detailed description of the problem. You can try it on every gcc/g++,
it depends on nothing, just demonstrates the problem.

It's called "name mangling". You must compile a.c with g++

Look at bdb-0.5.1, you have an example with bdbxml.cc where Init_bdbxml()
is defined inside a

  extern "C" {

  }

Guy Decoux

Hi,

At Wed, 8 Sep 2004 17:25:07 +0900,
Dominik Werder wrote in [ruby-talk:111830]:

> Add have_library("stdc++") to extconf.rb.
I don't use any build system for this little wrapper, or do you mean I
should add this to the ruby source and recompile ruby? I guess no :slight_smile:

Then how do you compile it?

I mean you have to create extconf.rb:

  have_library("stdc++")
  create_makefile("your_libname")

···

--
Nobu Nakada

How doesn't it work properly?

I'll try to explain:
I have two Files:

- The first one is a cpp file that wraps the functionality I want into
a function. I compile this one with g++ to an object file

- The second file is a .c file (my ruby extension). I compile this
with gcc because g++ gives errors like:

   bash-2.05b$ g++ -c cRubyTest.c
   cRubyTest.c: In function `void Init_cRubyTest()':
   cRubyTest.c:56: error: invalid conversion from `VALUE (*)(long
unsigned int)'
      to `VALUE (*)(...)'

C++ is much stricter when it comes to what kindes of type-casts are
allowed - especially when you use the "old-style" "(<type>)value" casts
(e.g "(char*)void_ptr"). You might have to use new-style C++-only casting
using
static_cast, reinterpret_cast,...

I got the code from the pickaxe book and don't know with this doesn't
work with g++. gcc compiles correctly to an object file.

See above.

- But if I try to link (with g++ cRubyTest.o cr.o -lcryptopp) ld sais:
cRubyTest.o(.text+0x1b): In function `cfunc':
: undefined reference to `GenerateRSAKey'
collect2: ld returned 1 exit status

where GenerateRSAKey is the wrapper function from the cpp file.....

When compiling plain C code, the symbols in the generated .o file are
named like the function they are describing.
With C++, however, it works differently, because you can have more than
one function with the same name (but different count or types or
arguments) in C++. The compiler therefore encodes the signature (the
order, count, and type of the arguments) of a function into its name -
e.g.
the symbol for "int my_func(char*, int)" might be
"int__my_func__char_star__int" (the actual name-mangling the gcc uses is
different, and less human-readable, but you get the idea). Since you
compiled one file with gcc, and the other with g++, the same function
"GenerateRSAKey" is mapped to different symbol names - which of course
makes the linker complain that it can't find the referenced symbols.

I believe you have to wrap the function-declaration of GenerateRSAKey"
(inside your cpp-source) in an 'export "C"' clause. This tells the
compiler that it should generate symbols compatible with C, algtough the
file contains C++ code.

So, instead of declaring GenerateRSAKey with
return_type GenerateRSAKey(type_1 arg1, type_2 arg2, ...) ;

you declare it writing
export "C" {
  return_type GenerateRSAKey(type_1 arg1, type_2 arg2, ...) ;
}

I hope I got the syntax of the "export" clause right - I haven't activly
programmed C++ for a few years, and I'm too lazy to look it up right now
;-))

greetings, Florian Pflug

···

On Wed, September 8, 2004 10:25, Dominik Werder said:

This macro is taken from SWIG:

#ifdef __cplusplus
# ifndef RUBY_METHOD_FUNC /* These definitions should work for Ruby 1.4.6
*/
# define VALUEFUNC(f) ((VALUE (*)()) f)
# define VOIDFUNC(f) ((void (*)()) f)
# else
# ifndef ANYARGS /* These definitions should work for Ruby 1.6 */
# define VALUEFUNC(f) ((VALUE (*)()) f)
# define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
# else /* These definitions should work for Ruby 1.7 */
# define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
# define VOIDFUNC(f) ((RUBY_DATA_FUNC) f)
# endif
# endif
#else
# define VALUEFUNC(f) (f)
# define VOIDFUNC(f) (f)
#endif

It's pretty safe to use it in your extension. You should
use this macro in rb_define_method() and similar functions:

/* Define method. */
rb_define_method(klass, name, VALUEFUNC(f), -1);
            
Regards,

···

On Wed, Sep 08, 2004 at 05:25:07PM +0900, Dominik Werder wrote:

   bash-2.05b$ g++ -c cRubyTest.c
   cRubyTest.c: In function `void Init_cRubyTest()':
   cRubyTest.c:56: error: invalid conversion from `VALUE (*)(long
unsigned int)'
      to `VALUE (*)(...)'

--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

nobu.nokada@softhome.net wrote in message news:<200409081052.i88AqDUm025449@sharui.nakada.niregi.kanuma.tochigi.jp>...

Hi,

At Wed, 8 Sep 2004 17:25:07 +0900,
Dominik Werder wrote in [ruby-talk:111830]:
> > Add have_library("stdc++") to extconf.rb.
> I don't use any build system for this little wrapper, or do you mean I
> should add this to the ruby source and recompile ruby? I guess no :slight_smile:

Then how do you compile it?

I mean you have to create extconf.rb:

  have_library("stdc++")
  create_makefile("your_libname")

When it was plain C without the C++ stuff I just used gcc from
commandline to make a shared object..

This explains a lot.. but I can't find this export keyword ?!?

Found it, the keyword is extern instead of export, but I solved it as
you said:

just said
extern "C" int myfunc() { .. }

If I put the extern statement into the header file, the gcc complains.
So I removed it from the header file and also had to remove the
#incude from the cpp file, because the declarations are not the same,
obviously, but it works!

bye!
Dominik

Dominik Werder wrote:

This explains a lot.. but I can't find this export keyword ?!?

its extern, not export