How to make compiler independent extension library on Window


#1

Hello,

I know there are some issues with various compiler versions of
ruby distribution and extension library. Mainly VC++6.0 and VC++7.1
conflict. I guess many people have VC++7.1 and want to make extension
library with VC++7.1. The library built with VC++6.0 is not working on
the VC++7.1 compiled ruby distribution and vice versa.

Here is the method to make compiler independent extension library.
Because it is a draft version, some modifications might be needed.

  1. Remove compile time dependency on ruby dll(msvcr71-ruby18.dll,
    msvcrt-ruby18.dll or others)

1-1. If not exist ruby_ext.h, make ruby_ext.h with make_header.rb

ruby make_header.rb

1-2. Insert #include “ruby_ext.h” after the line #include “ruby.h”
in the library source.

#include “ruby.h”
#include “ruby_ext.h”

1-3. Insert get_ruby_function(); at the first place of Init_xxx function
in the library source.

void Init_changejournal()
{
VALUE mWin32, cChangeJournal;
get_ruby_function();

  1. Remove run time dependency on msvcrt dll (msvcrt.dll,msvcr71.dll
    or others) - Optional

2-1. Insert $CFLAGS.sub!("-MD","-MT") befre create_makefile in the
extconf.rb

$CFLAGS.sub!("-MD","-MT")
create_makefile("win32/changejournal")
  1. Make extension library as usual

    ruby extconf.rb
    nmake install

Regards,

Park H.

=====file make_header.rb

require ‘rbconfig’
File.open(Config::CONFIG[‘archdir’]+’/ruby_ext.h’,“w”) {|f|
func_arr = []
var_arr = []
File.read(Config::CONFIG[‘archdir’]+’/ruby.h’).each {|l|
if l =~ /(^.[\s|*])(rb_\w)(\s.+;$)/
f.puts "typedef #$1 (p_#$2)#$3";
func_arr.push($2);
elsif l =~ /RUBY_EXTERN VALUE (rb_[c|e]\w
);/
var_arr.push($1)
end
}
File.read(Config::CONFIG[‘archdir’]+’/intern.h’).each {|l|
if l =~ /(^.\s)(rb_\w)(\s.+;$)/
f.puts “typedef #$1 (*p_#$2)#$3”;
func_arr.push($2);
end
}
func_arr.each {|fn|
f.puts “#undef #{fn}”
f.puts “p_#{fn} r_#{fn};”
f.puts “#define #{fn} r_#{fn}\n”
}
var_arr.each {|var|
f.puts “#undef #{var}”
f.puts “VALUE r_#{var};”
f.puts “#define #{var} r_#{var}\n”
}
f.puts <<DOC
typedef void *(*p_ruby_xrealloc)(void *ptr, size_t size);
#undef ruby_xrealloc
p_ruby_xrealloc r_ruby_xrealloc;
#define ruby_xrealloc r_ruby_xrealloc

typedef void *(*p_ruby_xmalloc)(size_t size);
#undef ruby_xmalloc
p_ruby_xmalloc r_ruby_xmalloc;
#define ruby_xmalloc r_ruby_xmalloc

#include <stdio.h>
#include <stdlib.h>
HMODULE hinstLib;

char* get_ruby_dll( void )
{
static char psBuffer[128];
FILE *pPipe;

 if( (pPipe = _popen("ruby -r rbconfig -e \\"puts

Config::CONFIG[‘RUBY_SO_NAME’]+’.dll’\"", “rt” )) == NULL )
return NULL;

 fgets(psBuffer, 128, pPipe);
 _pclose( pPipe );
 if(*psBuffer) psBuffer[strlen(psBuffer)-1]=0;
 return psBuffer;

}
void get_ruby_function()
{
hinstLib = LoadLibrary(get_ruby_dll());
if (hinstLib == NULL)
{
exit(1);
}
DOC

func_arr.each {|fn|
f.puts “#{fn} = (p_#{fn})GetProcAddress(hinstLib, “#{fn}”);”
}
var_arr.each {|var|
f.puts “#{var} = (VALUE)GetProcAddress(hinstLib, “#{var}”);”
}
f.puts “}”
}