たまに、動いている ruby プロセスがあるときに make install し
てしまうことがあるのですが、そのときにその ruby プロセスが
segv になることがあります。

例えば、以下のようなプログラムを動かしている途中に他の
window から make install-nodoc すると segv になります。

% ./ruby -rzlib -e '
loop {
  p Zlib::Deflate.deflate("a")          
  sleep 1
}'
"x\234K\004\000\000b\000b"
"x\234K\004\000\000b\000b"
"x\234K\004\000\000b\000b"
"x\234K\004\000\000b\000b"
"x\234K\004\000\000b\000b"
zsh: segmentation fault  ./ruby -rzlib -e ' loop {   p Zlib::Deflate.deflate("a")   sleep 1 }'
% ./ruby -v
ruby 1.9.0 (2006-03-02) [i686-linux]

この問題は shared library を書き換えてしまうとプロセスが使っ
ているコードが変わってしまうというところにあります。たぶん。

ところで、GNU cp には --remove-destination という、ファイル
をコピーする前にコピー先を削除するというオプションがあります。

というわけで、FileUtils.cp_rf に :remove_destination という
オプションを追加し、ext/extmk.rb でそれを使う、というふうに
するといいんじゃないかとおもうんですがどうでしょう?

Index: ext/extmk.rb
===================================================================
RCS file: /src/ruby/ext/extmk.rb,v
retrieving revision 1.86
diff -u -p -r1.86 extmk.rb
--- ext/extmk.rb	20 Feb 2006 08:34:49 -0000	1.86
+++ ext/extmk.rb	2 Mar 2006 17:09:32 -0000
@@ -381,7 +381,7 @@ if $extout
   RbConfig.expand(extout = "#$extout", RbConfig::CONFIG.merge("topdir"=>$topdir))
   if $install
     RbConfig.expand(dest = "#{$destdir}#{$rubylibdir}")
-    FileUtils.cp_r(extout+"/.", dest, :verbose => true, :noop => $dryrun)
+    FileUtils.cp_r(extout+"/.", dest, :remove_destination => true, :verbose => true, :noop => $dryrun)
     exit
   end
   unless $ignore
Index: lib/fileutils.rb
===================================================================
RCS file: /src/ruby/lib/fileutils.rb,v
retrieving revision 1.69
diff -u -p -r1.69 fileutils.rb
--- lib/fileutils.rb	19 Jan 2006 13:20:23 -0000	1.69
+++ lib/fileutils.rb	2 Mar 2006 17:09:33 -0000
@@ -392,7 +392,7 @@ module FileUtils
   OPT_TABLE['copy'] = %w( noop verbose preserve )
 
   #
-  # Options: preserve noop verbose dereference_root
+  # Options: preserve noop verbose dereference_root remove_destination
   # 
   # Copies +src+ to +dest+. If +src+ is a directory, this method copies
   # all its contents recursively. If +dest+ is a directory, copies
@@ -415,11 +415,11 @@ module FileUtils
   #                                      # but this doesn't.
   # 
   def cp_r(src, dest, options = {})
-    fu_check_options options, :preserve, :noop, :verbose, :dereference_root
-    fu_output_message "cp -r#{options[:preserve] ? 'p' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
+    fu_check_options options, :preserve, :noop, :verbose, :dereference_root, :remove_destination
+    fu_output_message "cp -r#{options[:preserve] ? 'p' : ''}#{options[:remove_destination] ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if options[:verbose]
     return if options[:noop]
     fu_each_src_dest(src, dest) do |s, d|
-      copy_entry s, d, options[:preserve], options[:dereference_root]
+      copy_entry s, d, options[:preserve], options[:dereference_root], options[:remove_destination]
     end
   end
   module_function :cp_r
@@ -440,9 +440,12 @@ module FileUtils
   #
   # If +dereference_root+ is true, this method dereference tree root.
   #
-  def copy_entry(src, dest, preserve = false, dereference_root = false)
+  # If +remove_destination+ is true, this method removes each destination file before copy.
+  #
+  def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
     Entry_.new(src, nil, dereference_root).traverse do |ent|
       destent = Entry_.new(dest, ent.rel, false)
+      File.unlink destent.path if remove_destination && File.file?(destent.path)
       ent.copy destent.path
       ent.copy_metadata destent.path if preserve
     end
-- 
Tanaka Akira