RubyCocoaをふつーのgemにしたい
だいぶ前から考えてた、RubyCocoaをふつーのgemにすることに挑戦してみた。アプリ用の.frameworkはまだ手を付けてないけど、拡張ライブラリのほうは`rake test`が全部通るとこまできた。
-現状の課題
今のRubyCocoaはほとんど全部の機能がRubyCocoa.frameworkのほうに入っているので、rubyスクリプトから使う場合にも必ずフレームワークの配置が必要になる。フレームワークは特定のバージョン・構成のlibrubyにリンクして、ちょっとしたスクリプト書くときや、いろんなバージョンで検証したいときにけっこう手間がかかる。
目標はこんなところ。
RubyCocoa今週のコミット 2017-06-12..17
新しいmacOSのbetaでてたので試してみた。案の定いろいろ問題あったんだけど、それ以前に10.12で動いてないことにいまさら気付いた…
macOS 10.12でSEGVする問題を修正
以前に確認したような気がするんだけど、10.12だとrequire 'osx/cocoa'だけでSEGVするので対応。
どうも調べたところ、WebKitの内部クラスでrespondsToSelector:をちゃんと実装していないのがいくつかあって、それが原因らしい。そいつらはRuby側からも見えてる必要がないので無視するように変更した。
テストまわりの修正
- QTKitの関数がなくなってたので、それらは実行しない。
- ruby-2.4でFixnumの警告がでるのでIntegerに変更した。
10.11以降で付属のrubyで落ちる
OS付属のrubyでrequire 'osx/cocoa'すると、class_addMethod()のあたりで落ちる。たぶんSIP(System Integrity Protecton)で保護されてるため。たとえば/usr/bin/rubyを作業ディレクトリにコピーして、そのrubyから実行すると問題なく動作する。
なので、リンクした.appとかは問題ない。rubyスクリプトでなんかやろうとすると落ちる。
たぶんovmixのあたりの処理を見直して、Objective-C側で定義したクラスにメソッド追加とかできないように制御すれば落ちなくはなると思う。ちょっと優先度低め。
diff --git a/install.rb b/install.rb index a57e53c..4fffc2f 100644 --- a/install.rb +++ b/install.rb @@ -1088,6 +1088,7 @@ class ToplevelInstaller < Installer ruby_cmd = '"' + File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['RUBY_INSTALL_NAME']) + '"' ruby_cmd = "/usr/bin/arch -#{@options['arch']} " + ruby_cmd if @options['arch'] + ruby_cmd = File.expand_path("../ruby", __FILE__) dive_into('test') { ENV['DYLD_FRAMEWORK_PATH'] = File.join('../framework', framework_obj_path) ENV['BRIDGE_SUPPORT_PATH'] = '../framework/bridge-support' diff --git a/test/util.rb b/test/util.rb index d65afe5..fbe9c54 100644 --- a/test/util.rb +++ b/test/util.rb @@ -2,7 +2,8 @@ module TestHelper def __spawn_line(line) - cmd = "#{@ruby_path} -I../lib -I../ext/rubycocoa -e \"#{line}\"" + ruby_cmd = File.expand_path("../../ruby", __FILE__) + cmd = "#{ruby_cmd} -I../lib -I../ext/rubycocoa -e \"#{line}\"" cmd = cmd_with_dyld_env(cmd) res = IO.popen(cmd) {|io| io.read} raise "Can't spawn Ruby line: '#{line}'" unless $?.success?
PowerShellのテンプレートエンジンEPS
rubyのERBみたいの。
Windows上でテキスト生成するのにテンプレート処理的なことをしたくって、でもわざわざrubyとかいれるのもなあと思って、PowerShell Galleryで"Template"で検索。コード生成みたいのが多い中で、EPSがふつうにテキスト生成するものっぽいので試してみることに。
"<%" "%>"で囲った中にPowerShellのコードを書くと実行される。まんまeRuby/ERBだね。
ReadMe.mdの例。
PS> Get-Content Test.eps Hi <%= $name %> <%# this is a comment -%> Please buy me the following items: <% 1..5 | %{ -%> - <%= $_ %> pigs ... <% } -%> Dave is a <% if($True) { %>boy<% } else { %>girl<% } %>. Thanks, Dave <%= (Get-Date -f yyyy-MM-dd) %> PS> Invoke-EpsTemplate -Path Test.eps -Safe -binding @{ name = "dave" } Hi dave Please buy me the following items: - 1 pigs ... - 2 pigs ... - 3 pigs ... - 4 pigs ... - 5 pigs ... Dave is a boy. Thanks, Dave 2017-06-12
由来的にもわからないでもないが、"EPS"って名前はどーなん?特にファイル名の拡張子。
MacBookのTouch IDでsudoを使う(PAM)
MacBookに付いてるTouch IDでsudoできないかなあと探してみたら、"「MacBook Proの「Touch ID」を利用してsudoなどの認証を行うPAMが公開。 | AAPL Ch.」"という記事を見つけたので試してみた。
手順は
1. pam_touchidをコンパイルして、てきとうな場所に置く
2. /etc/pam.d/sudo を編集して上記のモジュールの記述を**先頭に**追加
となる。これだけでちゃんと動いて、なんか不思議な感じする。。
ローカルにPortfile書いてインストールして設定した。issueでSSHのケース議論してたり、コードまだ読んでなかったりと自信ないので公式のportには入れてない。brewもまだないっぽいし。
% port contents pam_touchid Port pam_touchid contains: /opt/local/lib/pam/pam_touchid.so.2 /opt/local/share/doc/pam_touchid/LICENSE /opt/local/share/doc/pam_touchid/README.md /opt/local/share/doc/pam_touchid/screenshot.png % grep -n pam_touchid /etc/pam.d/sudo 2:auth sufficient /opt/local/lib/pam/pam_touchid.so reason="execute a command as another user"
% port cat pam_touchid # -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:et:sw=4:ts=4:sts=4 PortSystem 1.0 PortGroup github 1.0 PortGroup xcode 1.0 github.setup hamzasood pam_touchid 0.0.1 github.version ec7b7bdc1285b3588fe083d5bb9ac5ab5137fda2 categories security description A PAM module for authentication with Touch ID long_description ${description} platforms darwin license GPL-3 maintainers kimuraw openmaintainer checksums md5 5a80622d1150b9ff34515e7e97ee3a9c \ sha1 b08b8d338574da2131faaebd9f188098c93d51a1 \ sha256 7bac41ef30b7ba4a69aea5f8683d3b035a469139697f985ab8030c68f9724a13 xcode.project pam_touchid.xcodeproj xcode.configuration Release xcode.destroot.path ${prefix}/lib/pam xcode.destroot.type none # build without code signing for macports xcode.build.settings CODE_SIGN_IDENTITY= xcode.destroot.settings CODE_SIGN_IDENTITY= INSTALL_MODE_FLAG=440 post-destroot { xinstall -d ${destroot}${prefix}/share/doc/${name} xinstall -W ${worksrcpath} README.md LICENSE screenshot.png \ ${destroot}${prefix}/share/doc/${name} } post-activate { ui_msg "" ui_msg "================================================================================" ui_msg "If you try to use Touch ID with `sudo` command, add the below line to the top " ui_msg "of \"/etc/pam.d/sudo\". (see ${homepage})" ui_msg "" ui_msg "auth sufficient ${prefix}/lib/pam/pam_touchid.so reason=\"execute a command as another user\"" ui_msg "================================================================================" ui_msg "" }
(2016-12-30 追記)reasonをローカライズする方法がわからない……別に英語で出るのはかまわんのだけど、日本語のメッセージにまざってるとかっこ悪いしなあ。
MacPortsのPortGroup rubyをsubport対応に
per5, php, pythonなんかでは以前からひとつのPortfileで複数のインタプリタのバージョンに対応したsubportをまとめて登録できるようになっている。たとえば、perl5だとperl5.brahcnes・pythonだとpython.versionsというオプションで登録するsubportのバージョンを指示できる。
rubyではgemでみんな自分で入れるだろうし(最近のrb22-やrb23-てportはぜんぜん登録されてない)、いらないかなあと思ってとくに作ってなかったのだけど、ruby-2.4の準備中に「以前本体に入ってたruby/tkくらいは用意しておくか」と思ってちょっと作業してみたら、わりと簡単に対応できたのでコミットしといた。
もともとはruby/tkように準備していたものの、X11の問題があってお蔵入りになってしまい、使わないのもくやしいので、bundlerに入れておいた。
% port info --subports rb-bundler subports: rb23-bundler, rb24-bundler
rb-bundlerというPortfileで2.3と2.4のsubportが登録されている。
これであとはport:rubyをport:ruby18に改名すれば、個人的にはやっと1.8の呪縛から脱出できる感じがするねえ。
MacPortsのport:ruby24を登録
例によってクリスマスに新しいバージョンがリリースされていたので対応しました。変更点などは公式のリリースアナウンスを見てください。
従来通り、MacPorts版は
- ruby2.4, rake2.4, gem2.4などバージョンのsuffixがつく
- port select --set ruby ruby24などselectを使うと、suffixなしのバージョンで使える
となっています。
以前からアナウンスが出ていたように、tkがruby本体のリリースに含まれなくなりましたので、variantから関連するものを外しています。OSのTk.frameworkにリンクするようにして(デフォルトでそうなるはず)gem tkを入れるのがよいでしょう。
手元の環境で試した感じだとX11版はMacだと以下の問題が起きてダメっぽい感じです。
- Sierra: XQuartzがそもそも動かない? wishすら立ち上がらないので、ruby/tkもダメです。
- El Capitan: ruby-2.4だとウィンドウを閉じたときにSEGVする。ruby-2.3はセーフ。
(追記)OS X 10.7以前でコンパイルできない問題/解消済み
10.7や10.6のbuildbotで"ext/-test-/memory_status/emory_status.c"のコンパイルエラーになっていた。
さすがに古い環境なので「知らんがな」という感じだったものの、twitter上で@n0kadaさんとやりとりしたりしてtrunkにr57180がはいったので、その変更をマージしたruby24-2.4.0_1として登録しました。まあ使ってる人いるかは知らないけど…
(ちなみに10.5 ppcはダメなままです。buildbotのメールが2日くらい遅れてきたので調べていません。)
Mac App Store用のコマンドラインツール mas を登録
コマンドラインでMac App Store経由のインストール、更新などの操作ができる mas (mas-cli) というツールがある。
使い方はREADMEに書かれてる用例を見ればほとんどわかると思う。
$ mas list #インストールしているストアアプリの一覧を出力 $ mas search app-name #ストア上のアプリを名前で検索 $ mas install app-id-number #ストアアプリをインストール $ mas outdated #更新されているアプリを表示 $ mas upgrade #更新されているアプリを最新にする :
有償のアプリを購入することはさすがにできないみたい。
個人的にはちょっと前から使っていたのだけど、アプリケーションの指定時に謎の数字(ストア上のURLに含まれるもの)で指示するところとかがどうかなー?と思って公式のリポジトリには登録してなかった。
最近読んだいくつかのMacの環境構築記事で、新しい環境にストアアプリを入れるのに使うということが書かれてて、そういうユースケースならあらかじめ数字わかってるし問題ないと納得したので公式のport登録することにした。
リポジトリ入れてbuildbotの結果ながめるまで気付かなかったのだけど、最新版はswift3で書かれてるからXcode 8以上がいるんだね。OS X 10.11上でも使えてたからあまり意識してなかった。
ということでPortfileに制限の記載を追加。
# requires swift3 minimum_xcodeversions {15 8} pre-fetch { if {${os.major} < 15} { ui_error "${name} @${version} requires OS X 10.11 or later." return -code error "incompatible OS X version" } }
これで、Xcode 7.xな環境だとちゃんとバージョンが足りてない旨のメッセージが出るようになる。
---> Extracting mas Error: On macOS 10.11, mas @1.3.1 requires Xcode 8 or later but you have Xcode 7.3. Error: See https://guide.macports.org/chunked/installing.xcode.html for download links. Error: org.macports.extract for port mas returned: incompatible Xcode version Please see the log file for port mas for details: /opt/local/var/macports/logs/_Users_kimuraw_work_ports_sysutils_mas/mas/main.log To report a bug, follow the instructions in the guide: http://guide.macports.org/#project.tickets Error: Processing of port mas failed
MacPortsのw3mmanが動かないので直した
w3mというターミナル上で動作する偉大なブラウザがあってですね、それに付属する`w3mman`というコマンドがSEE ALSOやヘッダファイルをリンクとしてジャンプできたりとえらく便利で愛用してたんですよ。
いつのまにか実行しても空の画面しか表示されなくなっていて、「ながいこと更新されてないソフトだししゃーないな」と思ってエイリアス解除して忘れてしまっていた。さいきんふと思い出して調べてみたら、
% perl w3mman2html.cgi Can't use 'defined(%hash)' (Maybe you should just omit the defined()?) at w3mman2html.cgi line 223. %
と、そもそもスクリプトがperlのエラーで動かないということがわかった。どうもメッセージのとおり単にdefined()を外せばよいようで、@msmhrtさんからdebian版は問題ないらしいとの情報をもらって確認したりして対応した。
port:w3mはnomaintainerなので修正パッチを追加(ついでにw3mhelp.cgiも)してコミット。
というわけで、port:w3m @0.5.3_6からはw3mmanが動くようになっているはずです。
poll(2)の動作がSierraで変わってるぽい
(2016-11-12追記)この現象は10.12.2 beta2(16C41b)で直っているようです。10.12.2がリリースされたら解消するかもしれません。
ruby 2.4-preview3が出たので、test-all流して動作確認してたら、Sierraで通らないテストがあったので気付いた。
pollのman見ると、poll(2)のインターフェイスはこんななんだけど
SYNOPSIS #include <poll.h> int poll(struct pollfd fds[], nfds_t nfds, int timeout);
呼び出し時に渡すnfdsの値(=fdsの数)が0のときの動作がSierraから変わっているみたいで
- 10.11以前: timeoutだけ待つ
- 10.12: 待たずにすぐ終了する
となっている。
curlのほうでも先月に話題になっていたよう。
- "poll on mac 10.12 is broken daniel.haxx.se"
- "poll() on macOS 10.12 returns prematurely · Issue #1057 · curl/curl"
Hacker Newsでは「そもそもPOSIX的にどうなん」「仕様的にセーフだったとしてもこれはダメだろ」みたいな議論をしてるっぽいがよくわからん。
Sierraのxnuのソースコードがまだopensource.apple.comにあがってないのがコードみて確認できないのがもどかしい。
この件はruby側の問題じゃないと思うのだけれど、テスト通らないのは動作確認で困るので報告しておいた。
問題のtest/fiddle/test_function.rbを元に、ruby+fiddleでpollの動作確認用のスクリプトを書いた。
require 'fiddle/import' require 'tempfile' include Fiddle libc = dlopen('/usr/lib/libc.dylib') @func = Function.new(libc['poll'], [TYPE_VOIDP, TYPE_INT, TYPE_INT], TYPE_INT) def test_poll(fds, nfds) t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) n1 = @func.call(fds&.to_ptr, nfds, 200) t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) puts "fds=#{fds ? fds.fd : "(nil)"}, nfds=#{nfds}, slept=#{t1 - t0}, status=#{n1}" end fds = Fiddle::Importer.struct(["int fd", "short events", "short revents"]).malloc file = Tempfile.open('poll') begin fds.fd = file.fileno fds.events = 0 fds.revents = 0 puts RUBY_DESCRIPTION puts `uname -sr`.chomp test_poll(fds, 0) # not block on macOS Sierra test_poll(fds, 1) test_poll(nil, 0) test_poll(nil, 1) ensure file.unlink end
SierraおよびEl Capitanでの結果は次のとおり。
# Sierra ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin16] Darwin 16.1.0 fds=7, nfds=0, slept=0, status=0 fds=7, nfds=1, slept=205, status=0 fds=(nil), nfds=0, slept=0, status=0 # ←nfds=0では待たない fds=(nil), nfds=1, slept=0, status=-1 # El Capitan ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin15] Darwin 15.6.0 fds=7, nfds=0, slept=201, status=0 fds=7, nfds=1, slept=206, status=0 fds=(nil), nfds=0, slept=203, status=0 # ←nfds=0でも待つ fds=(nil), nfds=1, slept=0, status=-1
# Sierra 10.12.2 beta2 (16C41b) INS 2016-11-12 ruby 2.4.0preview3 (2016-11-07 trunk 56661) [x86_64-darwin16] Darwin 16.3.0 fds=7, nfds=0, slept=201, status=0 fds=7, nfds=1, slept=202, status=0 fds=(nil), nfds=0, slept=200, status=0 # 直ってる!? fds=(nil), nfds=1, slept=0, status=-1
待たずに終わったときのpoll()の戻り値が0なのもちょっと嫌な感じ。
正直よく知らないのだけど、fd渡さずに単に指定した時間待たせるためにpoll(2)使うのって一般的なテクニックなんですかね?
-
- とりあえずAppleにバグとして報告したほうがよさそうだけど、再現コードをCで書き直すのめんどいなあ。--(次の10.12.2で直るみたい)
(2016-12-17 追記)10.12.2で解消したことを確認しました。
# Sierra 10.12.2 (16C67) INS 2016-12-17 ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin16] Darwin 16.3.0 fds=7, nfds=0, slept=205, status=0 fds=7, nfds=1, slept=205, status=0 fds=(nil), nfds=0, slept=206, status=0 # <- same as 10.11 El Capitan or earlier fds=(nil), nfds=1, slept=0, status=-1
MacPortsの開発リポジトリがgithubへ移行(予定)
話はずいぶん前から出てたのだけれど、ようやくMacPortsの開発がgithubに移ることになったそうです。今週末の10/29-30で移行する予定らしい。
今まではmacports.org上のsvnとtrac上で作業してたけれど、ちょくちょくtracが落ちてたのでgithub.comのほうが稼働率高そうなのがいちばん助かるかなあ。coreはともかくportfileは単純なものだからvcsはsvnでもそんなに困らんし。
コミッタのみなさまはMLでの指示("Moving to GitHub: Status Update, Action Required")どおり
- (なければ)githubのアカウントを登録
- アドレスに macports.org のメールアドレスを追加
- macports-infra あてに"Please invite me to MacPorts on GitHub"の件名でメール送る
の手続きをとってねとのこと。てゆかさ、ふつうに開発者MLに流れてたから見逃してたよ!