Forum: Ruby How to make compiler independent extension library on Window

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Park H. (Guest)
on 2006-04-26 19:13
(Received via mailing list)
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();

2. 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")

3. 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 "}"
}
This topic is locked and can not be replied to.