ctypesをduneで使っていく方法

気づけば10月、今年ももう3ヶ月を切っていることにびっくりです。 今回は、OMakeをビルドシステムとして使っていたツールをdune対応した時に困ったことがあったので、それについて書こうと思います。 <!–more–> 発端 https://github.com/derui/okeyfum このリポジトリですが、6年くらい前にノリだけで作ったツールです。もともとは OMake というビルドシステムを使っていました。しかし、OMakeが事実上の開発休止になり、このリポジトリ以外ではocamlbuildを使っていたりしました。そして現代は、事実上dune一択状態になりました。 そこで、暇を見つけてdune対応しようとしたとき、ctypesを使っていたために、色々とビルドが通らないようになってしまいました。 ctypesとは ちょっと脱線して、OCamlにおけるctypesというライブラリについて紹介しておきます。 https://github.com/ocamllabs/ocaml-ctypes どういうライブラリかは、最初の一文を見れば大体わかります。 ctypes is a library for binding to C libraries using pure OCaml. The primary aim is to make writing C extensions as straightforward as possible. The core of ctypes is a set of combinators for describing the structure of C types – numeric types, arrays, pointers, structs, unions and functions. You can use these combinators to describe the types of the functions that you want to call, then bind directly to those functions – all without writing or generating any C! ...

October 7, 2020 · derui

OCaml製プログラムでperformance profileをする

OCamlで作ったソフトウェアをチューニングしようとprofilingしようとしたら、4.09.0で gprof 対応が削除されていました。 https://github.com/ocaml/ocaml/pull/2314 これはこれで困ったので、Linuxでのprofiling方法を調べたのでメモります。 ...

September 22, 2020 · derui

Migemoを使って絞り込みできるfzfっぽいものを作っています

残暑というかもう真夏じゃねーか、という気温でいやんな感じです。でも夕方の風邪は大分過ごしやすくなってきました。 そんな秋の声が聞こえはじめている季節とは関係なく、今作っているtoolについて書いてみます。 https://github.com/derui/oif ...

September 9, 2020 · derui

Windows10 + WSL2で環境を整えた

帰省のイベントである、自分のノートPC(Windows10)に開発環境を整備する時期になったので、今回はVagrantからWSL2を使ったものにしてみました。 見切り発車ですので出来るかどうかは不定です。ではいってみましょう。 <!–more–> 不安な点 いつもはVagrant上に構築したX11環境で開発していたわけですが、今回はWSL2になるということで、いろいろ考える必要がありそうでした。 WSL2ではUbuntu20.04/Debian/SUSEくらいしか使えない いつもはArchLinuxを使っているので、色々と不安な点が・・・ Xserverが必要 Windows上のX serverを入れる必要があります 自分のdotfileが使えるのか・・・? Gentoo/Archlinux用になっているようなものなので、色々厳しそう? 今回の要件 以下を目標にします。努力目標は OPT がついてます。 EmacsをGUIで使える 自分のdotfile/.emacs.dを使えている OCaml/opam/Node.jsが入っている (OPT) Emacsからmozc_emacs_helperを通してWindows上のGoogle日本語入力を使えている (OPT) EmacsからWindowsの方のブラウザとかを使える Emacsとterminalだけで大体生きてるOld typeなので、これくらい出来ればだいたい何とかなります。 WSL2のインストール いつものごとく画像はありませんがご容赦を。以下の手順でWSLを有効にします。なお、前提としてWindowsのOS versionがMay Update以降である必要があります。お気をつけて。 アップデートが必要なことを忘れていてだいぶ時間を食ったのは内緒です インストールと更新方法は、Microsoftの公式ドキュメントが詳しいのでそっちを見ましょう。 https://docs.microsoft.com/ja-jp/windows/wsl/install-win10 一応手順を書いておきます。 PowerShellを管理者権限で開く dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart 再起動する またPowerShellを管理者権限で開く wsl --set-default-version 2 なんかURLが表示されるので、アクセスしてWSLのkernel updateを入手してインストールする Windows StoreからWSLのディストリビューションをダウンロードする(今回はUbuntu 20.04を選択) Windows Storeからダウンロードしたディストリビューションを起動する しばらく待つ(数分程度) UNIX username/passwordを入れる。Windows usernameと同じにしとくのが無難な模様 これでいけるはずです。WSLにアクセスする時は、Windows TerminalとかcmdとかPowerShellとかお好きなもので wsl と打てば、デフォルトで設定されているディストリビューションに対してアクセスできます。 WSLにいろいろインストール WSL2は普通のLinuxなので、色々設定をしていきます。ただ、WSL2は若干特殊な環境なので、systemctlは使えないものと考えるのが良さそうです。 timezoneはだいたい初期状態で問題なさそうでした。 ...

August 8, 2020 · derui

lambda-termでmulti byteを一文字ずつ表示する

気づいたら8月になっていました。今年の梅雨はかなり長かったですね・・・。過ごしやすいのは結構なんですが、野菜が高くなるのでこれも困ります。 今回は、OCamlでTUI(Terminal-based User Interface)を作る際の鉄板ライブラリである lambda-term を使ったときに、multi byteを表示出来なかったのを解消したので、備忘録として書いておきます。 <!–more–> やりたかったことと起こっていたこと やりたかったこととしては、 一文字ずつ表示したい 各文字にstyleを当てたい lambda-termでは、 LTerm_draw.draw_string と LTerm_draw.draw_char という2つの関数があります。こいつらは字面の通り、stringやcharをレンダリングします。 使い方はこんな感じです。実際にはcontextが必要なので、widgetの中とかで行う感じです。 let str = Zed_string.of_utf8 "foo" in let style = LTerm_style.none in LTerm_draw.draw_string ~style ctx 0 0 str; LTerm_draw.draw_char ~style ctx 0 1 @@ Zed_string.get 0 str これで表示自体は出来るんですが、 LTerm_draw.draw_char を使っていった時に、色々と気になる問題がありました。それは、multi byte(ここでは日本語)を表示しようとした時に、なぜか表示されない、ということでした。 解決 備忘録なのでさっさと行きますが、原因は LTerm_draw.draw_char のcolumn指定の誤りでした。 LTerm_draw.draw_char のシグネチャは、以下のようになっています。 val draw_char: ?style:LTerm_style.style -> LTerm_draw.context -> int -> int -> Zed_char.t -> unit さて、Zed_charですが、こいつは zed というライブラリが提供しているmoduleです。こいつはunicodeを保持していて、保持している文字の幅も持っています。 Zed_char.width で取得できます。 LTerm_draw.draw_char の挙動ですが、基本的にはterminalのascii 1文字を1columnとして描画します。ただ、 Zed_char.width が1より大きい場合は、1より大きい分だけSizeHolderというダミー文字で埋めるようになっています。 この挙動がわかっていなかったので、multi byteを1columnずつずらして表示しようとすると、一つ前に表示したmulti byteを消したのと同じ状態になってしまっていました。 実際、multi byteを考慮した上で LTerm_draw.draw_char を使う場合、以下のようにする必要があります。 let str = Zed_string.of_utf8 "テストfoo" in let style = LTerm_style.none in Zed_string.fold (fun ch index -> LTerm_draw.draw_char ~style ctx 0 index ch; index + Zed_char.width ch ) 0 |> ignore わかってしまえば納得ですが、中々ドキュメントだけでは分かりづらいことなので、誰か(主に自分)の役に立てばと思います。 ...

August 1, 2020 · derui

shellのpipeを使いつつ入力とかを受け付ける方法

ちょっと最近やり始めた(正確に言うとやり直し始めた)ツールづくりで、どうやったかを毎回調べてしまうので、備忘録的に書いておきます。 <!–more–> pipeしたときの標準出力とかの状態 Unix(Linux)で、shellからプログラムをpipeで繋いで起動した場合に、標準入出力がどうなるか?というのは、以下の記事にわかりやすく載っています。 Qiita Linuxのパイプをちょっとだけ理解する さて、pipeは標準入出力、特にinteractiveな操作を必要とする場合、標準入力が別コマンドの標準出力が繋がっていることが問題になります。上の記事にもある通り、キーボードを受け取る口が無くなるので、pipeの右側にあるコマンドは、そのままではdaemonみたいな感じになっています。 また、この状態でさらにpipeで繋がれると、当然ですが標準出力が別のコマンドの標準出力につながることになります。進捗などを表示したりするときに標準出力に出したりすると、別のコマンドに余計な出力をすることにもなり、あんまりうれしくありません。こういうのをどうやって解決したら良いか? /dev/tty を使う そんなときには、character deviceである /dev/tty を使います。 http://tldp.org/HOWTO/Text-Terminal-HOWTO-7.html#ss7.3 この辺りに説明が書いてありますが、 /dev/tty は、 現在のprocessに対するterminalの制御 を行うためのデバイスです。つまり、このデバイスファイルに対して出力するとターミナルに対して入力したものとして扱われ、このデバイスファイルを読み込むと、書き込んだものを読める、ということになります。 試してないのであれですが、異なるプロセスが同時にこのファイルを開いても、最終的には /dev/pty/N というキャラクターデバイスに割り当てられるはずです。なので、競合とかは考えなくていい、と思います。 簡単に書くとこんな感じになります。入力のみ受け付ける、とかであれば、 RDWR を RDONLY にすると良いです。 (* OCamlで書くとこんな感じ *) let () = let fd = Unix.openfile "/dev/tty" [Unix.RDWR] 0o666 in let stdin' = fd and stdout' = fd in (* stdin' stdout'を使う *) Unix.close fd かなりシンプルですが、これでちゃんと動きます。Windowsでは確か仕組みが異なるため、それも対応するとなると、また別の方法が必要ですが。実際に別のptyが割り当てられていることを確認する場合、以下のような手段があります。 tty コマンドというそのまんまの名前のコマンドを使うと、今のプロセスで標準入力に接続されているファイルがわかります ps コマンドのtty欄を見ると、そのコマンドの標準入力に繋がっているファイルがわかります 特にpsコマンドの方だと、shell scriptの中から起動されたコマンドのttyは、起動元のshellのttyと同一であったりと、仕組みが思い浮かぶような感じにもなっていて面白いので、覚えておくといいと思います。 最後に 今回は久しぶりにhow to 系の記事でした。またこういうのも書いていこうと思います。How To系ってちゃんと書こうとするとハードルが高いのと、調べればわかるので書く気力が湧けば、ですが・・・。 ...

July 12, 2020 · derui

最近はpure CSS + PostCSSを使っている話

緊急事態宣言は解除されましたが、相変わらず在宅勤務です。また満員電車とかに慣れるための修練が必要になりますね・・・ 今日は ネタがないので 、最近の趣味におけるCSSの書き方を簡単に書いていきます。 <!–more–> なぜPure CSSに回帰したのか 以前は、自分で書くのは全部SCSSで、仕事ではPure CSSでした。SCSSの現場もありましたが、余計な依存を増やさないでくれ、という依頼があった時はPure CSSを書くようにしていました。 だいぶ前(PostCSSが出るより前)は、ある程度構造化したり共通化したCSSをかきたいなー、ってなった場合、SCSSなりSassやLESSといったAltCSSを選択するしかありませんでした。 私の把握している範囲では、です。他にあったのかもしれませんが、当時リーズナブルな手法と言ったらAltCSSだったと思います。 ただ、AltCSSはAltJSと同じような課題を抱えていました。今も余り変わらないと思いますが・・・。 Toolに追随する必要がある 機能の増えた・減ったなどに対応する必要がある 結局生成されるのはCSSなので、CSSの知識+アルファが必要 色々やりすぎて結局保守性が下がる PostCSSとCSS Custom Variables PostCSSは以前から知っていましたが、実際に使ったことはありませんでした。使うだけなら、npm/yarnでCLIを入れれば使えます。 $ yarn add postcss-cli PostCSSとAltCSSの違いは、色んな所で言われていますが、大きく他と違うのは、 あくまでCSSのPostprocesser である、ということだと理解しています。 そのため、PostCSSのpluginは大抵未来のCSS標準を試すための試金石だったり、autoprefixerに代表されるutility系が多いです。言語の根幹を変更するようなものは、ユーザーが自ら入れなければならないため、危険が少ないのも利点だと思います。 また、AltCSSを利用する最大(個人的に)の理由だった、変数についてもCustom Variableという形で利用できるようになっています。 SCSSの変数とは異なるものではありますが、逆にSCSSの変数では出来ないことも出来るので、メリット・デメリット両方があると思います。 特に、テーマ機能のようなものを使う場合、Custom Variablesの方が使いやすいと思います。色々問題もありますが。 なにより、最悪PostCSSが使えなくなってもダメージがそれ程でもない、というのが安心感あります。 最近使っているPostCSSのPlugin postcss-extend-rule @extend を使えます、が、現状特に使っていないという・・・ postcss-import cssのbmportと違い、inlineでの展開が出来ます。 postcss-nesting SCSSとかのようなnesting ruleを書けます これだけしか使っていませんし、これ以上入れる気もあんまりしていません。 正直nestingもいらないと言えばいらないんですが、疑似要素とかを書く時に重宝するので入れています。 これくらいしか入れていなくても、それほど問題なくサクサクと書けています。複数人開発じゃないから、というのもありそうですが・・・。 とりとめのない終わり 実際、SCSSを書いてもCSSを書いても、セレクタの命名規則だったり詳細度の話だったりは変わりません。ので、ちょっとした書き味の違いを求めるのであれば、標準であるCSSをそのまま書いたほうがメリットがあると、最近は思っています。 Sassに疲れた、とか機能を使い切れなくて悔しい、とか感じているようなら、一度Pure CSSに戻ってみてはどうでしょうか。逆に新鮮だったりするかもしれませんよ。

June 10, 2020 · derui

cmigemoの代わりに自作のmigemoを使うようにしてみた

GWでも変わらずこもってますが、よく考えたら常日頃こもってるので、いつもと変わらんじゃないか、とも思ってきました。 さて、最近Emacsの設定や開発環境を見直したりしていますが、その中で久しく動いていなかったmigemoを動くようにしてみましたので、それについて書きます。 <!–more–> なんで動いていなかったのか そもそもなんで動いていなかったのか、ですが、cmigemo自体は自分でbuildしていたものがあったので、動かすことは出来ました。ただ、 cmigemoが依存しているnkfが、gentooでinstallできない(ので、cmigemoもinstallできない) nkfがpython2.7のみに依存しているのですが、私の環境は脱python2.7しているので、installできなかった。。。 という一点に於いて、cmigemoをこのまま使うべきかどうか、中々判断しづらかった、というのがあります。 cmigemoの代替は・・・ cmigemoでなければどうするか、ということですが、実は選択肢はほとんど無く、originalのmigemoくらいしかありません。 http://0xcc.net/migemo/ ただ、cmigemoはC言語で実装されているので、速度がダンチです。また、私の環境ではRubyが入っていないも同然なので、migemoのためだけに入れるのも・・・と感じていました。そんな時、ふと以前OCamlで実装し直したmigemocamlというのがあるのを思い出しました。 これにEmacs用の実装を入れればいいんじゃないか? という天啓(?)を受けて、実装することにしました。 こぼれ話:なんでOCamlでmigemoを実装していたのか 趣味で作っているOCamlアプリケーションで、migemoを使った検索をしたかったんです。ただ、Windows/Linux両対応する、というときに、C Libraryを使うのは色々とめんどくさいですし、stubの実装が馬鹿になりません。 pure OCamlで作ってしまえば、Windows/Linux両対応部分が大幅に減るので、色々楽じゃん、ということで再実装しました。 cmigemoとほぼ遜色のない速度を出せているので、個人的には満足です。 Emacsの正規表現をだせるようにする migemocamlで出力している正規表現は、PCREを前提とした、最小限の特殊文字だけ利用しています。ただ、Emacsの正規表現は、歴史的な事情から、特殊なエスケープが必要になっています。 https://flex.phys.tohoku.ac.jp/texi/eljman/eljman_218.html 詳しくは上掲のサイトに載っていますが、今回対応した分だと、次のような違いがあります。 (と) は、 \(と\) にしないといけない | は、 \| にしないといけない ただ、OCaml上での実装は、こういった違いをmoduleで表現して差し替えられるようにしたくらいで、あんまりいじってはいません。 https://github.com/derui/migemocaml/pull/1 ocamlformatをかけたのでめっちゃ差分が出てるけど・・・ Emacsに設定する 無事に実装できたので、Emacsで設定してみます。なお、Emacsの設定では全面的に leaf.el + straight.el になっております。 (leaf migemo :straight t :commands migemo-init :custom (migemo-command . "~/.opam/4.09.1/bin/migemocaml") (migemo-options . '("-q" "--emacs")) (migemo-dictionary . "/usr/local/share/migemo/utf-8") (migemo-user-dictionary . nil) (migemo-regex-dictionary . nil) (migemo-coding-system 'utf-8-unix) (migemo-use-pattern-alist . t) (migemo-use-frequent-pattern-alist . t) (migemo-pattern-alist-length . 1024) :config (migemo-init)) migemo-dictionary の設定がcmigemoと異なりますが、それ以外はcmigemoと同じ設定でいけるようになっています。あとは、 avy-migemo とか helm とか、migemoをsupportしているpackageを使えば動作します。 ...

May 5, 2020 · derui

qmk_firmwareの日本語配列からかな入力をする

すっかり在宅に慣れてきましたが、ちょっと出かけることも出来ないというのが割とストレスですね・・・。 最近は出勤時間分の時間が空いたので、環境の改善をよく行っています。そんな中で、日本語入力も改善したので、それについて書こうかと思います。 <!–more–> qmk_firmwareと日本語入力 いくつかqmk_firmwareでカナ入力の方式を実装してきましたが、今までの実装だと、以下のような問題がありました。 どうしてもローマ字で入力させる必要があったため、マッピングが肥大する 肥大すると、当然ながら他の機能を追加できないため、使い勝手が悪い 濁音を後置する場合、どうしても不自然になる 本来であればIME側でやってくれることを、ファームウェア側でやる必要がある 遅延で入力させることもできるが、いかんせん表示がかなり不自然になる 特にnew stickney配列を使うようになって顕著なのが、濁音後置になったため、濁音の入力時に考えなければならないことが増えました。 timerを使った遅延入力にすると、出力自体が遅延するため、今入力している内容を把握するのが大変です。濁音キーを入れた時に、一回入れた文字を消して新しい文字を入れる、ということもしてみたりしましたが、これはこれで誤動作が多く、今ではお蔵入りになっています。 なぜIMEのかな入力を使わないのかと IMEでローマ字ではないかな入力を使えば、こういう問題はある程度解決されます。今までやってなかったのは、ひとえに マッピングがめんどくさい という点が大きかったです。 また、ローマ字では、キーボードのレイアウトがUSでもJPでも全く問題なく扱うことが出来ますが、かな入力では、USではそもそも入力できないキーコードが必要になります。こういった点を解決できるのかが把握できなかったため、放置していましたが、一念発起して対応してみました。 対応した結果 こんな感じになりました。key sequenceが1文字になったことと、濁音と半濁音のハンドリングを自分で行う必要が無くなったため、全体の容量は減っています。 https://github.com/derui/qmk_firmware/tree/master/keyboards/crkbd/keymaps/derui ただ、小書き文字に対する対応が必要であるため、母音を入力するときだけは遅延が発生する状態です。慣れればdelayを低くしてもいいとは思いますが、今のところは置いておいてます。この小書き文字の部分をスマートに実装できれば、かなりの使い勝手になりそうだと勝手に思ってます。 また、Emacsでの設定も追加しました。 (setq mozc-keymap-kana mozc-keymap-kana-101us) この対応をした結果、以下のようになりました。 Fcitx + mozcでは特に問題なく使える Emacs + mozcでは、 ろ と ー に対応するkey codeをハンドリング出来ていないため、本来の入力と異なるmappingが行われてしまっている この2つ以外は、問題なくnew stickney配列を再現できている Emacsでもfcitxを使って、mozc.elを使わない、とかすればいいかもしれないが・・・ mozc-keymap-kana-106jp というkeymapに変更すると、異なる文字が入れられるようになってしまう 多分USレイアウトとJPレイアウトで記号が異なる部分で違っている USレイアウトにないkey codeをハンドリングすることが出来ればなんとかなるので、mozc.elの中を覗いているところ 仕事で使うMacでは試していない ローマ字でいいじゃん、という誘惑との戦い 正直、これだけやっていても、仕事で急いでいるときにはローマ字で入力してしまっているという体たらくなので、ローマ字でいいんじゃないか?と思うときがないわけではありません。 特に、価値のあること(大抵金銭的なもの)以外に時間を使うことに対して否定的な環境にいると、非効率自体が無駄とみなされがちです。 しかし、異なる入力方法に親しむということは、異なる能力開発をしている、ということでもあります。この入力を自然に行うためにはどうするべきか?という問いに答えるのは自分しかいません。問題解決能力を鍛えるということは、みんな大好き人生100年時代にもマッチするのではないでしょうか。 なんだかんだ書いてみましたが、つまるところ自分の趣味なので、まー好きにさせてくれよ、というところでしょうか。 かな入力はIMEに任せよう 濁音後置型のかな入力は、IMEのJISかなに任せると楽が出来ます。新下駄配列とかの濁音も一モーションで入力するような配列では工夫する必要がありそうですが、送信するキーシーケンスの数は減るはずです。 qmk_firmwareでカナ入力を実装している方の参考になれば幸いです。

April 29, 2020 · derui

Enzymeの代わりにtesting-libraryを使うようにしてみた

いろいろコロナの影響が出てきましたが、いかがお過ごしでしょうか。会社でも東京勤務は基本的に在宅となりました。 今まで、ReactとかのIntegration testにはenzymeを使っていましたが、Preactに切り替えた際に課題が多発したため、なんとかして解決してみました。 <!–more–> Preact + Enzymeの課題 Enzymeは元々jsdomとセットで利用していたのですが、 React -> Preact に切り替えたとき、仕様の違いによってテストが動かなかったです。 主な違いとしては、 Preactではshallow renderingが出来ない Portalで色々問題がある これはReactでも色々あるみたいなので、Preactに限ったことではないですが React/Preactでeventの扱いが全く異なる といったあたりです。特に既存のtestでshallow renderingを多用しており、大抵は動くのですが、 React.createPortal を使っているところが全滅でした。 testing-library React.createPortal および Preactの createPortal ですが、いずれも libraryの管理範囲外のDOMにrenderingする というcomponentを構成します。 React.jsの場合、EnzymeのAdapter側でかなり色々やって対応しているようですが、Preactの場合、 Componentを完全にrenderingする というそもそもの仕様から、対応が無理っぽいです。ちゃんと見ていませんが、third partyがlibraryの内部実装に依存している、というのはあまりよろしくないように感じます。 また、よく考えると、jsdomとはいえ実DOMにrenderingするということは、もう それはIntegration Testじゃないのか? という意見を見て、 ( ゚д゚)ハッ! となりました。そんな折に見つけたのが、testing-libraryです。 公式によると、testing-libraryは次のようなソリューションを提供するlibraryです。 The Solution The Testing Library family of libraries is a very light-weight solution for testing without all the implementation details. The main utilities it provides involve querying for nodes similarly to how users would find them. In this way, testing-library helps ensure your tests give you confidence in your UI code. ...

April 5, 2020 · derui