Visual C++ 14 と Ruby その1

Microsoft Visual Studio 2015 CTP6がでましたね。VS14ではVisual C++ Runtimeに大きく変更が入るそうで、とてもイヤな予感がしますから、ちょっと様子を見てみましょう。
Azure使いの人はMicrosoft Azure virtual machine galleryにあるVisual Studio Ultimate 2015 Preview on Windows Server 2012 R2を使うと手間が省けます。そうでない人は頑張ってインストールしましょう。インストールの際はGitを一緒に入れておくとbison.exeやsed.exeが一緒についてくるので楽です。
インストールが終わったら早速VS2015 x64 Native Tools Command Promptを起動してとりあえずcl.exeを叩いてみるわけですが、なんと起動しません (上記Azureでの場合)。cl.exeはVisual C++ 2015 再配布可能パッケージに依存しているのに、なんと愚かなことに普通はこれがインストールされないんですね。C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\1033\vcredist_x64.exe にあるので、インストールしましょう。 (注: RCでは直りました)
気を取り直してrubyソースコードを取ってきて、win32\configure.batを実行です、失敗します。これはランタイム名とバージョンを検出するツールwin32\rtname.cmdが見事に上記の変更を踏んだからですね。前向きに直して次に進みます、失敗します。よく見るとverconf.mkの \ の後に余計なスペースが入っています。これはnmake14をいじって壊したようです。困りますね。
まじめに対応するのもばかばかしいので、C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64\nmake.exeを適当においてお茶を濁しましょう。 (注: RCでは直りました)

つづく

「文字列」について

「文字列を文字の列とみなす単純化」について議論がありますが、前提が抜け落ちてるように思うので書くことにします。
そもそもこの話はどのような文脈の上にあるかというと、テキスト処理 (wikipedia:en:Text_processing) の文脈になります。ここでいう「テキスト処理」とは plain text (wikipedia:プレーンテキスト) の検索・加工のことで、ここでは特に UNIX Text Processing の系譜が念頭に置かれています。つまり、複雑な装飾を含むリッチテキストではなく、処理の対象を ASCII 文字列といくつかの制御文字へと抽象化することで、正規表現のような強力な道具を用いた処理を可能とした世界です。UNIX でのお話ですから、ここでの具体的な処理の単位は char であり、全体としては char[] になります。この char の中身は上で述べたとおり、ASCII 文字列ですので、値は 0〜127 です。 (実際初期の UNIX tools は 8-bit clean ではなかった)
さて、アメリカ以外の国では (制御文字込みで) 128文字では当然足りないので、拡張が必要です。拡張の方針には

  1. ワイド文字: char を大きくする
  2. マルチバイト文字: 複数の char を組み合わせて、「1文字」にする

の2種類があります。

ワイド文字

ヨーロッパの言語ではアクセント付き文字を用いますが、これらは ASCII に収録されていません。ここで取られた策が 7 bit から 8 bit への拡大です。とはいえ、UNIX において char はたいていの場合もとから 8 bit でしたから、何か新しいものを導入する必要はありませんでした。
その後の wchar_t の導入や TRON コード、Unicode などでは、16 bit や 32 bit などのより大きな文字型が提案されています。
ワイド文字のメリットはプログラミングモデルはそのままで、型と関数だけを取り替えればより多くの文字を扱えることです。これにより、文字コードのことをよく知らない人でも国際化に対応したプログラムを開発出来ます。
デメリットは文字列型が変更されることでプログラムのインターフェイスが変わってしまうことと、ネットワークなどのバイトストリームではそのままでは使えないことになります。

マルチバイト文字

複数の char を組み合わせて一つの文字を表すようにするのが「マルチバイト文字」です。
この方法の場合、プログラミングモデルは複雑になりますが、既存のプログラムを改修する際に、そのインターフェイスを維持したまま文字数を数えるなど必要最小限の変更で日本語対応させられることがメリットでした。

世界の選択

当初、世の人々はワイド文字こそが長期的には正しい選択だと考えていました。1 wchar_t = 1文字 は明らかにわかりやすい抽象化だからです。また、単一の文字コードUnicodeを採用することで国際化は格段に容易となることが期待されました。しかし、この考えは何重にも間違っていたことがその後明らかになります。
まずはUnicodeが16bitに収まらなかったことです。これにより、シンプルな16bit固定長だったUCS-2サロゲートペアを用いたUTF-16へと改修せざるを得なくなり、複数のワイド文字 (code unit) で1文字を表すという両者のデメリットを兼ね備えた方式へと堕ちました。
また、Unicodeが本格的に IVS をはじめとした文字の結合を扱うようになったことにより、複数Unicode文字 (Unicode scalar value) を組み合わせて1文字を表す「結合文字列」を扱う必要が増し、結局プログラミングモデルの変更も必要となってしまいました。(なお、絵文字周りの話は文字コードのかなり上の方のレイヤーの話なので、今回の話とは全く関係ないと思う)
加えて、現代の多くのプログラムではネットワーク通信を扱うことが多いと思いますが、というかHTTPを扱うと思いますが、HTTPはASCIIをベースとしつつバイナリも混ざる混沌とした世界です。言い換えるとバイト列なのに文字列処理をしたいというワイド文字としては扱いづらいデータになります。(byte[]とStringの相互変換が乱れ飛ぶコードを目にした人も多いのではないでしょうか)
結局の所、ワイド文字という試みは失敗であったし、今となっては無意味な複雑化であると結論づけていいのではないかと思います。

Ruby の選択

Ruby はマルチバイト文字型のアプローチを採用しています。(「Unicode路線に見切りをつけ」たのではなく、ワイド文字路線に見切りを付けたのである)これにより、String#each_byte, String#each_char, String#each_codepoint などのメソッドを通じて、バイト列上に構築された様々な抽象化レイヤを自在に扱うことが出来ます。また、現在は要望やユースケースが皆無なために実装は見送っていますが、IVS を考慮した each 亜種も容易に追加することが出来ます。
加えて、複数文字コードを同時に扱う…ことは普通の人はやらないと思いますが、ネットワークプログラミングを行う際にバイト列と文字列をシームレスに扱うことが出来ます。つまり、HTTPヘッダ等を扱う際にbyte[]とStringを変換する必要がありません。

まとめ

ワイド文字はオワコン

Cの構造体や関数が定義された位置を表示するnadoka用bot、crubybotつくった

なにをつくったか

表題のとおり crubybot.nb ですが、その名の通りCRubyのソースを解釈して、与えた構造体や関数の定義位置を返します。返す時はGitHubのURLなんですが、まぁそこは枝葉ですな。

libclang

Cコンパイラにはプリプロセッサ構文解析構文木の構築などが含まれています。ですので、Cソースで何かをしたい場合、Cコンパイラのモジュールを使えると便利です。clang由来の便利なやつがlibclangです。

なにをしているか

find_def のあたりを見ればわかるでしょ。

まとめ

というわけで、libclangを使うと簡単にCソースで遊べるので便利です。

付録

きつねさんとおぼえる!Clang おかわり を読んだらもっと楽にできた気もするけれど、わたしは読めていません。

最近のFreeBSDのsignal trampolineの場所

しばらく悩んでしまったので、後世の人が悩まないように。

プロセスにシグナルが送られると、カーネルはsignal frameをスタック(またはsigaltstack)に積み、「signal handlerを呼び、戻ってきたら後片付けをして元々のプログラムの位置に戻る関数(=sigreturn)を呼ぶコード」を実行します。詳しくは「インタプリタとシグナル - 微酔半壊」で。
で、このコードが signal trampoline なわけですが、backtrace で得られるアドレスにもこの signal trampoline 内を指すアドレスがあります。具体的には signal handler を呼んだ直後のアドレスです(理由はDEBUG HACKSのHACK #27あたりで)。なので、FreeBSD amd64 の場合 sys/amd64/amd64/sigtramp.S がどこに置かれたか探すわけですが、sys/kern/kern_exec.c だけを見ていると実際の値といまいちずれることがあります。
理由は r217151 にて shared page なるものが導入されたからです。酷いのは、実際に確保される場所が場合によって違うっぽいことで……、[http://lists.freebsd.org/pipermail/freebsd-current/2013-November/046773.html:title=ある報告では0x00007ffffffff003だと言っているけれど」、手元では0x00007ffffffff193なんですよね……。
この問題は、r258661で実際に signal trampoline が置かれた場所を sysctl で取れるようになるようなので、それを待てば良いということになります。work around が必要ならば、shared pageの始まる0x00007ffffffff000以降のどこか、ということになりますが、まぁいいよね。

C backtrace

5. Backtrace系ライブラリについて。

> シグナルトランポリンとかよくわからないので教えてほしい。

わたしは黒のBSD本 (4.7 Signals) で勉強しました。日本語訳は入手困難だけど、英語版ならKindleで買えます。
が、第2版が8月にでるそうです!(3月14日追記)

BSDカーネルの設計と実装―FreeBSD詳解

BSDカーネルの設計と実装―FreeBSD詳解

  • 作者: マーシャル・カークマキュージック,ジョージ・V.ネヴィル‐ニール,砂原秀樹,Marshall Kirk McKusick,George V. Neville‐Neil,歌代和正
  • 出版社/メーカー: アスキー
  • 発売日: 2005/10/18
  • メディア: 単行本
  • クリック: 122回
  • この商品を含むブログ (57件) を見る
Design and Implementation of the FreeBSD Operating System, The

Design and Implementation of the FreeBSD Operating System, The

The Design and Implementation of the FreeBSD Operating System (2nd Edition)

The Design and Implementation of the FreeBSD Operating System (2nd Edition)

  • 作者: Marshall Kirk McKusick,George V. Neville-Neil,Robert N.M. Watson
  • 出版社/メーカー: Addison-Wesley Professional
  • 発売日: 2014/09/15
  • メディア: ハードカバー
  • この商品を含むブログを見る

> CRubyにもどっかから持ってきたのかaddr2line.cってやつがあって、さっきのexecinfo.hで得た情報をもとにして、更にDWARFのデバッグ情報をつかって情報を拾い集めている。

経緯は %ruby観察日記 2010-11-25#4089 にありますが shinh さんによる独自実装ですね。

なお、Rubyの場合、rb_print_backtrace() という C API が(非公開APIとして)存在します。
ので、デバッグ用ではご自由にお使いください。

公開するgemでは使うなよ!ゼッタイだぞ!!

さくらのBASE Storage について

待望のs3っぽいやつがさくらに来たので、chkbuildのログ上げてみたら、CentOS系だけで70GB近くあった。 http://logfiles.b.storage.sakura.ad.jp/

content-typeとHTTPヘッダ (Content-Encoding) の設定ができないので、html.gzやtxt.gzをブラウザに自動展開してもらえないのが困っている。

GitHub で Web だけで Pull Request を投げるには

あらすじ

  1. typo の修正とかでいちいちローカルにリポジトリ取ってくるのだるいよね。
  2. GitHub って Web でファイル編集できて便利だね。
  3. 油断してると master で編集しちゃうけど、master ブランチから Pull Request とか小学生でも許されないよね
  4. どうやってブランチを作ればいいんだろう?

まとめ

結論としては、以下の様な手順になります。

  1. fork する
  2. ブランチ選択画面で、修正の元となるブランチに移動する
  3. 再びブランチ選択画面で、入力欄におもむろに新しいブランチ名を入れて Enter おす
  4. 新しいブランチができるので、Web から編集してコミット
  5. Pull Request 投げる

まとめ2

ヘルプがあったらしい