きりかノート 3冊め

おあそびプログラミング

忘れがち、OS Xの標準のファイルシステムは大文字小文字を区別しない

ちょっと前にMacPortsのチケットで問い合わせがきてた(#45257 (ruby20: warnings from library files that differ only by case of filename) – MacPorts)ものについて、慣れてるとすぐあたりがつくんだけど、気付かないとだいぶイミフなのでメモ残しとこう。

これはMacPorts固有の現象でもないので、10.9 Mevericksに添付のrubyで試してみよう。

   % irb -w --simple-prompt
   >> RUBY_VERSION
   => "2.0.0"
   >> require 'Digest'
   => true
   >> Digest::MD5.digest("!")
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/digest.rb:4: warning: method redefined; discarding old const_missing
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/Digest.rb:4: warning: previous definition of const_missing was here
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/digest.rb:28: warning: method redefined; discarding old file
   /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/Digest.rb:28: warning: previous definition of file was here
     :

定数が上書きされてるよ!という警告がでてきてしまう。これはなぜ?という話。もちろん実際にはファイルは小文字の名前の"digest.rb"しかない。

requireされたファイルを見てみると、確かに"digest.rb"と"Digest.rb"のふたつの名前が読み込まれている。これは実際には同じファイルだ。

   >> $LOADED_FEATURES.grep(/digest/i)
   => ["/System/Library/.../lib/ruby/2.0.0/universal-darwin13/digest.bundle",
       "/System/Library/Frameworks/.../lib/ruby/2.0.0/Digest.rb", # *D*igest
       "/System/Library/Frameworks/.../lib/ruby/2.0.0/digest.rb", # *d*igest
       "/System/Library/.../lib/ruby/2.0.0/universal-darwin13/digest/md5.bundle"]

原因はOS Xの標準のファイルシステム、HFS+がファイル名の大文字小文字を区別しないことだ。

1. require "Digest" → $LOAD_PATHから"Digest.(rb|bundle)"を探すと(詳細はるりまのKernel#require参照)、ファイルシステムは大文字小文字を区別しないので「"Digest.rb"があるよ」と答える → digest.rbが読み込まれ、"Digest.rb"として$LOADED_FEATURESに記録される。
2. Digest::MD5したとき、const_missingの処理の中で`require "digest"`される。"digest.rb"はまだ$LOADED_FEATURESの中にはないので、同じ"digest.rb"が読み込まれる。

という流れみたい。今回は警告メッセージ出すようにしてたから気付けたけれど、ファイル名の大文字小文字がちがってても動いてしまうので、そのまま他の環境に持っていくと動かない。ということもあるので注意。

Mac用のアプリでもこのへんわりとぐだぐだで、ファイルシステムを大文字小文字区別するHFSXに変えると動かないものがあるというのは時々聞く話。でも個人的にはそろそろ標準をHFSXにしてほしいなあと思う。