重力に縋るな

千種夜羽です

RustでUEFIアプリケーションを書く 2020 Edition

RustでUEFIアプリケーションを書く 2020 Edition

みなさんこんにちは.sksatです. 最近はVRで生活したり,オタクで を取ってゲラゲラしたりしています.

ちなみに映画化しました*1.よろしくお願いします. youtu.be

さて,これは自作OS Advent Calendar 2020の21日目の記事なわけですが, Advent Calendarに登録していたことを完全に忘れていて,Twitterで教えてもらいました.オイオイ. 今日中に公開したら許してほしい*2.今は13:50(JST)です.

adventar.org

ということでなんも準備してないわけですが(は?), 実は今年のセキュリティ・キャンプ全国大会のYトラック自作OSゼミでチューターをやったりしていました. まあ今回はオンライン開催だったということもあり,受講生の人と一緒にワイワイデバッグしながらガッと開発,みたいなことはできなかったんですが*3,チューターをやっている間に(ようやく重い腰を上げて)Rustに入門したり,RustでUEFIアプリケーションを書いたりしていたのです.なのでこの話をします.

Rust

言わずと知れた最近ブイブイ言わせている*4プログラミング言語です. なんか最も愛されていたりするらしい.ℒ𝒪𝒱ℰ...

簡単に紹介しておくと,コンパイラに天才を投入し書き手に制約を課しコンパイル時間を天に捧げる*5ことで, 最高の開発体験と高速に動作するバイナリを得ることができるプログラミング言語です.

Rust,ずっと気になってはいたんですよね. どれくらい気になっていたかというとRustはいいぞというツイートを見て「ホォ〜ン良さそうじゃん.僕はC++17書くけど...」とか言ったり, AmazonのwishlistにRustの本入れたり, wishlistに入れてたRustの本がRust好きなフォロワーに買われて届いたけど積んだり, 積んだRustの本をチラチラ見て「いいじゃ〜んそういうのだよそういうの」とか呟いたり, Rustで書かれた組み込みOSを眺めてみたりThe Rust Programing Language 日本語版をチラチラ見たり, プログラミング言語の入門にはLISP書いてみるといいですよとTwitterで言われて一理あるなと思って所有権とかなんもわからんままLISPインタプリタ実装しかけてAST作ったところで詰んだりしていました.

そんなこんなでRustやるんだかやらないんだか微妙なところで踏みとどまっていたんですが,まあ例によってVRChatのオタクに布教されたので教えてもらいながら始めました. VRChatは最高.

ここまででVRChatとRustが最高なことしか情報がないですね.そういうこともある.

自作OS的に分かりやすいRust最高ポイントはpanicをちゃんと実装してあげれば突然の死の時にもある程度情報が得られるところとか,ターゲットアーキテクチャバチバチ切り替えられるところとか,ユニットテストフレームワークが言語標準で付いてるところとか,OS(std)に依存しないライブラリ(crate)がたくさんある上にそれらを標準のビルドツール(cargo)で引っ張ってくることができるところとかですかね.

UEFIアプリケーションを書きたい

というわけでRustってやつでUEFIアプリケーションを書いてみましょう. LLVMだしclang+lldの時みたいにやればできるでしょ.

Rust UEFI [検索]

\ババーン/ github.com

なんとライブラリがあります.UEFIアプリケーションを書くための.何?(こういうところもRust最高ポイントですね)

これを使ってHello World!する話は例によってオタクが書いてますね. neriring.hatenablog.jp

しかしせっかくなら全部自分で書いてみたいです.車輪の再発明も車輪をバラすのも大好きなので. セキュリティ・キャンプでも受講生の一人が最初uefi.hをUEFI Specificationを見ながら手打ちしていて,「わかる〜」となりました*6

んでもってそういう記事も既にあるわけです.やった〜 garasubo.github.io

でもこれは今は動かなくなっています.まあcargo-xbuildのバージョンをこの当時のものにすれば大丈夫な気はしますが.

とはいえRustは進化の速い言語です.最新のRustでもuefi-rsを使わずにUEFIアプリケーションを書きたい.僕は書きたかったです. ということで書きました.

github.com

apt update && apt install -y curl git gcc
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
git clone https://github.com/sk2sat/uefi-hello-rs
cd uefi-hello-rs
rustup component add rust-src
cargo build --release

こんなかんじでビルドできるはずです.Dockerでもいける.

rustupはRustツールチェーンのバージョンやらターゲットやらをいいかんじに管理できるやつです. Rustはディストリのパッケージマネージャから入れるよりも https://rustup.rsに書いてあるワンライナーで入れた方がいいまである. 実際これで一回詰まった((実はrustupでRustを入れると使えるrustcとかcargoとかはそれそのものではなくてrustupのシンボリックリンクになってるんですよね. ls -l which cargoとかしてみると分かる.Buildrootかな?まあなるほど感はあるけど微妙に挙動が違って非常に時間を溶かしたので,なにも考えずにpacman -S rustとかやらない方がいいです.communityにrustupあるから使おうね.)). 実態は$HOME/.rustupとかにいるので環境をブチ壊さなくて安心.エコってやつです.

cargoはビルドシステム+パッケージマネージャみたいなやつです.これの存在もRust最高ポイントの一つですね. なんとライブラリを追加するのはCargo.tomlのdependenciesでcrate名とバージョンを指定するだけ*7. ほとんどのcrateはhttps://crates.io に登録されているのでこれだけで大丈夫な上,gitで取ってくるとかもできます. あとはcargo buildとか叩くとガーッと依存物がダウンロードされビルドが走ります.

cargo buildで自作OSをビルドしたい

Rustで開発する時はほぼcargoしか叩かない(rustcを直接呼んだりmakeを使ったりしない)んですが, 諸事情により自作OSではcargoではなくxargoやそのforkのcargo-xbuildが使われていました. xargomakeで呼んでるやつとかも見ますね.

でも,せっかくRustを使っているわけですし,cargo buildでおもむろに自作OSがビルドできるようになってほしいですよね. 僕はなってほしいです. そこで,今cargo-xbuildのリポジトリを見にいくと,

github.com

Cargo now has its own feature for cross compiling the sysroot: build-std. You can use it by passing -Z build-std=core,alloc to cargo build. Alternatively, you can specify the following in a .cargo/config.toml file:

[unstable]
build-std = ["core", "compiler_builtins", "alloc"]

The above requires at least Rust nightly 2020–07–15. With the above config in place, the normal cargo build command will now automatically cross-compile the specified sysroot crates.

とあります.おや?なんか最近のやつならいけそうじゃあないですか.これはやるしかない.

ということでなんとcargoだけでビルドできるようになりました.やった〜.

まずはなにもしないやつ

cargo buildでビルドできるようになったところでHello, Worldやっていきましょう.まずはなにもしないものを作ります.

#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "C" fn efi_main() {
    loop {}
}

#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
    loop {}
}

最初の#![~~~]はcrate-level attributeというもので,ソースコード中で色々な指定ができます. ここではno_stdno_mainですね. no_std-nostdlibみたいなやつで, no_mainmainなんていう関数は無いけど怒らないでねってやつです. いつものやつですね.

次のusePanicInfoという型を後で使うのでそれを引っ張ってきています. C++usingみたいなやつですね. ここで急に出てきたcoreは何かというと,なんと標準ライブラリみたいなやつです. 普段なら自作OSで標準ライブラリが使えるわけないだろ!下がってろ!となるところですが, なんとcoreはOSの機能に依存しておらず自作OSでも使えるのです.やった〜((coreがOSの機能に依存していない,というよりは標準ライブラリを作るにあたってOSの機能に依存しないが必要なものをcoreとして明確に切り分けて実装した,というのが適切なんじゃないかなと思います.たぶん.))

次はefi_main関数ですね.エントリポイントです.この関数にはno_mangleというattributeが付いているのでマングリングが行われません.お手軽ですね.

最後はpanic handlerです. panicした時にダイイングメッセージを書く奴ですね. no_std環境では標準出力なんてものがあるわけがないので自分で実装する必要があります. この引数にさっきのPanicInfoが来るわけですね.

Hello, World!

さてHello, World!していきましょう. UEFIアプリケーションなので,とりあえず必要な分だけシステムテーブルの構造体を作ってSimpleTextOutputProtocolを取ってきてOutputString関数を叩くだけです. かんたんですね(そうかな?)

ということでsrc/uefi.rsがこんなかんじになりました.

use core::ffi::c_void;

#[derive(Clone, Copy)]
#[repr(C)]
pub struct Handle(*mut c_void);

#[repr(usize)]
pub enum Status {
    Success = 0,
}

#[repr(C)]
pub struct TableHeader {
    signature: u64,
    revision: u32,
    header_size: u32,
    crc32: u32,
    _reserved: u32,
}

#[repr(C)]
//#[repr(packed)] // packedを付けると32bit縮められて死ぬ
pub struct SystemTable {
    pub hdr: TableHeader,
    pub firmware_vendor: *const u16,
    pub firmware_revision: u32,
    pub console_handle: Handle,
    pub _con_in: usize,
    pub console_out_handle: Handle,
    pub con_out: *mut SimpleTextOutputProtocol,
}

#[repr(C)]
pub struct SimpleTextOutputProtocol {
    reset: unsafe extern "efiapi" fn(this: &SimpleTextOutputProtocol, extended: bool) -> Status,
    output_string:
        unsafe extern "efiapi" fn(this: &SimpleTextOutputProtocol, string: *const u16) -> Status,
    _resb2: u128,
}

impl SystemTable {
    pub fn stdout(&self) -> &mut SimpleTextOutputProtocol {
        unsafe { &mut *self.con_out }
    }
}

impl SimpleTextOutputProtocol {
    pub fn reset(&self, extended: bool) -> Status {
        unsafe { (self.reset)(self, extended) }
    }

    pub fn output_string(&self, string: *const u16) -> Status {
        unsafe { (self.output_string)(self, string) }
    }
}

最初は自分でゴチャゴチャやってたんですけど結局uefi-rsを参考にしました.uefi-rs使った方がいいです. あと,C/C++のノリで「あ〜こういうのはpacked付けとけばいいでしょ」と思って付けまくってたら動きませんでしたね. なんかメンバのアドレスが32bitズレてたりしてました. ちゃんと挙動を調べたかったのでメンバのオフセットが合ってるかみたいなユニットテストを書きたかったんですが,これもイマイチやり方がわからず時間を溶かしました. ウーム.今度ちゃんと調べます(ホンマか?)

あともちろん,いきなり構造体のメンバのアドレスを関数だと思って呼ぶなどというCでは一般的な野蛮な活動はRustでは許されないので,unsafeを付けています.

UTF-16

これでHello, World!する準備が整ったので,あとはefi_main関数でoutput_string()とかを呼んであげればいいわけですが, ここで一つ問題があります. それは文字列です.

Rustでは文字列はUTF-8です. これもRust最高ポイントですね.

どこぞのC++とかいうプログラミング言語は最近ようやく文字とは何かを理解したわけですが...(なお...) qiita.com

さてここでUEFI Specificationを見てみましょう

\ババーン/

FI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString()

_人人人人人_
> CHAR16 <
 ̄Y^Y^Y^Y^Y^ ̄

┏-┷-┓
┃ U ┃
┃ n ┃
┃ i ┃
┃ c ┃
┃ o ┃
┃ d ┃
┃ e ┃
┗━━┛

はい.まあUEFIMicrosoftが策定にガッチリ絡んでますからね. MicrosoftUnicodeと言ったらUTF-16ですし,型はCHARとかWCHARですよ.まあCHAR16なだけだいぶマシですかね. UEFIは滲み出るwindows.h感でとても懐かしい気持ちになる物体としておすすめです.

こういうこと言うとWindows 10のMay 2019 Updateでnotepad.exeのデフォルトがUTF-8になったじゃないかとか, WSLは最高の開発体験だとか言われることがありそうな気がしますが, そういう人はWin10のシステムロケールUTF-8にしてみるといいんじゃないでしょうか.あまりに色んなものがブチ壊れて楽しいですよ.

まあ僕も最近VR関連の諸々のためにWin10使うことがだいぶ増えてはきましたけどね*8. それでもArch Linux使う時間の方がずっと長いですが.

話が逸れました.さてUTF-16です. まあUEFIアプリケーションのサンプルでたまにありがちな,文字列を一旦バッファに入れてunsigned 16bitの型の配列の下位8bitに雑に詰めるやつをやってもいいんですが, あれはなにかに敗北した気持ちになるのでやりたくないです.まあどうせ表示するのはASCIIのHello, World!なんですけど.

なのでUTF-16な文字列リテラルとかがあるとうれしいんですが,Rustにはそういうのは無いらし...おや?

github.com

こんなcrateがありました.求めていたものっぽい.

これはRustのマクロを使ってUTF-16な文字列リテラルの真似事をするというものです. 具体的にはutf16_literal::u16というマクロに普通に文字列を突っ込むとu16の配列になって出てくるようになっています. UTF-8の文字列をUTF-16の文字列に変えるなんて処理は動的メモリ確保が無い状態だとちょっとつらいですし, なにより今回は表示するものが決まっているので,UEFIアプリケーション上で処理する必要すらないわけです.

ということでこんなかんじになりました.やったぜ.

extern crate utf16_literal;
use utf16_literal::utf16;

mod uefi;
use uefi::Status;

#[no_mangle]
pub extern "efiapi" fn efi_main(_image: uefi::Handle, stable: uefi::SystemTable) -> Status {
    let stdout = stable.stdout();
    stdout.reset(false);
    stdout.output_string(utf16!("Hello, World!").as_ptr());

    loop {}
}

cargo runでQEMUが起動してほしい...起動してほしくない?

Rustで普通のHello, World!したことある人なら分かると思うんですが(分からない場合はcargo new hoge && cd hoge && cargo run), cargo runってやると書いたアプリケーションが起動するじゃないですか. あれが最高なので,というか普段Makefile書いてmake runしてる人間なのでcargo runしたらQEMUなりBochsなりが起動してほしい.起動してほしいです.頼む.

で,まさにそういうことができるものがあります.custom runnerってやつですね.

これは.cargo/configにこんなかんじに追記してやればいいです.

[target.x86_64-unknown-uefi]
runner = "qemu-system-x86_64"

これで行けるならいいんですけどね.残念ながらUEFIアプリケーションなのでmnt/EFI/BOOT/BOOTx64.EFIとかにバイナリを置いてマウントする必要があります((でも,カーネルだけならqemu-system-x86_64 -kernelで行けるし,なにかトチ狂ってLinuxでWin32AP直叩きアプリケーションを書くとき(たまにある)にwineを指定できたり,夢が広がりますね(?).)). なので最初はじゃあディレクトリ切ってコピーするワンライナーを前に押し込んでやればいいなとか思ったんですが, これはsystem()が呼ばれるとかではない(シェルが呼ばれるわけではない)のでそういうことはできませんでした.

あと,cargo runMakefileでよくあるようにcargo build->cargo runと実行されるわけではなく, なにかそれで時間をめちゃくちゃ溶かした気がするのですが覚えてないです. 完全に先入観のせいなんですが「え?これどうなってるんだ」とcargoのソースコードを読みに行ったのはよかったような気がします.

結局これは以下のようなrun-qemuというシェルスクリプトを作ってgot kotonakiしました.

#!/bin/sh
echo $1
mkdir -p mnt/EFI/BOOT
cp $1 mnt/EFI/BOOT/BOOTx64.EFI
qemu-system-x86_64 --bios bios/RELEASEX64_OVMF.fd -drive format=raw,file=fat:rw:mnt

これでcargo runすると... f:id:sksat:20201221203836p:plain

やった〜

cargo runQEMUが起動するようになって満足し,その後進捗がありませんでした. いかがでしたか?

*1:Q. これはなに A. クソドメイン部 Q. クソドメイン部ってなんですか A. 僕も知りたい

*2:履修も受講も課題提出も全部失敗してるオタクがアドベントカレンダー書けるわけないじゃん.じゃあ登録するな.https://soude.su

*3:footnoteなのであんまり関係ない話していいですか?いいよあり. 今日もCOVID☆19さんが全世界で猛威をふるっていらっしゃるわけですが,なんというかこの伝染病は良くも悪くもFateシリーズの聖杯ってかんじですよね. 伝染病が大流行しているような事態はこれっぽちもよくはないわけですが, 色々なところで言われているように(要出典),これには巨大なデメリットと同時にメリットも振り撒いていますよね. 未だかつてこんなにも世界中の「IT化」が進んだ瞬間があったでしょうか.まあパワーのある政治をやっている国ならあったかもしれませんが. そんなメリットの一つが外に出なくてい(ry,じゃなかった,今回のセキュリティキャンプだったり大学の講義だったりのオンライン化だと個人的には思っています. もちろんこれちゃんとやるのは非常に難しいんですけどね. まあ難しいだろうなと思って大学の講義を見ていたわけですが,セキュキャンで実際やる側に少し回ってみてやはりこれは大変だなと思いましたね. メリットの話をしましょうか.まあ大きいのは参加のハードルの低下,録画の公開(の一般化)ですかね. でもこれデメリットも同じくらいあるんですよね(オイ).通話に参加すること事態のハードルは低くても, (見ず知らずの人間と)ミュート解除して話すコストはめちゃくちゃ高いし.とくにGoogle MeetなりZoomなりだと初期設定の虚無アイコンがババーンと表示されてるだけですしね. これはかなり前からだいぶ気にしていて,5月くらいからFaceRigを試したりしていました.実はVRにどっぷりハマったのもそういう経緯があったり無かったりする(どうかな). 研究室でも最初に美少女になったのは僕でしたね.その後数人が3teneとかでやってましたね. まあここ最近精神と生活リズムが完全にブチ壊れていてろくにミーティング出られてないんですけど.すみません. 僕は最近はVRChatでストリームカメラ or VRM化したアバターをVMagicMirrorに突っ込んだものOBSでキャプチャしてやっています. 毎回Index被るのはさすがに面倒だったり不都合があったりするのでVMagicMirrorは重宝してますね. 普通に便利だしあそこらへんのツールで唯一(?)wineでまともに動くし.Linuxデスクトップ太郎としてはな. 仮想カメラで美少女が喋ってると個人的にはだいぶ話すハードル下がると思うんですよね.他の人がどうかはよく分からないけれど. 今年のセキュキャンはせっかくオンライン開催だったのでほぼ全編美少女で参加しました. 受講生の人の心理的なハードルを少しでも下げられていたらよかったなと思います. あとLTでVRへの勧誘したり時間外にVRChatへの勧誘したり元々VRChatにいた参加者・チューター・講師とワチャワチャしたりしました(あれ?) 話を戻しますか.まあこれ全部脱線だけど. あー録画の話ですね.これは非常にありがたいとともに個人的な恨みつらみがたくさんあります. 講義が録画されるようになることとそれが受講者に対して公開されるムーブ自体は最高なんですが,問題はその共有方法です. まあ権利的に難しかったりするわけで同情できないわけではないんですが,あの不自由まみれの状態は一体なんなんですかね. 他の大学だとだいぶマシだったりするみたいですが,クソみたいなDRMのかかったクソみたいに使いにくい動画ビューアに始まり, それをWindowsでしか動かないカスゴミアプリケーション上でのみ再生できるようにするだのリクエストがあった時のみ公開するだの1週間経ったら公開を停止するだの. まあこんなことに一丁前にキレてたら色んなものが破滅したんですけど. 最後のやつは毎週ちゃんと見ろよと言われたらまあそうですねとなるし. それにしたってこういう状況なんだからせっかくのメリットを生かしてほしい気持ちが非常に強いですけどね. 毎週講義準備するのが恐ろしく大変だということは少しは分かるつもりではいるので,そんなに強いこと言う気にはならないんですが. さてこの欄は本編書くのに飽きたら書いてたんですが本編書き終わったので終了です.ひでえfootnoteだ.

*4:V言語でゎなぃ

*5:これはリンク以外はCPUが十分強ければまあまあ速くなります.僕の(ろくに活用されていなかった)Ryzen 3700Xがフル活用されて最高.とはいえ自作OSならクソデカライブラリ使わないのでリリースビルドでもだいぶ速く済みますけどね.

*6:Q. 別に仕様書見てるならただやるだけのものを手打ちする必要は無いのでは? A. ち,ちがうんですよ!ぜんぶじぶんでかいてみたいじゃん!

*7:ライブラリの追加もcargo-editを入れておくとcargo addだけでできて最高です.

*8:でもこれProtonが進化してVRChat上で動画が見られるようになったり,xrdesktopとかでいいかんじにXS Overlayが代替できればWin10使う理由かなり減るんですよね.Valve Softwareの異常者がんばってほしい.なんである程度は動いてるのかわかるけど意味分からんけども.あとはWebEx Trainingとかいうカスですかね.まあこっちはVMでいい気もする.そしてそもそも不自由な形式での講義動画の配布をやめればいい話.

Google Summer of Code 2020に採択された

Google Summer of Code 2020(以下GSoC)に出していたProposalが採択されました. やったぜ.

記録と来年以降GSoCに申し込む人のために書いておきます. 僕も先人のブログにめちゃめちゃ助けられましたしね.

GSoCって何

Google Summer of Code. よくGSoCとも呼ばれます.

GSoCは端的に言うと,「学生の人,夏休み暇でしょ?メンターからの指導を受けつつオープンソースプロジェクトにcommitしてみない?ちなみにGoogleから金も貰えるんだが」というかんじのイベント(?)です.

summerofcode.withgoogle.com

Google Summer of Code is a global program focused on bringing more student developers into open source software development. Students work with an open source organization on a 3 month programming project during their break from school.

僕は周囲の参加してるオタクとか,しゅううせんせーのブログとかで存在を知った覚えがあります.

syuu1228.hatenablog.com

夏休みと書きましたが,これはもちろん海の向こう側の話なので我々日本の民が参加する際は注意が必要です. 思いっきり期間中に大学の試験期間がありますからね. その点で言えばCOVID-19で世の中や大学が混乱してる時期にできるのはアドかもしれないなあと思ったり. 1限の試験とかやりながら他のことモリモリやるとか僕には無理です. まあ全部リモートになっても1限は無理なんですけど.

なにやるの

summerofcode.withgoogle.com

じゃあお前はGSoCで何やるねんということなんですが, emboxという組み込みOSをMAiX BiTに移植します.したい.

github.com

emboxは簡単に言うとPOSIXなアプリケーションが動く組み込みOSです. 色々な「それ絶対組み込みで動かんやろ」みたいなやつがなんかシュッと移植されて動いたりする.

なんかQtがSTM32で動いたりするらしいです.マジかよ...

Porting Qt to STM32 / Embox Blog / Sudo Null IT News

で,このemboxなんですが,かなり色々なプラットフォームで動きます. アーキテクチャも色々あるしなんなら普通のx86アプリケーションとしても動いたりする. 比較的最近になってみんな大好きRISC-Vにも対応しました. といってもHiFiveだけだけど.

でもHiFiveって高いじゃないですか.いやまああの値段でRISC-Vなマイコンが買えるならって思うとそんなにってかんじだとは思いますが. とはいえしがない学生からするとマイコンにスッと6000円とか出すのはまあまあ厳しいものがありますよね. まあ今まで積んできた本やらマイコンやらの合計金額確認ゲフンゲフン.

それでもRISC-Vを実機で触ってみたい. どうにかしたいですよね. そして最近はそんな夢を叶えるべく(?), sipeedが超パワーでお財布に優しいRISC-Vマイコンをぽんぽん出してくれているわけです.

その1つが今回のターゲットのMAiX BiTです.

www.switch-science.com

3500円でRISC-V 64bitデュアルコアかつ色々なアクセラレータも載ってるマイコンが買えるのヤバくないですか?ヤバい. やべーっつってアキバのShigezoneで買ってMicroPythonとPlatformIOでちょっと遊んだ後積んでました*1. そして,Proposalどうしようかな〜と悩んでいるときに,ふと「これに移植できたら面白いのでは...?」と思ったので,なんかそんなかんじのProposalを書いて送ってみたら通ったってかんじです.

申し込み

申し込みにあたっては,先人たちのブログ記事がめちゃくちゃ参考になりました.ありがたや.

hakatashi.hatenadiary.com

yamaguchi-1024.hatenablog.com

n-yoshikawa.hatenablog.com

Organizationが発表*2されたら,まずは公式サイトを見て面白そうなプロジェクトを見繕います. Organizationはかなりたくさんあります.

summerofcode.withgoogle.com

LLVMとかNeoVimとか,いつも使ってるビッグネームが並んでいてすごい. その一方で,今まで知らなかった面白OSSもかなりあってこの一覧を見るだけでも面白かったです. 今回僕が応募したemboxもここで始めて知りました.

一応僕が見ていておもしろそ〜と思ったOrganizationのリストを載せておきます. メモはかなり雑なのであんまり気にしないでください.

hackmd.io

プロジェクトを見定めたら,メンター候補の人に連絡を取ってみましょう. たぶんどのプロジェクトでもメールアドレスが書いてあると思います. というかGSoCのページにまずはメールしろ!と書いてあるプロジェクトも多いんじゃないですかね. その後の対応はプロジェクトによってかなり違うんじゃないかなという気がしますが, なんやかんやあった後はちょっとcontributeするかんじになると思います.

emboxの場合は"goot first issue"ラベルの付いたIssueが量産されていたので, 「これやりてえ!」ってコメントしてアサインしてもらってからプルリク送るとええ,ってかんじでした.

github.com

というわけで僕はこんなかんじのプルリクを送って無事マージされました. OSSにプルリクを送ったのは多分これが始めてだと思います. プルリクがマージされるとえらいきもちがええんじゃ.

その後,"Student Application Period"が始まったら登録ができるようになります. そうしたら後は適当なGoogleアカウントを登録して, 自分が学生だということを証明したりProposalをガシガシ書いたりするだけです.

学生の証明は学生証をスキャンしてPDFとかにして送りつけるだけです. ただし,学生証が日本語の場合ダメで〜す!wと言われるので, 後で書いてある内容を英訳したものを送る必要があります.

Proposal

これらの諸々ができたら,あとはProposalを書いて送りつけるだけです.簡単だね!(ぇ)

基本的にはOrganizationのGSoCのページに「idea list」があるので, その中から面白そうなものを選んで,GSoCの期間中にそれをどう実装していくかを書くことになります.

ですが,大体そのidea listの一番下とかに「お前のアイデアを送りつけてもいいぜ!」みたいなことが書いてあります. さすがにいきなり独自アイデアをブチ込む勇気は僕には無かったんですが,idea listにあったネタでProposalを書いていて「いや全然わからん...何からどう実装したらいいのかわからんしそのスケジュールとか立てられん...」となったので,本当にふと思いついたネタで特攻したというわけです. まさか選ばれるとは...

ProposalはまずdraftをGoogle Documentとかで書いて早めに出して,中の人からコメントを貰ってからPDFをGSoCのダッシュボードから提出します. 僕はGoogle Documentがあんまり好きではなかったので*3どうしようかなと思ったんですが, 中の人がコメントできるならURL貼っ付けていいよ,みたいなことが書いてあったのでGistに書いて出しました. emboxはGitHub上で開発されててメンター全員100%GitHubアカウントありますしね. 実際普通にコメント来たので大丈夫だったっぽいです. まあGistくらいならOSSバリバリやってる人には大丈夫でしょ!wと思いますが, 普通は無難にGoogle Documentに書いた方が良いと思います.たぶん.

ちなみに,Final Proposalは期限まであと数日というところで, 唐突にSATySFiで書くか!wっつってSATySFiで書いて送りました. SATySFiで文章書くのはこれが始めてでした(なんで?) 色々教えてくれた丼のオタク,ありがとうね...

あと,自分の中では数日前のつもりだったんですけど, 今確認したら3/30の真夜中にSATySFiわからんとかトゥートしてたので, 正確には1日前っぽいです.バカなの?

可能性がある.知らんけど.

慣れたらかなり良さげっぽいなあとは思ったので,ちょいちょいやっていきたいですね.SATySFi.

というわけで僕は結局期限の数時間前くらいに提出したと思うんですが(記憶がない)91分前に出してたんですが, もっと早めに出した方がいいです. タイムゾーンも違うしね...

まあタイムゾーンに関しては案内にもかなり口酸っぱく書いてありますし, 直前にダッシュボードにアクセスするとご丁寧にJSTでの期限と残り時間が表示されていたので任意の提出物ギリギリ提出オタク各位はダッシュボードとにらめっこするとよいです.

あと,ギリギリ提出オタク各位向け有用情報としては,PDFはいくらでも再登録できるので, ある程度書けたと思ったらとりあえず登録しておいて,少し直したら登録しなおす,というのをやると最悪の事態は避けられます. また,直前に慣れてないもので書こうとか思わない方がいいです.いやそれは普通か...

mstdn.maud.io

さいごに

自分の過去のProposal見せてくれたり,僕のdraftに色々ケチつけてくれたり,SATySFiのこと教えてくれたりした末代各位,ありがとうございました.

あと,今年は全てのEvaluationを通すと$5400貰えるらしいです.ヤバい*4

developers.google.com

ちゃんとEvaluation通せるように頑張っていきたい.

*1:正確には積んでいたのはMaixduinoで,色々弄るにはMAiX BiTの方が良いよと丼のオタクに勧められたのでProposal書きながらMAiX BiTを買った

*2:今年の場合は2/21

*3:あと,G Suiteのアカウントでやろうとしたらワーニングが出たというのもある

*4:VR環境とか整えたいですね(取らぬ狸の皮算用)

メカニカルキーボードを買った

𝑴𝒚 𝒏𝒆𝒘 𝒈𝒆𝒂𝒓...

はい.ついに買いました.やったぜ. いや買ったのはかなり前なんですが海を彷徨ってようやく届いたので今書いてます.はい.

カニカルキーボードって何

よく家電屋でゲーミング任意売り場に置いてあるようなやつです. 光らないやつもある.最初全部光るのかと思ってたのはナイショです. 好きなオタクと違う方向性のキーボードが好きなオタクがいるらしいです.

こいつらの特徴として,打鍵感を決定する「「「軸」」」とかいうものが何種類かあります. あるらしいです. オタクがよくツイッターで赤軸とか青軸とか吠えてるじゃないですか.あれです. あとなんかこの軸ってやつにはCherry MXという規格的なものがあるらしく,とっかえひっかえできるらしいです.楽しそうですね.知らんけど.

軸の種類の解説とかは色々あるけどここらへん見ておけばいいと思います.たぶん. www.diatec.co.jp

買った経緯

相変わらずノリと勢いです. 衝動に従え.

まあもともと気になってはいたんですよ.お高いキーボードってやつ. でもお高いから躊躇してたんですよね.あと沼っぽいし.

じゃあなんで今回買ったかというと,安く買えたからなんですね. 今回メカニカルキーボードを買うのにはDropというサイトを使いました. 昔はMassDropという名前だったそうです.

drop.com

いわゆるgroup buyサービスってやつです. キーボード関連のものとかアウトドアギアとかなんかよくわからんカッコイイ構造物とかが期間限定でたまに安く買えたり買えなかったりします. つまりめちゃくちゃマイニューギアりたい時におすすめです.

alu.jp

ということで,今回買ったキーボードは何かというと,"Durgod Taurus K320 TKL Mechanical Keyboard"というものです.

Amazon CAPTCHA

amazon.jpだと静音軸しか残ってなくて高いですね.2万かあ.

www.amazon.com

amazon.comだと普通の軸が選べますね.99ドルかあ.

じゃあお前はいくらで買ったんかいなというとこんなかんじです

f:id:sksat:20200318172804p:plain

76ドル!やったね!

軸は茶軸にしました.初心者なので. まあ一応ビックカメラのゲーミング任意ゾーンに行ってみたら赤青茶の体験が出来たのでポチポチはしてみましたけどね. 感想としては赤ウーン青ウザッ茶なるほどというかんじです. まあ茶にして良かったんじゃないでしょうか.

あと10ドルくれ!!!!!

↓↓↓

drop.com

※ここから登録すると俺とお前に10ドルやるよリンクです.頼ム〜ッ

使用感

さっき使い始めたのであんまり分かってはいないですが, 今この記事を書いている感想としては書きやすいです. スラスラタイピングできる.あと軽い. なんだったんだ今までのあの力の要るタイピングは代という気持ちです. あと前のは手に合ってなかったんだな感.まあアキバで雑にかった700円とかのキーボードなのでそれはそう.

やっぱり,多分一生パソコンカタカタオタクやっていくわけですし,毎日使うものにはお金かけた方がいいんだなということが分かってきましたね.QoL大事. デスクトップマシン初めて組んでコア数とメモリ容量がドカンと増えた時も良かったし,キーボードなんて物理的に叩くものですからね. やっぱり大事ですよ.

最近はコード以外にもドキュメントとか技術同人誌とか書くようになってきたのもあって,タイプ数/日が激増してる気がするんですよね. 手首とか肩が微妙に痛くなる頻度も上がってきたし. 新しいキーボードでここらへん改善したらいいなあ.

あと,キーボードそのものには関係ないんですがUS配列使うの初めてなので主にそこで苦しんでます. 記号打とうとすると脳がバグる.しばらくは記号打つときはタッチタイピングできないですね. ついでに,今までibus-mozcだったのをfcitx-mozcにしてみました.悪くない.

今後

静電容量無接点方式とか自作キーボードにも手を出していきたいですね. あと割れてるやつとか.マウスも正直微妙だと思ってるのでたまにみるゴロゴロするやつとかも試してみたい.

技術同人誌を作ったり頒布したりしている話

技術同人誌というものを作っているので,ちょっとその話をしておこうと思います. 要はOtakuAssemblyの話です.今更ですけどね.

あ,この話はOtakuAssemblyをやることになった経緯とか執筆環境の話なので, そういう話が気になる人は読んで下さい.

そういうのいいから技術の話しろよというそこのアナタ!

COVID-19騒動で家で暇してるそこのアナタ!

アナタにピッタリの技術同人誌がなんと通販で買えちゃうんです!(ダイマ) otakuassembly.booth.pm

電子版も完備!汚染されていない生のPDFが手に入ります!

あなたとOtakuAssembly,
今すぐダウンロー
*1

※Vol.2の物理本は現在入荷待ちなのでしばらくお待ち下さい(3/17現在)

OtakuAssemblyとは

2019年の5月頃にできた技術同人誌サークルです. たしか第15回自作OSもくもく会にいた大学1年生のオタク3人(@sksat_tty,@PG_MANA_,@Cra2yPierr0t)が完全にその場のノリと勢いでやるぞと言って気が付いたらやることになっていた,みたいな経緯だったと思います.たぶん.

まあ実はそれより前に@PG_MANA_に「一緒に技術同人誌書かないか...?」と誘われていたんですが, その時は僕も書いてみたいと思ってるけれどネタも微妙だしノウハウもないし金もかかるし何も考えずに特攻するのは無理があるだろみたいな話をどっかのフードコートと改札前で延々と終電ギリギリまで話した覚えがあります. 結局,実際はあんまり何も考えずに特攻したのでなんとも言えないんですけどね. とはいえあれでやろう!となっても長続きしなかったんじゃないかなあとも思います.

じゃあなんで自作OSもくもく会で急にやろう!となったかというと, 久しぶりに会ったからこの話の続きみたいなことをしてたんですよねたぶん. ただ,この時は近くにいた@Mopp_jpさんが「"書いてみたい"って言ってる奴は書かないんですよ〜」と煽ってくれたんですよね. @Mopp_jpさんは技術書典5,6,7で個人出展している強い人で,これにはめちゃくちゃ説得力がありました. そして,いつもTwitterで「これやりたい」「やりてー」とか言ってロクに成したことが無い僕にはとても刺さりました. 今書いてても刺さりますね.やっていきたい.

ということで「とりあえずやってみよう!」という気持ちになり,@PG_MANA_とたまたまその場にいた@Cra2yPierr0tを捕まえて引き入れて「やるぞ!」ということになりました. 完全にノリと勢いです.

ここらへんの話は@PG_MANA_氏もブログに書いてますね. pg-mana.net

ノリと勢いってやつは凄くて,翌日にこんな募集ツイートをしてしまうんですよね.

このツイートが界隈内でまあまあ伸びたんですよね. 金銭面や合同誌のボリューム的に,1~3人増えたらうれしいな. あわよくば経験者が来てくれるとうれしいな,と思ってこんなツイートをしたんですが, 何がオタクに刺さったのか数時間でオタクが10人くらい集まりました.は?

実際は消失したり原稿を落としたりするオタクがいたんですが(これは予想通り*2 ), それでも8人残りました.は?

そんなこんなでなんとか技術書典7に初参加し,『OtakuAssembly Vol.1』を無事頒布することができました. その後も技術書典8に参加し,イベント自体は中止になってしまったものの『OtakuAssembly Vol.2』を作ることができました(BOOTHで売ってるので皆さん買って下さい.頼ムッ).

OtakuAssemblyを支える技術

さて,技術同人誌を作るとなると,執筆環境が重要になってきます(要出典).

OtakuAssemblyでは大体以下のようになっています.

Re:VIEWについて

Re:VIEWを使っているのは主に次のような理由からです. あと僕の趣味*3

  • 原稿・設定ファイルがテキストファイル → Gitで管理できる
  • Docker Imageがある → CIが回せる
  • 技術同人誌を作ることを考えて作られている
  • 学習コストが低い
  • (あんまりやりたくないけど)いざとなればLaTeXを弄ってどうとでもできる

特に最初の2つは大人数のオタクの原稿を管理するにあたってはマストだと思っています. 別に1人で作るならどうとでもできますし,そういう場合はどんなツールを使ってもいいと思います. WordでもAdobe系のツールでもいいでしょう. 執筆時点で体裁とかをあまり気にしないとかなら,Google Documentとかでもいいのかもしれません. 某satさんとかはそんなかんじでやってると聞いたことがあるような気がします.

しかし,OtakuAssemblyは執筆者2ケタの大規模サークル(?)です*4. そして執筆者が全員プログラマーでオタクなので, Wordじゃないと呼吸困難になって死ぬということも無いですし, Gitは使えると思っていいですし,Markdownなどにも慣れているでしょう. このような前提のもとでは,原稿をGitで管理することができるかというのはとても大きな利点となります.

まず,適当なリモートリポジトリを用意して,各自執筆したらcommitしてpushする,ということをするだけで,各位の進捗状況が簡単に確認できます. また,みんなcommitしとる,原稿書いとらんのお前だけができます.僕のことですが... あと,これは個人的にかなり重要だと思っているんですが,「家では書いたんすけど〜w」とか「PCが壊れちゃって〜w」が防止できます. まあ中高の部活の部誌と違ってOtakuAssemblyは原稿を書きたくて集まっている人たちなのでそんなことは無いと思いますけどね!(無いよね?) 「push忘れてた」はやめてください.自信無くていいからpushはしてくれ.

あとdiffを確認できるのがめちゃめちゃ良いです. 自分で書いていて確認できるのもそうですが,執筆用のブランチを切って編集用のブランチに適宜MRを出す,ということをやっていたので,校正・校閲がやりやすくて良いです. まあGitというよりはGitLabの良さかもですけどね.

さらに,そもそもRe:VIEWが技術同人誌を書くために作られたものであるというのも大きいです. 何も考えずにやっても標準でトンボ出してくれたりしますしね. ビルドして出てきたPDFも大体そのまま印刷所に投げつけられます入稿できます. 設定もyamlファイルでできるので,オラッA4にするぞみたいなcommitして,あとで「やっぱA4はアカンわ.revertしたろ.」みたいなことも簡単にできます. というか実際やった.

Docker Imageがあるのもとても良いです. LaTeXの環境構築してないPCでも作業できる,というのもありますが一番大きいのはCIで回せることです. 詳しくは後述しますがCIでPDFをビルドするのはいいぞ.

さて,これらの理由を見ると「LaTeXじゃあかんの?」と思う人もいるかもしれません. もちろん,Re:VIEWでもPDFを作るなら結局LaTeXを吐くわけですし,デザインや文字の配置に拘りたいならLaTeXと真剣に向き合った方が良いですし,それなら直接LaTeXを書いた方がいいかもしれません. ですが,OtakuAssemblyでは執筆者全員が生のLaTeXを書くようになることは無いと思っています.

何故かというと,意味分からんエラーメッセージを見たくないからです. あと意味分からんエラーメッセージを見たくないです(大事なことなので2回言った). 何を言いたいかというと,他の人が書いた原稿をpullしてきてビルドしたら意味分からんエラーメッセージがターミナルを埋め尽くした......みたいな事象を許容できるか?ということです. 僕は許容できません*5. また,執筆者に執筆に集中してほしいということがあります. 原稿を書け. 文章を思いついたらVimで自分の原稿のファイルを開いて書くだけ,という環境を用意しておくのはとても大事だと思っています. 原稿を書け.

このことから,Re:VIEWの記法がとてもシンプルなのも重要だと思っています. まあまあMarkdownっぽいので,普段Markdownを書いている人なら,Re:VIEW フォーマットガイドを読めば難なく書くことができるでしょう. どうしても慣れなかったらある程度はMarkdownで書いてもらって(ただし派生記法をできるだけ使わず),md2reviewで変換する,といったこともできるでしょう. 実際何度かMarkdownで書かれた文書をRe:VIEWに変換してPDFにする,というようなことをやっていますが,変な記法を使ってなければそこまで大きな問題は起きないです. 正直#を=に変えるだけでも大体どうにかなると言っても過言ではありまs...流石に過言か.

記法のシンプルさだけで考えれば,原稿をMarkdownで書いてどうにかこうにかして*6PDFを作るのもアリだと思っています. ただ,Markdownは多くのオタクが普段から書き慣れているという利点はあるものの, その「書き慣れている」記法は得てして任意 flavored Markdownなので,「は?俺の知ってるMarkdownと違うんだが...」が発生するのではないかと思っています. もちろん凝ったことをしなければ何の問題も無いだろうとも思いますが. hikaliumさんがやっていたMarkdownで書いてSATySFiでビルド,とかは今後検討してみたいです.

GitLabを使った運用

リモートリポジトリにはGitLabを使っています. GitHubではなくGitLabなのは,organizationでもprivateリポジトリを作ることができる上, GitLab CIで簡単にCIを導入できるからです. 今ならGitHub Actionsがあるので,GitHubを使う選択肢もあると思います.

GitLabに"OtakuAssembly"というorganizationを作って,そこにprivate repositoryを生やしているだけです. 新規参入者には持っていなければGitLabのアカウントを作ってもらい,organizationにinviteした上で,執筆ネタが決まったら対象となるリポジトリでDeveloper権限を付与する,というようなことをしています.

また,主に編集作業の効率化のために,Git flow的なワークフローを採用しています.

具体的には,masterブランチは常に「リリース(=入稿)」できるもの,developブランチでは編集作業や設定の調整を行う,draftブランチでは各自が執筆する,というやり方をとっています. draftブランチは各自のIDに合わせてdraft/sksatみたいなかんじにしています. あと印刷所から怒られが発生するとhotfixブランチが生えます.わあい(白目).

なんでGitHub flowじゃないの?と思う人もいるかもしれませんが,「リリース作業」が行われることが数えるほどしか無いし,rebaseを行う必要性が微塵もないのでこれでええやろと思ってます. まあVol.1の時に僕がこれくらいしか知らなかったというのもありますが. とはいえこれでかなり上手く行っていますし多分Vol.3が出ることがあってもこれで行くんじゃないかと思います. あとmasterにマージした時のdiffのウオー俺達こんなに書いてたんだ感がいい.

なので,基本的には執筆者は自分のdraftブランチで執筆を行うだけです. そして,執筆に一区切りついたり*7,執筆が完了したりしたらdevelopブランチに対してMerge Requestを飛ばしてもらいます. MRの内容確認やマージは編集担当(基本的には僕)が行います. developブランチでは原稿を統合した時に不具合が起こっていないかチェックしたり,「今こんなかんじか〜」ってなったりします.

GitLab CIによるPDFのビルド

文書作成におけるCI,めっちゃくちゃ重要だと思っています*8. もうCIの無い文書作成はあんまり考えたくないぐらいです. いやもちろんある程度の規模の文書ならってことですけどね. でも,「今のうちに卒論で困らないように執筆環境とCI整備しておこうかなあ」と思うくらいには重要視してます. 常にビルドが通るように気をつける,ビルドが落ちるようになったらすぐに知ることができる,というのも重要ですが, それにより常に標準的な環境でビルドされたPDFを手に入れることができる,ということが大きいと思っています.

Re:VIEWで書こうが最終的にPDFを作るのはLaTeXの仕事なので,出力されるPDFは割とビルド環境にインストールされているLaTeX環境に左右されます. 特にフォントとかね.あとまあバージョンも人によって結構違うことがあると思います. そのような差異を考えなくてよくなるのは結構大きなメリットです. さらに,今外出してて環境構築したPC持ってないんだよ,みたいな時にもスマホからGitLabにログインすれば校正・校閲が可能!!!!!*9 あと,「今tag付けたやつのビルド結果を入稿して!」ができます.これも大きい. 「このcommitのビルド結果を手が空いてる人でチェックして!!」とかもね.

GitLab CIではDocker Imageを簡単に突っ込めるのもとても良いです. Docker Imageには超有名なvvakame/reviewを用いています.

github.com

Re:VIEWのバージョン指定が簡単にできて良いんですよね. ちなみにOtakuAssemblyではVol.1ではversion 3.0,Vol.2ではversion 4.0のRe:VIEWを使っています. 新しいもの好きなので.

ただ,Vol.2の割と後半の方で「siunitxが欲しいんだが......」というオタクがいたので,急遽超虚無Docker Imageを作って差し替えました. まあマジでtexlive-scienceをインストールしてるだけですけどね. github.com

Docker Hubとか使ったこと無くて焦りましたね. でもこれ作ってDocker Image差し替えたら上手く行ったのでやっぱりDockerとGitLab CIは偉大ですね.

あと,Vol.1の時はGitLabのPDFビューアがなんかバグッててページの順番がぶっ壊れたかんじの表示になっていて, Web上でPDF見て校閲したい時かなり厳しい気持ちになっていたんですが,Vol.2の時にはこの問題は修正されていたみたいです. ありがとうGitLab!!!一生付いていきます!!!!!(普段はソースコードGitHubに上げながら).

Slackへの通知

OtakuAssemblyでは,連絡には主にSlackを用いています. というかSlackしか使ってません. なんなら執筆者のほとんどとはTwitterとこのSlackでしか繋がりがありません. 最近流行りのSNS採用・リモートワークってやつですね(?)*10

なので,各位のcommit状況の確認やCIの状況の確認のため,GitLabからSlackにwebhookで通知を飛ばすようにしています. f:id:sksat:20200318021011p:plain

こういうスクショ出すとたまに「スッコココすき」って言われてふふってなります. 名付け親なので(?). スッコココくん,CIをfailさせると顔真っ赤にして怒ってくるんですよ.かわいいですね. f:id:sksat:20200318022229p:plain

あと,Vol.2の執筆中の一時期Issueとかの通知を#vol2(Vol2全般のチャンネル)に飛ばすようにしてみたんですが, Issue上でメモとかするとそれも全部通知が行くのでちょっとウザかったのでやめてしまいましたね. open/closeだけ選別して送れたら良さそうなんですけど.

編集作業について

査読があると......うれしい!!!!うれしくないですか?僕はうれしいです. ということでOtakuAssemblyでも一応それっぽい活動をしています. 最近知ったんですが,僕は編集長だったらしいです.

前述したように,校正・校閲はMRが出たら編集担当が行います. 誤字脱字の指摘や表現の修正の提案はdiffを見てMR上のコメントとして行います. まあ編集担当も執筆者の一人であるというバグがある上に僕の執筆速度が大体一番遅いので終盤になってくると頼む〜〜〜〜手が空いたオタク誤字脱字チェックやってくれ〜〜〜〜となるんですけどね(オイ).

なんで進捗ヤバい時期って重なるんですかね.不思議ですね.

あと,Vol.1の時は誤字脱字もコメントで飛ばしてたんですけど, Vol.2では明らかな誤字脱字はわざわざコメント飛ばさず編集担当がdraftブランチにcommitしちゃっていいかと思うようになりました. しょうもないtypoの指摘に文意の確認とかが埋もれても嫌ですからね. そうじゃないんやってことだったらrevertすればいいですし. まあ適宜pullしてもらう必要がありますが.

ちなみにVol.1ではめっちゃギリギリまで原稿の調整や修正をしたり*11,手の空いた人間全員で読み直しや誤字脱字チェックしたりしてVol.1は〆切45分前入稿という偉業(偉くない)を達成しました.

そしてVol.2は〆切15分前を達成しました!(は?)

あと直前の誤字脱字チェックの時マジで@hsjoihs氏が有能of the humanでした. ありがとうございました. Vol.2では@hsjoihs氏の章が無いのに「監修」になっているのはそういうわけです.

また,Vol.2では新規参加の@coord_e氏がバチクソ誤字脱字や違和感のある文章の指摘・修正活動を行ってくれてとてもありがたかったです. やっぱり文章のクオリティを上げたいと思ってくれる人間がいるととても良いですね.

その一方で,技術同人誌における文章のクオリティってどうやって担保・向上させたらいいんだろうなあという気持ちに最近なっています. エディタースクールとか,そこらへんが出してる本とかもあるみたいなので,そういう分野も個人的に学んでみたいですね.

一応,最低限の注意事項はREADMEに書いていたんですが,執筆者のオタクのうちどれくらいがこれを気に留めて書いてくれていたんですかね.

あと,中高の部活での部誌とか,OtakuAssembly Vol.1, Vol2でそこそこ他人が書いた文章をチェックしたことから思うのは,「人々,他人に読ませることを意識して文章書かないがちでは?」ということです. これはもちろん自戒も込めての思いですけどね.

良い文章が書けない.なんとかしたいですよね.貴重な時間と精神力をたくさん使うのは惜しいですが,2人とも仲良しです.きっと成功しますよ.

技術書典7

こんなこと言ってたけど売れるかめちゃくちゃ不安でした.

当日の売り子は@PG_MANA_と僕で申請して,疲れたら適宜他のオタクと交代するか〜,と思っていました. ずっと売り子するのは疲れる,というのもありますが,そもそもこちらが自分でも技術同人誌を作りたいと思う程度には技術同人誌というものが好きなので,他のサークルの本も買いに行きたいんですよね. 交代ができるのは人数が多いサークルの利点ですね.

さて,そんなこんなで準備をして会場に向かったんですが,現地納品にしていたので物理本がどんな出来なのかは誰にも分かりませんでした. 会場に入り,OtakuAssemblyが配置された机を発見し,そこにある段ボール箱を開けると...

マジで「本じゃん」って思いましたね.本じゃん.

その後アワアワしながら初めての設営をしました. 設営後はこんなかんじになりました.

どのように設営を行うかはかなり悩みました. 何しろほぼ全員同人誌即売会での出展経験皆無でしたからね. まあ大体僕が勝手にやったんですが. 設営に関しては主にコミケとか例大祭とかのオタクのブログを参考にしました. たまに技術書典のオタクも書いていたりしますが,割とちょろっとしか書いてないことが多い気がします.

あとは,これまで技術書典4,5,6に「買う側」として参加していたのですが, その中でやや不満に思っていたことなどを踏まえて,できるだけ「買う側」の人が困らないように, 且つ,近くを通った時に目に留まるように,ということを意識していました.

「おしながき」とかんたん後払いのQRコードを上に吊る,というのもその1つです. 売る側は大体座ってるか中腰かが多いと思うんですが,買いに来る人たちは全員立って歩いてるんですよね. しかも技術書典はめちゃくちゃ込む(午前中は特に)ので,行く前から目を付けているサークルでもなければ,結構素通りしてしまいます. 僕は個人的にはできるだけ全部のサークルを見ようと思って周るようにしているんですが,それでもパッと見て内容が分かる情報が無いと後回しにしてしまうんですよね.

あと,「かんたん後払い」は人々がウカツに予定外の本を買う悪魔の最高のサービスなので, これを使わない理由はありません. ここで使うQRコードは事前に運営からデータを貰える他,小さめの紙に印刷されたものとそれを立てるためのなんか食玩とかにありそうな組み立て式の厚紙でできた台が当日配られます. もちろん配ってくれるのは親切だなあと思うんですが,正直あれは小さいし台も微妙だと思っていました. ちょっと改善したような気はしますが前をよく覚えていないので比較ができない.

実際やってみたところ,そこそこの人が吊った方のQRコードを使ってくれていたように思います. ただ,「アレッかんたん後払いのQRコードどれですか?」と何度か聞かれたので, QRコードもう少し小さくして「かんたん後払いはこちら」の文字をもう少しデカくした方が良かったかなという反省もありました.

これらの準備は以下のようなIssueを立ててやったりしました. f:id:sksat:20200317222732p:plain

ただ,当日朝バタバタしながらスマホからGitLabのIssueをポチポチするのは厳しさがあったので, 持ち物リストは紙とかにしておいた方が良さそうです.

そして一般参加者の入場が始まり,大量の人間が入ってきて「あ〜これで同人誌即売会あるあるの近くのサークルだけ売れてくやつが見られるのかな」とか, 100部は刷りすぎたかなあ......とか思っていました. でもポツポツ売れていくんですよね.めっちゃ嬉しい.嬉しいな.あれ......なんかめっちゃ売れるんだが......?

気が付いたら100部あった『OtakuAssembly Vol.1』は18部になっていました. 元々10部くらい売れたら頒布状況ツイートをしようと思っていたんですが,そんなことをする暇は全くありませんでした.やべえな. 本は何箱かの段ボール箱に入っていて,それぞれの本は5冊ごとくらいに紙テープでまとまって入っていました. なので,常に大体10部くらいが机の上に載っている状態を維持していたのですが,あまりにも売れ行きが良いので, 隣にいた@PG_MANA_に「オイ早く次の束くれ」「次の箱開けといて」「一々出してたら間に合わないから次机に載せるやつ椅子に置いておいて」とか言ってました. ツイートなんかできるわけねえ.

そしてゼエゼエしながらツイートした5分後には9冊に......

んでもってその6分後には物理本完売です.どうなってるんだ. あまりにも早く売れていったので,事前にオタクから頼まれていた取り置きを完全に忘却したり*12,予備分として付いてきた4冊も売ったり,後で執筆者の分ねえじゃん!となったりしました.

その後は電子版のダウンロードカードを配ったり,なんか急に生えてきた『The Zen Book』を展示したりしてました.

金が生えると→→→うれしい!!!!!!!

国会図書館への納本

技術書典7では物理本があまりに早く売り切れてしまったため,その後割とすぐ『OtakuAssembly Vol.1』を増刷しました*13. 増刷分はBoothで売りました. この増刷によってようやく執筆者が自分が書いた本を手に入れることができました(ウケる).

ということで余剰在庫が発生したので,前々からやりたいと思っていた(そして売る時完全に忘れていた)国会図書館への納本をすることにしました.

なんと自分で作った同人誌を国会図書館に納本するとなんと国民の税金を使って半永久的に黒歴史を保存してくれるんですよね.すごい.

というか,そもそも義務なんですよ.

納本制度」とは、図書等の出版物をその国の責任ある公的機関に納入することを発行者等に義務づける制度のことです。わが国では、国立国会図書館法(昭和23年法律第5号)により、国内で発行されたすべての出版物を、国立国会図書館に納入することが義務づけられています。

納本された出版物は、現在と未来の読者のために、国民共有の文化的資産として永く保存され、日本国民の知的活動の記録として後世に継承されます。

www.ndl.go.jp

みんなも出版した黒歴史を現在と未来の読者のために,国民共有の文化的資産として永く保存し,日本国民の知的活動の記録として後世に継承しよう!!!!!!!!!!

納本はとても簡単にすることができました. それまで国会図書館を使ったことがなかったのでその場でIDを発行してもらい, 荷物をロッカーに突っ込んでビニール袋に『OtakuAssembly Vol.1』を入れて*14中に入りました. 中はいいかんじの県立図書館をめちゃくちゃパワーアップした,みたいなかんじでした. あと入館とか検索用端末使うのとかに貰ったIDカード使うのオタク心が擽られてとても良いですね.

ああ納本の話するの忘れてましたね. 館内を見回しても特に納本の案内などは見当たらなかったので,先人のブログ記事に従い,受付で「すみません,技術同人誌の納本をしたいのですがどのようにしたらよいでしょうか?」と聞いてみました. そしたらちょっとびっくりした顔してから「少々お待ち下さい」って言われて,受付の代わりをする人が来てその人に「こちらです」って言われて付いていったら明らかに立ち入り禁止エリアっぽいところに行くんですよね. めっちゃいい. かなり日本国民としてのユーザーエクスペリエンスが良いので日本国民の皆さんにはぜひ同人誌を出版して国会図書館に納本して頂きたいですね. あ,あと立ち入り禁止エリアから出る時は一人だったので「勝手に立ち入り禁止区域に入ってこっそり出てきた一般人」ごっこができます. 誰かに咎められたらどうしようとか思った.

納本自体はとても簡単で本を渡して書類1枚書くだけです.

その後,こんなものが届きました.

それからしばらくするとNDLに『OtakuAssembly Vol.1』が掲載されました. やったぜ.

id.ndl.go.jp

新刊の『OtakuAssembly Vol.2』も近いうちに納本しに行きます. 国民共有の文化的資産ですからね(?).

あと,国会図書館とは関係ないですがOtakuAssembly Vol.1,Vol.2共にISDN: 国際標準同人誌番号というものを登録しています. これはまあISBNのパロディなのですが,結構ちゃんと運営されていて登録もスムーズにできますし,オプションを選択するとそれっぽいバーコードも出力してくれます. Vol.1の時はへ〜こんなものがあるのかと思って刷った後に登録してみたんですが,バーコードが出ると知ってVol.2では絶対にこのバーコードを入れて「「「本」」」にしてやろうと思っていたんですよね. まあ結局入稿数時間前まで忘れてたんですけど. でも印刷所からの怒られ後に表紙の再入稿ができたのでちゃんと裏表紙にこのバーコードを突っ込むことができました. 気になった君はOtakuAssembly Vol.2の物理本を手に入れて裏表紙を見てみよう!本だぞ!!!*15

isdn.jp isdn.jp

技術書典8

はい.中止になってしまいました.残念ですね. まあ仕方ない.仕方なくはあるんですがもう刷ってしまったのでオタクの財布が大変です!!!買ってくれ!!!!!

通販

今買うって言った?なんと通販で買えます.皆さんもウカツに買ってください.

techbookfest.org

otakuassembly.booth.pm

※Vol.2の物理本は現在入荷待ちなのでしばらくお待ち下さい(3/17現在)

おまけ:限界commit log selection

*1:これをやりたかっただけです

*2:オタクは信用できないので

*3:実はAC入試の自己推薦書はRe:VIEWで書きました

*4:こういう書き方するとヤバいな...

*5:もちろん,LaTeXを生で使う場合でも,適切にブランチを切りCIを回しておけば流石にこんなことは起きないと思います.たぶんね.でもマージした途端に大崩壊,みたいな可能性は否定できないと思うんですよね.特に各々が好き勝手にパッケージ導入とかやっちゃうと.まあこれも適切な運用をすれば大丈夫でしょうが,オタクは信用なりませんし,オタクは信用なりませんし,オタクは信用なりませんし,何より「気をつけて運用する」ということは精神的にまあまあ大きなコストです.

*6:pandocとかで

*7:これが難しいんですけどね...

*8:AC入試の自己推薦書でももちろんCI回してましたよ!!!!!面接はfailしましたけどね!!!!(溢れ出る学歴?コンプ)

*9:社畜か?

*10:でも,そういう考え方するとGitLabのム〜ブが参考になったりするのかな?とか思ったりしますね.知らんけど.

*11:直前に300pに抑えないといけなくなったりしたのは辛かった......

*12:このオタクには見本誌を渡してgot kotonakiしました

*13:儲かったので

*14:国会図書館内には基本的に物の持ち込みはできません.どうしても持ち込みたい物はその場に用意されているビニール袋に入れて持ち込む必要があります.

*15:まあ僕もまだ現物は見てないんですけど......

OpenSKを使ってみた

Twitter見てたらこんな記事が流れてきました.

gigazine.net

エッマジかよ. しかもRustなのかよ.すごいな.

security.googleblog.com

"fully open-source security key implementation" っょぃなあ...と思って読んでみたらなんとこれTock OSのアプリケーションとして実装されてるんですね. 俄然気になってきた.

Tockは前にも少し紹介したRust製の組込みOSです.

sksat.hatenablog.com

ということでOpenSKのrepoはここ.

github.com

READMEによると,nRF52840-DKとnRF52840-dongleに対応しているようです. なるほど〜たしかにdongleなら殻付ければセキュリティキーになるよなあ.

USBメモリっぽい形のマイコンってBad USB以外何になるんだろうみたいな偏見があったんですが,セキュリティキーはなるほどというかんじです. まあ僕はBad USBもセキュリティキーも大好きなんですが.

ということでnRF52840-dongleが欲しくなってきたのですが, せっかくnRF52840-DK持ってるので試してみたいですね.試します.

全部READMEに書いてあるのでその通りにやればよいです. 打つコマンドは以下. 書き込みに必要なのでJLinkは入れておいて下さい. あと多分tockloaderも入れておいた方がいいのかな?

$ git clone https://github.com/google/OpenSK
$ cd OpenSK
$ ./setup.sh
$ board=nrf52840dk ./deploy.sh os app
$ sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/ &&
$ sudo udevadm control --reload

これだけでOKです(でした).

あとは,USB peripheralの方にもUSBケーブルを刺してPCと接続しましょう. これでOpenSKのnRF52840-DKへのインストールと,OpenSKをセキュリティキーとして使うための準備が出来ました. さあ,見せて貰おうか.お前の"力"を...

といってもどうやって試したもんですかね. もしかしてこれめちゃくちゃデバッグが大変だったりするのでは? なんかテストツールとかあるんですかね.

まあ今回はめんどくさかったので一瞬だけGoogleへのログイン用のセキュリティキーとして使ってみることにしました.

f:id:sksat:20200201021338p:plain
セキュリティキーの登録

この状態で少し待つとLEDがピカピカ光ります. どうやら点滅する時としない時がある気がするけど何の違いだろう. LEDが光ったら,適当にボタンを押すと登録できます.

f:id:sksat:20200201022102p:plain
登録完了

できました.

f:id:sksat:20200201022131p:plain

では使ってみましょう.

f:id:sksat:20200201022426p:plain
オラッッッ

ここでまたLEDが光るのでボタンポチー.

すると...

f:id:sksat:20200201022501p:plain

ウオオオオオログインできたあああああああ. すごい.まあ登録ができてるんだからいけるのはそれはそう. でもすごいですね.ちゃんと使える. まあ今回は実験なので一瞬で登録解除しましたが.

ということで,オープンソースのセキュリティキー実装のOpenSKを使ってみました. YubiKey大好きマンですし(あんまりちゃんと使えてないけど),オープンソースも大好きなのでもしかしたらそのうち移行するかもしれないまである.

実装も超気になるので時間のある時に読んでみたいですね. とりあえず,近いうちにnRF52840-dongleを買ってケースを3Dプリントしようと思います.

ブラウザをVivaldiからFirefoxに乗り換えられるか試してみる

Vivaldi

中高生の頃はブラウザはずっとFirefoxを使っていました. 中古ノートPCだけですべてをやりくりしていたので, Chromeなんてすぐメモリを食べまくって使い物になりませんでしたからね. ほんの一時期だけOpera使ってたこともあるけど,昔は自分のパソコン持ってなかったのもあって, 色々カスタマイズしたところで同じ作業を何度もやるのダルいしな...とか思って結局Firefoxでいいやってなった. あと火×狐ってなんか厨ニ病っぽくて好き.

そんな僕でしたが,オタクからメモリを貰ったり(何?),大学入学を期にThinkPad X1 CarbonがメインPCになったりしてメモリ容量が割と潤沢になってきました*1

で,ツイのオタクが激推ししていて前から気になっていたVivaldiなるブラウザに乗り換えてみたんですよね. それが過去の僕のツイートから2019年4月2日のことっぽい.

それ以降も結構Vivaldi気に入ったのでずっと使い続けてました. stable版とsnapshot版で使い分けたりとかはしてたけど.

10月くらいにデスクトップマシンを組んだ時も,選ばれたのはVivaldiでした. もちろんディストリはArch LinuxだしWMはi3.

ただ,このVivaldi,なんかどうもたまによく死ぬ(急に落ちる)んですよね. なんかやたら死ぬ日みたいなのがある気がする.

デスクトップマシンで使ったらほとんど落ちなかったので,マシンの問題かもだけど. その他に発生した問題としては,いくつかのWebサービスで"そのブラウザは非推奨です"って言われることですかね. 非推奨なブラウザであることは事実なので仕方ないけども.

まあ,非推奨ですよ〜って言われるぐらいはいいんですよ. でもBANしてくるのはどうなんだ.

Webサービス運営者の気持ちになってみれば,まあ標準的なブラウザ以外サポートしたくなんてないし(特にIE),非推奨ブラウザでアクセスしてきておいてクレームつけられたらたまったものじゃないだろうし,正しい判断なんだろうな〜とは思うんですけどね. 思うけど,「でも中身Blinkだし許してくんねえかな」ってなりますね.なりました.

あと,僕にとって致命的だったのはTweetDeckがゴミクズみたいに使えなくなってきたことです. 入力はバグるしそもそも全体が固まることも多くなってきたし. なんなんですかねあれ.FAKE野郎なので全然原因究明してませんが. まあそもそもDeckとibusやらmozcやらの相性が激悪な気もしているし, 一概にVivaldiが悪いとは言えないとは思うんですが, Firefoxだとそこまでひどい現象は見られないので,はいってかんじですね. web panelでDeck表示しながらブラウジングしたり作業したりするの大好きなんだけどなあ...

なので,最近はAmazon MusicとTweetDeckのためだけにVivaldiの横でFirefoxを開く芸をやっていました. まあタイル型WM使いなのでちょうどいい位置にFirefoxを配置する苦しみみたいなのはあんまりないし, デスクトップマシンだとメモリ容量余裕あるからVivaldiFirefox両方同時に使ってもそんなに問題無い. とはいえ,普通のブラウジングVivaldiで横に常にAmazon MusicとTweetDeckだけ開いたFirefoxを忍ばせておく運用はなんというか精神がすり減るような感覚があります.

ということがあり,ブラウザをVivaldiから他のものに乗り換える...かは分からないですが, 乗り換えられる状況を作っておくのは悪くないだろう,と思ったというわけです. どうせVivaldiの横でFirefox開いてたらそっちも使っちゃうし...

じゃあどんなブラウザ使おうかねと思ったんですが,ちょっと考えたけどFirefoxでいいかってなりましたね. いいじゃん,Rustだし(?). あと脱Googleみたいなのにも興味があるような人間なのでそれでChromeはウーンというかんじでナシ. 別にChrome拡張もそんなに使ってない.いや使ってるけれど,同じものがFirefoxのアドオンにもあるものがほとんどなんですよね.

あとなんか知らんうちにFirefoxにもpicture in picture来てたしね.

それじゃあFirefoxアドオンマシマシにしたらVivaldi置き換えできるか気になるじゃないですか. Firefox Quantumで各種便利アドオンが殲滅されたみたいな話があるのでそこらへんは気をつける必要がありますが.

マウスジェスチャー

Vivaldiで僕が気に入っている機能の1つがマウスジェスチャーです. マウスの動きを登録しておいて特定の動作をさせるやつ. 新しいタブ開くとか今のタブ閉じるとか,そういうやつ.

Firefoxだとマウスジェスチャーできるようにするアドオンあるのかな〜と思ってみたら,いくつかあるみたいですね. でも,Firefox Quantumでかなり滅びたとか. ということで今回使ってみたのはGesturefyです. これが中々使いやすそうで良かった.

f:id:sksat:20200118230950p:plain
Gesturefyへのジェスチャーの登録

あと,デフォルトだと新しいタブが5億光年先で開くじゃないですか(タブは5億個開くので). なので,どうにかならんかな〜と思って見てみたら,Edit Gesture -> Command -> New Tab -> New tab positionを"after"にしたら望むものになりました.やったぜ.

web panelの再現

次はweb panelの再現です. web panelというのは,VivaldiブラウジングをしながらTweetDeckを使うための機能です(真顔). URLを事前に設定しておくとボタンポチーで画面の左半分とかにそのサイトを表示してくれるってやつです. 超べんり.これが無いとツイッターが出来ない体にされた. 僕の場合はDeckの他にはMastodonの一番よくいるインスタンスGoogle CalendarGoogle Translateを入れています.

さて,今回はFirefoxでこれと同じことをやりたいわけです. まあタイル型WM使いなので横にもう1つウィンドウ置けばいいだけといえばそうなんですが, その状態でターミナルのウィンドウとか開いたら好みの場所に設定しなおすのにまた手間がかかるので, ブラウザを1つのウィンドウだけでいいかんじにできれば良いにこしたことはありません.

で,問題はFirefoxにweb panel相当のものがあるかどうかなんですが, Bitwardenのアドオンをインストールした時になんか横にそれっぽいのが生えてたのは知っていました. Firefoxではside barというものだそうです. Vivaldiとは違ってデフォルトではここでWebサイトを開く手段は無さそうですけどね.

でも,side barがアドオンから弄ることが領域であるということは,絶対ここでWebサイトを開くかんじのアドオンがあるはずです. オタクくんそういうの好きでしょ.俺は詳しいんだ.

ということで調べてみると,まさにそういうかんじのアドオンが2つ見つかりました.

あと,もう少し調べてみたら,「side barで表示したいWebサイトをブックマークして,ブックマークのプロパティで"load this bookmark in the sidebar"というチェックボックスにチェックすればいけるで〜」という記事を見つけました. これでいいじゃん!と思ったのですがそんなチェックボックスはありませんでした. なぜ?と思ったらこの機能はFirefox 63で削除されたみたいです. ざんねん.

ということで,Webpage SidebarとSide Viewをそれぞれ使ってみました. まず,Webpage Sidebarはシンプルながら必要なものを抑えてるな〜と思いました.

f:id:sksat:20200118164933p:plain
Webpage Sidebar

クリックするとこんなかんじのシンプルなポップアップが出てきて, ここにside barで表示したいWebサイトのリンクを入れておけばそれ以降はここをポチっなとするだけでside barに表示してくれます.

f:id:sksat:20200118165409p:plain
Vivaldi web panel

できればVivaldiのこのボタンポチーで行けるようにしたいですけどね〜.まあ多くは望まない方がいいでしょう.

次はSide Viewです. これはWebpage SidebarよりもUIがなんというかキラキラしていますね(生htmlってかんじのじゃないねの意です). こちらの特徴としては,なんも考えずに今開いているページをside barに表示できるというのがありますね. これは便利だ.便利なんですが,特に開きたいやつを登録しておく,みたいなことができない. そこについてはWebpage Sidebarの方が「俺はこれとこれとこれをside barで開くんや」という気概があっていいかもしれないですね. とはいえRecent領域があるのでそんなに軽率に開かなければそんなに困らないかな...

f:id:sksat:20200118170649p:plain
Side View

あと,こっちはデスクトップ向け表示させるかモバイル向け表示させるかを選択できます. ちょっとVivaldiっぽい.

どちらを使うかは悩ましいです. でも開くサイトはほぼ決まってるし,サイトのアイコンを一緒に表示してくれればWebpage Sidebarがいいかなあ...と思っています. アイコンでものを判断しているので*2. そんなにコード長くないし,contributeしてみるのもありかもしれないですね?Webなんもわからんが...

さて,これで勝った...と思ったのですが,ダメでした. なんとこのside barさん広げられるサイズに上限がある...

オイ!!!!!!これだと通知が見えにくいやろが!!!!!! この問題はアドオンというか力とパワーで殴らないと解決できませんでした.

まず,これはuserChrome.cssというファイルに

#sidebar {
  max-width: none !important;
  min-width: 0px !important;
}

と書くと好きなだけ幅が変えられます. 変えられるのですが,例によってQuantumからuserChrome.cssが使えなくなったらしいです.oh じゃあどうするのかというと,about:configからtoolkit.legacyUserProfileCustomizations.stylesheetsを選んでtrueにします. で,このuserChrome.cssなるファイルはどこに置くのかというと,config:profilesからprofileのディレクトリを確認して, そのディレクトリ内にchrome/userChrome.cssを書けば良いみたいです.

というかユーザープロファイルって何?

www.clear-code.com

へーそういうかんじの概念か.

タブ管理

あれっ,タブスタックってそういやVivaldiの機能か...って言いながらFirefoxでタブの上にタブ重ねてうーんうーんってやるやつやってました. あと,タブバーを右側に置きたい.

とりあえず,Tree Style Tabなるものを使ってみたんですが, 残念ながらこれはside barを使うアドオンなんですよね.むむう.

他に良いもの無いかな?と思ったものの,やっぱりここらへんもQuantum以降めっちゃ難しくなったっぽいんですよね.

ツリー型タブのWebExtensionsへの移行のおはなし - Qiita

ひえー大変そう.

web panel問題 再来

縦タブ使いたいなあ,どうしたものかなあと思っていたら,TSTの作者の方からこんな情報が...

確かに,Side ViewとかでTweetDeck開くと微妙に表示がおかしいことがありますね...使えないほどではないけれど.

ということで教えてもらったのがこちら.

これをどう使うかというと,TSTとこのアドオンを入れた状態で,Firefoxのウィンドウを2つ開き, 片方でTweetDeck(web panel的に開きたいやつ)を開き,左側に配置します. そうしたら,もう片方のウィンドウで普通にブラウジングします(そして,こっちではTSTを使ってタブ管理します). こうすると,普通のブラウジングは縦タブで優勝しつつTweetDeckで人権が得られます. また,Deckの方で面白そうなリンクが流れてきても,普通に開くとそのタブがぐわーっと左のウィンドウに移動してくれます.なるほどね.

f:id:sksat:20200122181918p:plain
使用感

実際に使ってみるとこんなかんじ. 慣れるまで少し時間かかったけど,慣れたらまあまあ使いやすいですね.

しかし,ここで以下の問題が発生します.

  • 毎回ウィンドウを丁寧に左右に配置するのめんどくない
  • TweetDeck以外左で開けないやんけ

まず,1つ目に関しては,タイル型WMを使いましょう.i3使いましょう. タイル型WM使ってないんですか? ププーッ,ウィンドウが浮いているのが許されるのは小学生まででしょw(?) ということです.よろしくお願いします.

次に,2つ目についてですが,これは結局先程のweb panelもどきアドオンを使うことにしました. ちょっと表示おかしかったりはするけど,使えないってほどじゃないですからね. これがどういうことかというと,こういうことです.

f:id:sksat:20200122184540p:plain

一番見るのはTweetDeckですからね.まあいいでしょう. TwitterやめてMastodonに完全移行してもメインが変わるだけです.

ちなみに,この用途であればSide ViewよりもWebpage Sidebarの方が使いやすかったです.

おわり

ということで,VivaldiからFirefoxに乗り換えられるかなチャレンジをやってみました. とはいえ,やっぱりFirefoxだとアドオンマシマシにしないとできない(&してもできないことがある)ので,そういう機能がデフォルトで付いてる上に設定も弄りやすいVivaldiは良いですねという気持ちになりました. あと,僕がまだ使いこなせていないだけでVivaldiにはもっと色々カスタマイズできるところがありますしね.

でも,本当の意味で縦タブ(タブバーが縦)ができれば,僕にとっては随分状況が違う気もしますね.どうなんだろ.

まあしばらくFirefoxVivaldi両方使ってみようとは思います. Firefoxも好きだし.

*1:といっても,16GBとかですが

*2:ツイのオタクもアイコンで判断しているし,当然web panelのサイトもアイコンで判断している

Rust製の組み込みOS『Tock』について調べてみた

これは 自作OS Advent Calendar 2019 の9日目の記事です.

はじめに

最近大人気ですよね,Rust. 全人類Rust書いとる...俺は... システムプログラミング言語ですし,LLVMを使っているので色々なアーキテクチャ向けにコンパイルできますし, 安全性を重視しているので,RustでOSが書けるようになると色々と面白そうです.

とはいえ,なんだかんだでちゃんと使ってみようという気になれず,まだあまり書いたことがありません. そこで,今回はRustで書かれたOSであるTockを使って,モダンな言語でのOSの作り方やRustそのものについて調べてみようと思います.

Tockとは

TockはRustで書かれたCortex-MやRISC-Vで動く組み込みOSです.

https://github.com/tock/tock

最近はSTM32でも動くらしいですね.

https://garasubo.github.io/hexo/2019/02/18/tockapp.html

とりあえず動かしてみる

何はともあれ,まずは動かしてみましょう. Getting Started Guideに従います.

まずはRustの環境構築と,tockloaderのインストールです. 実はここでrustupで指定されたバージョンのRustを入れるだけのはずなのにnightlyだとclippyが云々とか言われて激しく躓いたんですが,rustupってそういうもんなんですかね...? よく分からないけど,もうちょっとどうにかならないんだろうか(割と公式っぽいところの記述通りにやってもだめだったりするの初心者殺しでは?).

次に,カーネルコンパイルします. カーネルコンパイルはボード毎のディレクトリで行うようです.

$ cd boards/nucleo_f446re/
$ make -n
RUSTFLAGS="-C link-arg=-Tlayout.ld -C linker=rust-lld -C linker-flavor=ld.lld -C relocation-model=dynamic-no-pic -C link-arg=-zmax-page-size=512" cargo build --target=thumbv7em-none-eabi  --release
"/home/sksat/.rustup/toolchains/nightly-2019-10-17-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm"-size target/thumbv7em-none-eabi/release/nucleo_f446re
cp target/thumbv7em-none-eabi/release/nucleo_f446re target/thumbv7em-none-eabi/release/nucleo_f446re.elf
"/home/sksat/.rustup/toolchains/nightly-2019-10-17-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm"-objcopy --output-target=binary target/thumbv7em-none-eabi/release/nucleo_f446re.elf target/thumbv7em-none-eabi/release/nucleo_f446re.bin
$ make
   Compiling tock-registers v0.3.0 (/home/sksat/github/tock/libraries/tock-register-interface)
   Compiling tock-cells v0.1.0 (/home/sksat/github/tock/libraries/tock-cells)
   Compiling enum_primitive v0.1.0 (/home/sksat/github/tock/libraries/enum_primitive)
   Compiling nucleo_f446re v0.1.0 (/home/sksat/github/tock/boards/nucleo_f446re)
   Compiling tock_rt0 v0.1.0 (/home/sksat/github/tock/libraries/tock-rt0)
   Compiling kernel v0.1.0 (/home/sksat/github/tock/kernel)
   Compiling cortexm v0.1.0 (/home/sksat/github/tock/arch/cortex-m)
   Compiling capsules v0.1.0 (/home/sksat/github/tock/capsules)
   Compiling cortexm4 v0.1.0 (/home/sksat/github/tock/arch/cortex-m4)
   Compiling stm32f4xx v0.1.0 (/home/sksat/github/tock/chips/stm32f4xx)
    Finished release [optimized + debuginfo] target(s) in 6.91s
   text    data     bss     dec     hex filename
  55809       2180      71548     129537      1fa01 target/thumbv7em-none-eabi/release/nucleo_f446re

最近はxargo?とかいうのを使わずともcargoで行けるんですね. ようするにcargoでターゲットを指定してビルドして,生成されたELFファイルをllvm-objcopyで素のバイナリにしているだけですね. また,cargoの出力からアーキテクチャ依存部分,ボードやSoC,ランタイム,Capsuleカーネル本体がRustのライブラリとして実装されていることも分かりました.

コンパイルができたので,まずはこのカーネルを手持ちのボードに書き込んでみます. 今回はSTM32F446を使いました(買ってくれた@tnishinagaさんありがとうございます). ...と思ったのですが,何故か書き込みができなくなってしまった(昨日はできたんだけどなあ...)ので, これ以降はnRF52840-DKを使います.申し訳...

(挙動からしてケーブルの接触不良感がするんですが諸事情により今使えるUSB mini Bなケーブルが1本しかないんですよね.マイコン弄りには致命的です.)

$ make flash
    Finished release [optimized + debuginfo] target(s) in 0.00s
   text    data     bss     dec     hex filename
  94208       2464     259680     356352      57000    target/thumbv7em-none-eabi/release/nrf52840dk
tockloader  flash --address 0x00000 --jlink --board nrf52dk target/thumbv7em-none-eabi/release/nrf52840dk.bin
Flashing binar(y|ies) to board...
Using known arch and jtag-device for known board nrf52dk
Finished in 0.560 seconds

書き込めたようです.

カーネルが書き込めたので,次はアプリケーションを動かしてみましょう(Tockではカーネルとアプリケーションは別に突っ込むみたいです). アプリケーションの書き込みには,専用ツールのtockloaderを使います. tockloaderはPython3で書かれています. 3で良かった...こういうのがPython2なのってたまによくあるけどめっちゃイラッとするんですよね.2019年も終わりますからね. Python2は速やかに滅ぼしましょう.

まずは対応しているボードを確認します.

$ tockloader list-known-boards
Known boards: hail, imix, nrf51dk, nrf52dk, launchxl-cc26x2r1, ek-tm4c1294xl

あれ?もしかして結局STM32使えなかったオチ? まあ割と最近追加されたターゲットらしいですし,そのうち実装されるでしょう.

ということで,最初はblinkというアプリケーションを書き込んでみます.

$ tockloader install --port /dev/ttyACM0 --board nrf52dk --jlink blink
Could not find TAB named "blink" locally.

[0]    No
[1]    Yes

Would you like to check the online TAB repository for that app?[0] 1
Installing apps on the board...
Using known arch and jtag-device for known board nrf52dk
Finished in 2.497 seconds

どうやら,アプリケーションはTABという単位で管理されており,オンラインのTABリポジトリに登録されているexampleなどはダウンロードして使えるようです.

めっちゃ光ります.

アプリケーションを見てみる

アプリケーションの実装例はC/C++のものRustのものがあるようです. 正確には,これらはC/C++とRust向けのユーザランドライブラリ群で,examplesにそれを使ったサンプルがあるかんじです. newlibとかluaとか使えるみたいですね.良さそう.

Rustはまだあんまり分かっていないので,ここではlibtock-cを見てみます. まずはblinkです.

#include <led.h>
#include <timer.h>

int main(void) {
  int num_leds = led_count();

  for (int count = 0; ; count++) {
    for (int i = 0; i < num_leds; i++) {
      if (count & (1 << i)) {
        led_on(i);
      } else {
        led_off(i);
      }
    }

    delay_ms(250);
  }
}

とりあえずこれもコンパイルして書き込んでみましょう.

$ git clone https://github.com/tock/libtock-c
$ cd libtock-c
$ cd examples/blink
$ make
~~~libtockのビルド~~~
Application size report for architecture cortex-m0:
   text    data     bss     dec     hex filename
   1240        188        352       1780        6f4 build/cortex-m0/cortex-m0.elf
Application size report for architecture cortex-m3:
   text    data     bss     dec     hex filename
    992        188        352       1532        5fc build/cortex-m3/cortex-m3.elf
Application size report for architecture cortex-m4:
   text    data     bss     dec     hex filename
    992        188        352       1532        5fc build/cortex-m4/cortex-m4.elf
$ tockloader install --port /dev/ttyACM0 --board nrf52dk --jlink build/blink.tab 
Installing apps on the board...
Using known arch and jtag-device for known board nrf52dk
Finished in 2.916 seconds

最初と同じように光ったので,delayの時間を少し変えてコンパイルし直してみます.

チカチカの間隔が長くなりましたね.ちゃんとビルド・書き込みができているようです.

さて,ここで気になるのがこのアプリケーションがどのようにビルドされているのかということです. ビルド時にアーキテクチャやボードは指定していないですし,make時のログを見る限りどうもCortex-M0,3,4向けにそれぞれビルドしているみたいです. ということでbuild/とtabファイルを見てみます.

$ ls build
blink.tab  cortex-m0/  cortex-m3/  cortex-m4/
$ file build/blink.tab
build/blink.tab: POSIX tar archive (GNU)
$ tar xvf build/blink.tab
metadata.toml
cortex-m0.tbf
cortex-m0.bin
cortex-m3.tbf
cortex-m3.bin
cortex-m4.tbf
cortex-m4.bin
$ cat metadata.toml 
tab-version = 1
name = "blink"
only-for-boards = ""
build-date = 2019-12-09T10:00:29Z

あっそういうことなの... とりあえず全部ビルドしてtarに突っ込んでるんですね. TABってtar archiveだったのか... つまり,書き込み時にtockloaderがtarを展開してmetadata.tomlを見ていいかんじに察して対応するアプリケーションのバイナリイメージだけを書き込んでいるということです. まあ,カーネルとアプリケーションが分離されているし基本的なアプリケーションを作る時にはアーキテクチャ毎にビルドしちゃって良いというのは分からないでもないんですが, 必要なやつだけビルドしたいなあ感が否めないですね.

さて,次に気になるのはled.hです. どのようにアプリケーションからカーネルを叩いているのかです.

libtock/led.cを見てみると,led_on()はこんなかんじになっていました.

~~~

int led_count(void) {
  return command(DRIVER_NUM_LEDS, 0, 0, 0);
}

int led_on(int led_num) {
  return command(DRIVER_NUM_LEDS, 1, led_num, 0);
}

~~~

どうやらcommand()システムコールラッパー的なやつで,LEDに関する操作は第一引数をDRIVER_NUM_LEDSにするとよいっぽいですね.

command()libtock/tock.cで実装されていました.

int command(uint32_t driver, uint32_t command, int data, int arg2) {
  register uint32_t r0 asm ("r0") = driver;
  register uint32_t r1 asm ("r1") = command;
  register uint32_t r2 asm ("r2") = data;
  register uint32_t r3 asm ("r3") = arg2;
  register int ret asm ("r0");
  asm volatile (
    "svc 2"
    : "=r" (ret)  
    : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
    : "memory"
    ); 
  return ret;
}

SVC命令で割り込みを発生させてカーネルを呼んでいるみたいですね. r0のdriverがLEDとかButtunとかの大雑把なドライバ(Capusle毎とかなのかな?)の指定に使われていて, そのドライバに対してコマンドと2つの引数を指定できるようです.

ドライバ番号は以下のようになっていました. 結構色々ありますね.

DRIVER_NUM_ALARM 0x0
DRIVER_NUM_CONSOLE 0x1
DRIVER_NUM_LEDS 0x00000002
DRIVER_NUM_BUTTON 0x3
DRIVER_NUM_ADC 0x5
DRIVER_NUM_DAC 0x6
DRIVER_NUM_ANALOG_COMPARATOR 0x7
DRIVER_NUM_SPI 0x20001
DRIVER_NUM_USB 0x20005
DRIVER_NUM_RNG 0x40001
DRIVER_NUM_CRC 0x40002
DRIVER_NUM_APP_FLASH 0x50000
DRIVER_NUM_NONVOLATILE_STORAGE 0x50001
DRIVER_NUM_SDCARD 0x50002
DRIVER_NUM_TEMPERATURE 0x60000
DRIVER_NUM_HUMIDITY 0x60001
DRIVER_NUM_AMBIENT_LIGHT 0x60002
DRIVER_NUM_NINEDOF 0x60004
DRIVER_NUM_TSL2561 0x70000
DRIVER_NUM_TMP006 0x70001
DRIVER_NUM_LPS25HB 0x70004
DRIVER_NUM_LTC294X 0x80000
DRIVER_NUM_MAX17205 0x80001
DRIVER_NUM_PCA9544A 0x80002
DRIVER_NUM_GPIO_ASYNC 0x80003
DRIVER_NUM_NRF_SERIALIZATION 0x80004
DRIVER_NUM_I2CMASTERSLAVE 0x80020006

次に,せっかくなのでlibtock-rsの方も見てみました. 時間がありませんでした.

ブートシーケンスとアプリケーションの実行

さて,一通り使ってみたところで,Tockがどのように起動するのか調べてみましょう. とはいっても,大体はTock Startupに書いてある通りです.

まず,Tockには.vectors.irqsの2つのテーブルがあります. Cortex-Mはベクタテーブルのリセットハンドラに関数ポインタを突っ込んでおくだけで,起動(リセット)後即その関数に飛んでくれるお手軽アーキテクチャなので, この中にあるtock_kernel_reset_handlerが最初に呼ばれる関数というわけです.

また,Rustでは#[link_section=".vectors"]のように書いておけば変数が置かれるセクションを指定できるようです.素晴らしい. #[used]で最適化で消されないようにもできるんですね.

ここで指定されているリセットハンドラはboards/<board>/src/main.rsにあるようです.ボード毎に実装されているわけですね. リセットハンドラは以下のような実装になっていました.

#[no_mangle]   // これでマングリングしないようにできるっぽい
pub unsafe fn reset_handler() {
    stm32f4xx::init();   // ボード毎の初期化処理

    // ペリフェラルとか諸々の初期化

    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES));

    let chip = static_init!(
        stm32f4xx::chip::Stm32f4xx,
        stm32f4xx::chip::Stm32f4xx::new()
    );

    // Console, LED, Buttunなどのcapsuleの生成

    // ボードの構造体
    let nucleo_f446re = NucleoF446RE {
        console: console,
        ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
        led: led,
        button: button,
        alarm: alarm,
    };

    debug!("Initialization complete. Entering main loop");

    extern "C" {
        static _sapps: u8;
    }

    kernel::procs::load_processes(
        board_kernel,
        chip,
        &_sapps as *const u8,
        &mut APP_MEMORY,
        &mut PROCESSES,
        FAULT_RESPONSE,
        &process_management_capability,
    );

    board_kernel.kernel_loop(
        &nucleo_f446re,
        chip,
        Some(&nucleo_f446re.ipc),
        &main_loop_capability,
    );
}

最初にボード毎の初期化やペリフェラルの初期化をしていますね. その後,board_kernelという変数を定義しています. これがこのボードにおけるカーネルを表現するための構造体か何かっぽいです. static_init!()が何をするマクロなのかは分かりませんが,多分kernel::Kernelの型の変数なのでしょう.

その後に定義しているchipはどうやらSoCに載っている諸々が実装されたものっぽいですね. これはボードとは別にtock/chips/以下に実装されています.GPIOのレジスタとか,そういうやつです.

その後は,console, led, buttunなどの抽象化されたデバイスが定義されています. どうやらこれらの構造体はTockではCapsuleと呼ばれているようです.

https://raw.githubusercontent.com/tock/tock/master/doc/architecture.png

TockのArchitectureを見てみると,カーネルがCore KernelとCapsuleに別れていることが分かります. Core Kernelはできるだけ小さくして,実際のハードウェアアクセスはCapsuleでやる,というかんじなんですかね. また,CapsuleはRustの構造体として実装され,明示的に指定されたリソースにのみアクセスできるので安全!とのことです.

Capsuleを作ったら,ボードの構造体にCapsuleを突っ込んで初期化は終わりです.

初期化が終わったら,kernel::procs::load_processesでプロセスをロードします. _sappsはアプリケーションのバイナリイメージを含むROMの領域のアドレスです.boards/kernel_layout.ldで定義されています. kernel::procs::load_processesの実装を読んでみると,PROCESSESの数だけProcess::create()でプロセスを生成しているようでした. あと,多値返却とかもできるんですねRust. ちなみに,APP_MEMORYstatic mut APP_MEMORY: [u8; 65536] = [0; 65536];となっていたので,アプリケーションは最大64KiBのメモリを使うことができるようです.

これでプロセスができたので,後はboard_kernel.kernel_loop()でメインループに入っています. このメインループはtock/kernel/src/sched.rsで実装されており, プロセスはスケジューラによってスケジューリングされつつ,process::State::Runningの時に実行されるようです.

おわりに

実はこの記事は2,3日で急いで書いたので今回はここまでとします. ちなみに書いてる途中に良さげな似たような記事を見つけて焦って内容を増やしました. でも,あんまり「Rustでどういうところがうれしいのか」みたいなところまで調べられませんでした. そもそも僕自身ほとんどRust書いたことがなくてなんもわかっとらんというのもあります.

とはいえ,最近はxv6とかLinuxとかのソースコードしか読んでなかったので,「おお〜モダンな言語っぽい書き方だなあ」という気持ちになりました. ボードとかSoCとかもちゃんと分けられていますしね. インターン先でZenで書いてるOSと似たものを感じました.

でも,チラッと見た限りですがポインタ操作とかちょっとめんどくさそうだな〜という気持ちにもなりました. もちろんユーザーアプリケーションを書く時にはあんまりポインタ使うべきではない/使うとしても安全に使えるようにすべき,というのは分かるんですが, ベアメタル環境で動くプログラムだとそうもいかないですよね.ペリフェラル弄ったりとか. 個人的にはそこらへんはZenの方が楽かな,と思いました(別にステマとかじゃないですよ).

あと,色々読んでみてRust結構良い言語だな〜となるやつ(N回目)をやったので, 少しずつRustでプログラム書いていきたいですね. やっていくぞ.