Mac で Cコンパイラ 9cc の写経をしたい

言語プロセッサの勉強をしたいなーと思って、途切れ途切れではあるが Swift コンパイラにコントリビュートしてみたり、 Writing An Interpreter in Go を写経してみたりしていた。

そんな折、Rui Ueyama さんが 低レイヤを知りたい人のためのCコンパイラ作成入門 という平易な文章で1からCコンパイラの実装を解説したページと GitHubリポジトリを公開してくださった。

これに取り組んでみたいなと思ったのだが、読み進めるとLinuxmacOSアセンブリが完全互換ではないため、Mac ユーザならば Linux 環境を用意した方が良いということが分かった。 そこで Docker を使って Mac で 9cc をビルドする環境を作ったのでメモを残しておく。 (なお筆者に Docker の実務経験はないのでもっと良い方法があるかもしれないとエクスキューズしておく。。。)

環境

  • macOS Mojave 10.14.4
  • Docker version 18.09.0, build 4d60db4

手順

Docker で Ubuntu のイメージを pull する

$ docker pull ubuntu:18.04

Docker の image が取得できていることを確認

$ docker images

前述の docker images で取得した IMAGE ID を使ってコンテナを起動する Ubuntu の root にログインできる

$ docker run -it {IMAGE ID}

必要なツールをインストールする

以下 Ubuntu のイメージで実行

$ apt-get update
$ apt install sudo
$ sudo apt install gcc make git binutils libc6-dev vim

GitHub にコードを push したいので ssh の鍵を登録する

この辺を参考に Dockerで作るGitHub環境 - Qiita

以上で 9cc を開発できる環境が一応整った。時間を見つけて少しずつ進めたい。

github.com

Playgroundを使ってUIの実装したら便利だった

Playground を使って UI の実装をしたら便利かつとても簡単だったので備忘録として。

普段書き捨てのコードやコーディングクイズの問題を Playground で実装するというのはよくやるのだけど、UIの実装で使うというのはほとんどやったことがなかった。ここでいう UI というのは UILabel や UIButton などの UI コンポーネントを指す。

なぜやるのか

なぜ Playground を使って書くかというと、Playground はコマンド一発で View の確認ができるのがとても手軽だから。アプリのプロジェクトを何回もビルドするのは時間がかかる。特に大きいプロジェクトでは余計に。またシミュレータや実機で確認するにしても、アプリが起動してから動作確認したい画面まで遷移するというのも手間で時間がかかる。Playground を使えば見た目がすぐに確認できるのでフィードバックループを小さくできる。確認の手間を小さくして、何度もチェックできるというのが良いところだと思う。「手動で動作確認をする代わりにユニットテストを書き、フィードバックループを小さくして何度も "チェック" する」というのはよく言われることだけど、それと同じだと思う。

環境

Xcode 10.2.1

やり方

1. プロジェクトを作成

Xcode -> File -> New -> Playfround -> Single View を選択

f:id:enmtknt:20190509171844p:plain

すると以下のコードが自動生成された Playground ができる

Playground Driven Development (Xcode 10.2, Swift 5 ...

ここでポイントになるのは最後の行で、 PlaygroundPage.current.liveView にセットした ViewController や UIView を Playground の live view ですぐに見ることができる。

PlaygroundPage.current.liveView = MyViewController()

2. UIの実装

いつも通り UI コンポーネントを実装する。Playgroundの同じページに書いていって構わない。

3. 動作確認

  • ショートカット Command + Option + Return で live view を表示できる。
  • コードを実行する。左下のボタンを押すか、 Command + Shift + Return で実行できる。
    f:id:enmtknt:20190509175038p:plain
    エラーが出ているが、ビルドは通っている

最後に

Playground Driven Development で調べるとより詳細な方法が出てきた。

ここまで行けると良さそうだけど、シンプルな UI コンポーネントの実装であれば、 ViewController に addSubview() して見た目を素早くチェックする → コードを変更する → チェックする → コードを変更する ... というループを素早く回せればそれだけでも充分良いかなと感じた。

Swift で C style for loop を書きたい

最近時間が取れる時に LeetCode をやっている。LeetCode はアルゴリズムの問題を解ける Web サービスで、課金するとシリコンバレーの有名企業のコーディングインタビューの過去問が解けたりもする。*1

自分が普段一番使うプログラミング言語が Swift なので、LeetCode でも Swift を使っている。解答例やフォーラムがあるので解けなかった問題はそこで答えを確認できるのだが、 JavaC++ の実装で for 文を使ったもが多い。Swift には C 言語や Java でいう for ループがない。*2

そこで代わりに使えるシンタックスがないか調べていたら stride(from:to:by:) というのが標準ライブラリにあった。

replacement of C style for loop in Swift 5(Xcode 1 ...

*1:イギリスでCSの学部を卒業した同僚曰く、就活が近くなると、同級生達は授業をろくすっぽ聞かずに LeetCode に勤しんでいたそうな。

*2:厳密には Swift 3 で deprecated になったので、現在は使うことが出来ない。2019年4月現在の LeetCode の Swift バージョンは 4.2。

困った時に iOS 開発のドキュメントやサンプルコードを探す方法

iOS アプリの開発をしていて行き詰まると Google 検索することがよくある。というかほぼ毎日やっている。検索結果として Stack Overflow や Qiita, 個人のブログ記事を見つけて、困っていた問題が解決する場合がある。解決したい問題がフレームワークやライブラリの仕組み上必要なバッドノウハウだったりすればそれで構わない。しかし特定の API について体系だって書かれたドキュメントを読んで知識を得たい場合、正しい使い方を知りたい場合、知りたかった内容が必ずしも得られるとは限らない。その場合、適当にググって見つけた記事を読むよりも効果的な方法は以下の 2 つになるような気がしている。

  • 公式のドキュメントを確認する
  • 実際に動くコードを参考にする

公式ドキュメント Apple Developer

Apple Developer

基本的に公式の情報は全てここにある。ただ自分としては、初心者にはいまいち知りたい情報を探しにくいし取っつきづらいと感じている。

そこで Apple のエンジニア直伝の開発ドキュメント検索方法。昨年 WWDC のラボで

「 developer.apple.com って初心者にはいまいち知りたい情報を探しにくくないですか?例えばあなたはどうやってドキュメントを調べていますか?」

Apple のエンジニアに質問してみた。すると、そのエンジニアはそれは課題だと感じていて、 Google のサイト内検索機能を使っていると教えてもらった。

Google のサイト内検索

Google で検索したい内容を入力する時に、検索バーに site:https://developer.apple.com と入れることで、サイト内検索をすることができる。 例えば URLSession について調べたければこんなかんじ。

f:id:enmtknt:20190221182742p:plain

Xcode のドキュメント

同じように Xcode でドキュメントを調べることもできる。(Xcode 10.1)

Xcode を起動 -> Help -> Developer Documentation

f:id:enmtknt:20190221183629p:plain

実際に動くサンプルコード

実際に動くコードの例を探したいことは良くある。その場合に考えられるのが以下の方法。

  • GitHub でコードを検索する
  • Apple Developer のサンプルコードを読む

GitHub のコード検索

GitHub には世界中のエンジニアが書いたライブラリやフレームワークのコード、定番ライブラリを組み込んだアプリのコードがたくさん公開されている。これらは未経験の開発言語やフレームワーク、新しいライブラリを使う場合とても参考になる。検索ツールを使えば、言語や公開時期など細かい条件を指定してコードを検索することができる。

GitHub · Where software is built

f:id:enmtknt:20190222183023p:plain

Apple Developer のサンプルコード

Apple Developer にも動くプロジェクトとしてサンプルコードが公開されている。ぱっと見探しづらいが以下の方法で調べることができる。

Google サイト内検索を利用して検索

前述と同じ方法。

site:developer.apple.com Sample Code と入力する。

f:id:enmtknt:20190221183931p:plain

Documentation Archive の Sample Code

以下の Documentation Archive の Sample Code にも色々まとめられている。

Documentation Archive

f:id:enmtknt:20190221184214p:plain

所感

忙しいと Google 検索して済ませがちだけど、やはりオフィシャルのドキュメントにはフレームワークの正しい使い方が書いてあるし、実コードを手元で動かしたり、様々な使い方を目にすることで自分のコードに活かせる新しい発見がたくさんあるように思う。

fastlane deliver で Multiple App Store Connect Teams found; unable to choose, terminal not interactive! が出た時の解決方法

CircleCI 上で実行した $ fastlane deliver

Multiple App Store Connect Teams found; unable to choose, terminal not interactive!

というエラーが出た。

先に結論を述べると、職場で利用している Apple Developer Program のアカウントが複数のチームに紐付いていたのが原因だった。 最近 Enterprise アカウントを作成したことの副作用で発生した出来事だった。

解決方法としては、deliver のパラメータに Team ID を明示的に渡してやる。Deliverfile に書いてやるのが簡潔で良い。 ちなみに自分のプロジェクトで使っている Deliverfile は以下の通り。内容は一部改変している。

app_identifier “jp.foo.bar"
username “buz@example.com"
team_id “xxxxxxxxxxx"
force false
skip_screenshots true
skip_metadata true
skip_binary_upload false
automatic_release false

ちなみに1点気をつけることがあり、この時 Team ID として入力するのは、 Developer Program で確認できる 10 桁の Team ID ではなく、 Spaceship で取得できる数値。 fastlane が実行できる環境であれば、irb も Spaceship を使えると思う。以下のように取得する。

$ irb
irb> require "spaceship"
irb> Spaceship::Tunes.login("iTunesConnect_username", "iTunesConnect_password")
irb> Spaceship::Tunes.select_team

環境

  • Ruby 2.3.1
  • fastlane 2.113.0

参考

Web API に依存するモジュールのテストに使う extension

環境

Xcode 10.1, Swift 4.1

Web API に依存するモジュールのテスト

iOS アプリ開発において、 Web API にリクエストするモジュールのユニットテストを書くことは良くあると思う。その場合 Web API にそのままアクセスするテストを書くと、返す値によってテスト結果が変わる脆いテストになってしまう。そのため Web API の戻り値をスタブして、 実際には HTTP リクエストを行なわないというのが基本になる。

HTTP リクエストをインターセプトして、任意の値を返すために使うライブラリは kylef/Mockingjay, AliSoftware/OHHTTPStubs 辺りが定番で、僕は Mockingjay を好んで使っている。Mockingjay のインストール方法は GitHub の README.md を参考にしてほしい。また、Web API の戻り値を json に肩代わりさせるが、その方法については以前書いた Qiita の記事に詳しい。

iOSプロジェクトのテストバンドルに存在するファイルを取得する - Qiita

簡便のための extension

以下の extension を用意することで、呼び元で簡潔にスタブすることができる。

gist.github.com

Quick を使った場合のテストケースの例

呼び元のコードはこのように書く。XCTest を使う場合も呼び方は変わらないが、非同期のテストを書く場合少し工夫が必要になる。

gist.github.com

所感

ユニットテストに限らず、本質的にやりたいことを実現するためにはどうしても煩雑なコードが必要になる場合がある。コードの保守性を高く保つ為には、複雑性を隠蔽して明解なインターフェースに落とし込み、呼び元のレイヤを簡潔に保つことが必要不可欠になる。

iOS アプリのバージョンをインクリメントするためのスクリプト

iOS アプリをストアにリリースする時にはバージョン番号を上げる作業が必ず発生する。その際に Info.plist を手作業で更新するのは手間だしミスが発生する余地があるので、 Pythonスクリプトを使って自動化している。以下のスクリプトを アプリのプロジェクト直下に配置し、実行する。 Python 2.7 でも 3 系でも動作する。

This script bumps iOS app version numbers. (Python ...

調べていたら Fastlane にも increment_version_number というコマンドがあったので、CI に導入する場合はこちらを使うのも良いかもしれない。バージョンのインクリメントに限らずアプリ開発で面倒な作業はなるべく自動化していきたい。