雑に PR を出したので解説をする。
Ruby の namespace 機能をきちんと触っていなかったなと思ったため、サンプル (↓のブログ) を見ながら Cygwin 環境でいじっていると native extension (.so) を require すると LoadError が発生したので追いかけてみた。
原因は namespace は使用する .so を一時領域にコピーして、それを dlopen でロードするのだが、Cygwin 環境では .so に executable permission bit がセットされていないと失敗することであった。
Ruby 内部の namespace の処理で .so をコピーする時に fread で読み出す → fwrite で書き出すという方法をとっている。
Cygwin 環境ではこれによりコピーされた .so は Windows 側のファイルシステムに従った permission を持つため、必ずしもコピー元の .so の permission とは一致しなくなる場合がある。
Cygwin maps Win32 file ownership and permissions to ACLs by default
今回はここで executable permission bit がセットされていなかった。(umask を 022 にしていたけど、だめだった。)
そこでコピー後に元の .so の permission と同じ設定にする処理を追加することで、例外が発生することなくコピーされた .so を require できるようになることを確認した。
ちなみに executable permission bit がセットされていないと dlopen に失敗する原因は「Cygwin DLL の中で dlopen が呼ぶ LoadLibraryW が ACL での Executable 属性がないと失敗する (ERROR_ACCESS_DENIED)」ためみたいなのだが、どうも公式仕様では明言されていないようで、現在の挙動としてはそうなっているという状態のようである。
If the library is not executable, the LoadLibrary function returns an "access denied" error. You should have this observed, too.