How to make compiler independent extension library on Windows?

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 Heesob

=====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 "}"
}