Swift on WSL

2020年8月7日, 2020年8月31日更新, 2021年9月18日追記

株式会社あいはら 研究開発チーム
高橋 純 junt@aihara.co.jp

WSL (Windows Subsystem for Linux) の登場によって、Windows 上でも手軽に Linux 環境 (様々な Linux 上で動作するコマンドラインツールやプログラミング言語など) を利用することが可能になりました。特にプログラミング言語については、コマンドラインでの利用が Linux と同様に可能になるので、主に研究などで大量な計算をする場合などには、向いた環境であると言えます。

そこで、本稿では、WSL のセットアップから、Swift、プログラミング言語 C を利用できるようにするまでを解説します。

なお、WSL を利用するには 64 bit 版 Windows 10 が必要です。また、本稿で用いている Windows のバージョンは 64 bit 版 Windows 10 Pro Version 1909 です。


WSL の準備

まず、Windows の「設定」を開き、[アプリ]をクリックして、「関連設定」の [プログラムと機能] をクリックします。次に、そこで開くウィンドウの [Windows の機能を有効化または無効化] をクリックします。
次に、そこで表示される「Windows の機能」ダイアログで、「Windows Subsystem for Linux」 (Windows のバージョンによっては「Linux 用 Windows サブシステム」) にチェックを入れて、[OK] をクリックします。しばらくすると Windows の再起動を促す画面が表示されるので、指示に従って再起動します。

Windows が再起動したら、「Microsoft Store」で、Ubuntu を検索します。いくつか候補が現れますが、ここでは「Ubuntu 20.04 LTS」を入手・インストールします。

インストール後、初めて Ubuntu 20.04 LTS 起動したときは、次のようにメッセージが表示されますので、準備が完了するまで、しばらく待ちます。

Installing, this may take a few minutes...

続いて、次のように WSL 利用時のユーザ名とパスワードの設定を求められるので、指示に従って入力します。以降、WSL で sudo を使う場合は、ここで設定したパスワードを使います。

Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: 
New password:
Retype new password:

さて、WSL では Windows のコマンドプロンプトで使えていた、Ctrl + V でペーストなどの、キーボードショートカットが使えないため、とても不便です。しかし、次の手順で、代わりに Ctrl + Shift + C でコピー、Ctrl + Shift + V でペーストが行えるようになりますので、設定しておきましょう。

まず、Ubuntu ウィンドウの左上の Ubuntu のアイコンをクリックして現れるポップアップメニューの「プロパティ」を選択します。
続いて表示されるダイアログで「Ctrl + Shift + C/V をコピー/貼り付けとして使用する(C)」にチェックを入れて、[OK] をクリックすれば完了です。

続いて、次のコマンドを使って、Ubuntu にインストールされているプログラム等の更新を行います。適宜画面に表示される指示に従って進めてください。

$ sudo apt update
$ sudo apt upgrade

更新が完了したら、WSL の準備完了です。


Swift インストール前の準備

続いて、Swift に必要なパッケージをインストールします。
下記サイトに必要なパッケージの一覧が載っていますので、自身の環境に合わせてインストールしましょう

ここでは、Ubuntu 20.04 LTS をインストールしていますので、以下のように必要なパッケージをインストールします。

$ sudo apt install binutils git gnupg2 libc6-dev libcurl4 libedit2 libgcc-9-dev libpython2.7 libsqlite3-0 libstdc++-9-dev libxml2 libz3-dev pkg-config tzdata zlib1g-dev

その他有用なパッケージのインストール

その他、プログラミング言語 C や、プログラム開発をする上で有用な以下のパッケージをインストールします。

$ sudo apt install clang
$ sudo apt install make
$ sudo apt install emacs
$ sudo apt install zsh
$ sudo apt install zip

Swift のインストール

いよいよ、Swift をインストールします。
なお、以下の操作はすべて ${HOME} ディレクトリで行っています。

まず、下記サイトから、自身の環境に合った最新のリリース版をダウンロードします。

ここでは、Ubuntu 20.04 LTS 用の swift-5.2.5-RELEASE のツールチェーンと、電子署名をダウンロードします。

$ wget -N https://swift.org/builds/swift-5.2.5-release/ubuntu2004/swift-5.2.5-RELEASE/swift-5.2.5-RELEASE-ubuntu20.04.tar.gz
$ wget -N https://swift.org/builds/swift-5.2.5-release/ubuntu2004/swift-5.2.5-RELEASE/swift-5.2.5-RELEASE-ubuntu20.04.tar.gz.sig

次に、以下のようにして PGP 鍵をインポートし、更新もしておきます。

$ wget -q -O - https://swift.org/keys/all-keys.asc |  gpg --import -
$ gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift

これで PGP 署名確認の準備ができたので、次のようにしてダウンロードしたファイルの確認を行います。

$ gpg --verify swift-5.2.5-RELEASE-ubuntu20.04.tar.gz.sig

その結果、以下のように Good signature と表示されていれば、検証に成功です。
もし、BAD signature と表示された場合、なんらかの理由で正しいファイルをダウンロードできなかったことになりますので、そのファイルは決して展開しないでください。

gpg: assuming signed data in 'swift-5.2.5-RELEASE-ubuntu20.04.tar.gz'
gpg: Signature made Thu Aug  6 04:04:48 2020 JST
gpg:                using RSA key 925CC1CCED3D1561
gpg: Good signature from "Swift 5.x Release Signing Key <swift-infrastructure@swift.org>" [unknown]

また、以下のような WARNING が表示されることがありますが、ここに書かれた説明によれば、そこに記載された正しい手順で鍵を取得していれば、この警告は無害であるとのことです。

gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: A62A E125 BBBF BB96 A6E0  42EC 925C C1CC ED3D 1561

さて、PGP 署名による検証が問題なければ、ダウンロードしたファイルを展開します。
展開すると、swift-5.2.5-RELEASE-ubuntu20.04/ というディレクトリが作られます。その中の usr/bin/ ディレクトリにパスを通せば Swift が利用可能になります。

ここでは一例として、以下の通り、/opt/org.swift/ に配置するようにします。

$ sudo mkdir /opt/org.swift
$ cd /opt/org.swift
$ sudo tar xvzf ~/swift-5.2.5-RELEASE-ubuntu20.04.tar.gz

そして、swift-5.2.5-RELEASE-ubuntu20.04 のシンボリックリンクを Swift という名前で作成します。

$ sudo ln -s swift-5.2.5-RELEASE-ubuntu20.04 Swift

次に ~/.bashrc の最後の行に以下を追記します。bash 以外のシェルを使っている場合は、それぞれのシェルに合わせて、適宜設定を行ってください。

export PATH=/opt/org.swift/Swift/usr/bin:"${PATH}"

そして、次のコマンドで追記を反映させます。

$ source ~/.bashrc

これでインストールは完了したので、次のコマンドで確認を行います。

$ swift --version

問題なければ、以下のようなメッセージが表示されます。

Swift version 5.2.5 (swift-5.2.5-RELEASE)
Target: x86_64-unknown-linux-gnu

このようにしておくことで、別のバージョンの Swift を利用したい場合は、/opt/org.swift/ に新たにツールチェーンを展開し、シンボリックリンクを作成し直すことで利用可能になり、それまで使っていたバージョンも残しておくことができます。

開発版スナップショットのインストール

この項目は必要がある人のみ行ってください。(2021/9/18追記)

リリース版は残しつつ、最新の開発版スナップショットを利用したいときは、次のように行います。

リリース版と同様、下記サイトから、自身の環境に合った最新開発版スナップショットをダウンロードします。

なお、下記の実行例の URL は、2020年8月7日現在のものなので、適宜最新版 URL に読み換えてください。
また、PGP 鍵はインストール済みなので、更新のみを行っています。

$ wget -N https://swift.org/builds/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a/swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04.tar.gz
$ wget -N https://swift.org/builds/development/ubuntu2004/swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a/swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04.tar.gz.sig
$ gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift
$ gpg --verify swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04.tar.gz.sig

リリース版のときと同様に、検証に成功していたら、次のようにファイルを展開し、シンボリックリンクを作り直します。

$ cd /opt/org.swift
$ sudo tar xvzf ~/swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04.tar.gz
$ sudo ln -nfs swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04 Swift

これで開発版スナップショットのインストールは完了したので、次のコマンドでバージョン確認を行います。
リリース版とは違うバージョン情報が表示されていれば、成功です。

$ swift --version
Swift version 5.3-dev (LLVM ab0a317622eabba, Swift b50a2cf430c9e63)
Target: x86_64-unknown-linux-gnu

(2021/9/18追記)リリース版に戻す場合は、以下のようにシンボリックリンクを作り直しますが、まず ls で状況を確認します。

$ cd /opt/org.swift
$ ls
Swift
swift-5.2.5-RELEASE-ubuntu20.04
swift-DEVELOPMENT-SNAPSHOT-2020-08-04-a-ubuntu20.04

ここで、ls で表示されるファイルやディレクトリはインストールされている swift のバージョンによって違いがあります。
さて、ここで表示されているディレクトリうち、RELEASE が含まれているものがリリース版になります。ここでは、swift-5.2.5-RELEASE-ubuntu20.04 ですが、自身の状況に合わせて、下記コマンドは適宜読み替えて実行してください。

$ sudo ln -nfs swift-5.2.5-RELEASE-ubuntu20.04 Swift

Swift によるコマンドラインプログラムの作成

Swift を使った簡単なコマンドラインプログラムの作成例を解説します。

パッケージマネージャーを使用したコマンドラインプログラムの作成

Swift.org - Getting Started の説明に従って、パッケージマネージャーを使ってコマンドラインプログラムを作成してみましょう。

次のようにコマンドを入力して、${HOME} ディレクトリにパッケージを作成します。ここでは、Hello という名前にしています。

$ cd
$ mkdir Hello
$ cd Hello
$ swift package init --type executable

すると、以下のように表示され、パッケージが作成されます。

Creating executable package: Hello
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/Hello/main.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/HelloTests/
Creating Tests/HelloTests/HelloTests.swift
Creating Tests/HelloTests/XCTestManifests.swift

ここで作成された Sources/Hello/main.swift の内容を見てみましょう。以下に、そのコマンドと結果を示します。

$ cat Sources/Hello/main.swift
print("Hello, world!")

これを見ると、Sources/Hello/main.swift には Hello, world! と表示されるプログラムが既に記述されています。
そこで、次のコマンドでコマンドラインプログラムをビルドして実行してみると、以下のようにビルドの結果と、実行結果が表示されます。

$ swift run
[4/4] Linking Hello
Hello, world!

ここでビルドされたコマンドラインプログラムは .build/debug/Hello になりますので、以降は次のコマンドで実行できます。

$ .build/debug/Hello
Hello, world!

なお、上記の実行ファイルはデバッグ版ですが、次のコマンドでリリース版のコマンドラインプログラム .build/release/Hello を作成し、実行することができます。

$ swift build -c release
$ .build/release/Hello
Hello, world!

make コマンドによるコマンドラインプログラムの作成

make コマンドは、ファイルの依存関係と処理などを記述したファイル makefile に従って、必要最低限の処理だけで、コマンドラインプログラムのビルドなどを行うツールです。

前述のパッケージ Hello のソースコードを題材に説明します。
まず、次のようにコマンドを入力して、${HOME} ディレクトリに HelloWorld という作業用ディレクトリを作り、そのディレクトリに移動します。

$ cd
$ mkdir HelloWorld
$ cd HelloWorld

次に、~/Hello/Sources/Hello/main.swift をカレントディレクトリにコピーします。コピーせずに、emacs等のテキストエディタを使って、下記のような内容のファイル main.swift を作成してもよいです。

print("Hello, world!")

次に下記のような内容のファイル makefile を作成します。

TARGET=HelloWorld

SWIFTCFLAGS=-O

all: $(TARGET)

$(TARGET): main.swift
	swiftc $(SWIFTCFLAGS) -o $@ $^

clean:
	rm -f $(TARGET)

main.swiftmakefile が作成できたら、make コマンドを使って、コマンドラインプログラム HelloWorld をビルドしてみましょう。
以下に、make コマンドと作成された HelloWorld の実行結果を示します。

$ make
swiftc -O -o HelloWorld main.swift
$ ./HelloWorld
Hello, world!

ここで作成した makefile は、HelloWorld をビルドするには main.swift が必要であり、ビルドには swiftc を使うというルールとが記述されています。
よって、main.swift を修正して、HelloWorld のタイムスタンプが main.swift より古くなった場合、再度 make コマンドを使うと、再ビルドできます。
また、下記のようなコマンドを使うと、HelloWorld を削除することができますが、これも makefile に記述されたルールに従って動作しています。

$ make clean
rm -f HelloWorld

ここでは make を使ったコマンドラインプログラムの作成方法を説明してきましたが、それ以外にも makefile 次第で多彩な利用をすることが可能です。是非活用していきましょう。


Xcode で作成されたコマンドラインプログラムのビルド

~taiji/lecture-2020 contents で公開されているコマンドラインプログラムをいくつかダウンロードしてビルドしてみましょう。
以下の例では、ダウンロードしたファイルに makefile も同梱されていますので、そのまま利用します。

コマンドライン引数とURLからHTML取得: URLcat

次のように、zip ファイルをダウンロードして、展開します。

$ cd
$ wget -N https://www.aihara.co.jp/~taiji/lecture-2020/URLcat-20200806.zip
$ unzip URLcat-20200806.zip

続いて、ソースコードの置いてあるディレクトリに移動して、make コマンドを使ってビルドします。
最後の make test では、makefile に記述されたルールに従って、動作確認を行っています。

$ cd URLcat/URLcat
$ make clean
$ make
$ make test

その他のコマンドラインプログラム

Linux 版の Swift では、UIKit や Cocoa が入っていないなど、macOS 版との違いがあります。そのため、~taiji/lecture-2020 contents で公開されているコマンドラインプログラムの中でも、Linux 版でビルドできないものがありますので、以下に Linux対応を示します。

Linux対応 ✔: 対応、○: パッチにより対応、△: パッチにより非対応コードを除外
ファイル名Linux対応Linuxにおける備考
ModuloOperation-20200806.zip
ComprehensiveModuloOperation-20200806.zip
URLcat-20200806.zip
SampleXMLParser-20200806.zip
EmojiList-20200806.zip Unicode.Scalar.Properties に isEmoji 等がないため。
EasyQuestions.playground-20200806.zip
Playunderground-20200806.zip Playunderground01.Start.swift arc4random() を Int.random() に置き換えることで対応。
Playunderground02.Function.swift
Playunderground03.Structure.swift Cocoa モジュールがないため。
Playunderground04.Optional.swift
Playunderground05.Protocol.swift
Playunderground05.Protocol.v3.swift
Playunderground06.BasicTypes.swift Unicode.Scalar.Properties に isEmoji 等がないため。
526行目で発生する "error: argument type 'String' does not conform to expected type 'CVarArg'" は Linux 版の不具合かもしれません。
Playunderground07.Operators.swift
Playunderground07.Pattern.swift
Playunderground08.Class.swift
Playunderground09.MemoryManagement.swift
Playunderground10.Extension.swift CoreGraphics モジュールがないため。
Playunderground11.Error.swift
Playunderground12.Closure.swift
Playunderground13.Generics.swift
Playunderground14.DataOfObjective-C.swift Cocoa モジュールがないため。
他、いくつか Linux 版未対応箇所あり。
Playunderground15.CustomAttributeAndDSL.swift
Playunderground15.OfObjective-C.dir Selector 型がないため。
#selector はObjective-Cランタイムでのみ使用可能。
Playunderground16.IntegrationWithGUI.swift SwiftUI モジュールがないため。
Playunderground18.Appendix.swift
MyPlaygrounds-20190831.zip MyPlayground.playground UIKit モジュールがないため。
MyPlayground1.playground Playground 用のコードが含まれているため。
MyPlayground2.playground
MyPlayground3.playground Playground 用のコードが含まれているため。
MyPlayground4.playground
MyPlayground5.playground Cocoa モジュールがないため。
MyPlayground6.playground Playground 用のコードが含まれているため。
MyPlayground7.playground Playground 用のコードが含まれているため。
MyPlayground8.playground Cocoa モジュールがないため。
Playground 用のコードが使われているため。
String(format:) で「%@」がエラーになるなど、Linux 版の不具合かもしれない箇所があるため。
MyPlayground9.playground
MyPlayground10.playground Playground 用のコードが含まれているため。
MyPlayground11.playground Cocoa モジュールがないため。
String(format:) で「%@」がエラーになるなど、Linux 版の不具合かもしれない箇所があるため。
他、いくつか Linux 版未対応箇所あり。
MyPlayground12.playground Linux 版未対応箇所あり。
MyPlayground13.playground Linux 版未対応箇所あり。
MyPlayground14.playground 複数のソースファイルからなるプログラムをコンパイルする場合、最初に実行されるコードとして main.swift が必要なため、Contents.swift のシンボリックリンクを main.swift という名前で作成し、コンパイルするようにして対応。
MyPlayground15.playground String(format:) で「%@」がエラーになるなど、Linux 版の不具合かもしれない箇所があるため。
MyPlayground-JuniorHighSchoolMath.playground-20200826.zip swiftc-O オプションはつけずにコンパイルしてください。
MyPlayground-JuniorHighSchoolMath.playground-20200828.zip arc4random() を UInt32.random() に置き換えることで対応。
swiftc-O オプションはつけずにコンパイルしてください。
MyPlayground-JuniorHighSchoolMath.playground-20200828.patch

Playground の実体はディレクトリになっています。上記の例では EasyQuestions.playground-20200806.zip から展開される EasyQuestions.playground がそれで、その中にある Contents.swift がプログラムになり、ビルドすると下記のようしてに実行することができます。

$ ./EasyQuestions.playground/Pages/A01_Basics.xcplaygroundpage/Contents
$ ./EasyQuestions.playground/Pages/A02_Syntax.xcplaygroundpage/Contents
$ ./EasyQuestions.playground/Pages/A03_Object.xcplaygroundpage/Contents

Playunderground-20200806.zip は、一つの makefile で複数のプログラムをビルドするようになっています。そのため、ビルドできないプログラムのところで全体のビルドが止まってしまいます。そこで、Linux 版では対応していない箇所を除外してビルドするパッチを用意しました。

パッチの適用方法は以下の通りです。

$ wget -N https://www.aihara.co.jp/~taiji/lecture-2020/Playunderground-20200806.zip
$ wget -N https://www.aihara.co.jp/~junt/SwiftOnWSL/Playunderground-20200806.patch
$ unzip Playunderground-20200806.zip
$ cd Playunderground
$ patch -p0 -b -z.org < ../Playunderground-20200806.patch

MyPlaygrounds-20190831.zip は、Playground 用のコードが含まれているため、コンパイルできない箇所があります。そこで、それらの箇所や、Linux 版では対応していない箇所を除外してビルドする makefile とパッチを用意しました。

パッチの適用およびビルド方法は以下の通りです。
この例では、作業ディレクトリとして、MyPlaygrounds-20190831 を作っていますが、別の名前でもかまいません。また、ビルドの際に、MyPlaygrounds-20190831-makefile をダウンロードしたままのファイル名で使っていますが、makefile に名前を変更すれば、これまでと同様、make だけでビルドすることができます。

$ mkdir MyPlaygrounds-20190831
$ cd MyPlaygrounds-20190831
$ wget -N https://www.aihara.co.jp/~taiji/lecture-2020/MyPlaygrounds-20190831.zip
$ wget -N https://www.aihara.co.jp/~junt/SwiftOnWSL/MyPlaygrounds-20190831-makefile
$ wget -N https://www.aihara.co.jp/~junt/SwiftOnWSL/MyPlaygrounds-20190831.patch
$ unzip MyPlaygrounds-20190831.zip
$ patch -p0 -b -z.org < MyPlaygrounds-20190831.patch
$ make -f MyPlaygrounds-20190831-makefile

注意事項


付記: WSL 2 への更新

2020年8月21日

Windows 10 Version 2004 からは、WSL の新しいバージョン WSL 2 が利用可能になりました。
その違いは、Microsoft の文書「WSL 1 と WSL 2 の比較」に記載されており、WSL 2 ではファイルシステムのパフォーマンスの向上、Linux システムコールの完全な互換性のサポートが図られています。ただし、Windows ファイルシステムへのアクセスは WSL 1 より低下しているようです。
また、WSL 1 では動作しなかった、Swift の REPL も WSL 2 では動作することが手元の環境で確認できました。

以下では、既に WSL が利用可能な環境において、WSL 2 へ更新する手順を解説します。
なお、以下の説明で用いている Windows のバージョンは 64 bit 版 Windows 10 Pro Version 2004 です。

(2020年8月21日追記) Windows 10 Version 1903/1909 でも、更新プログラムの適用によって、WSL 2 が利用可能になりました。詳しくは下記を参照してください。

WSL 2 への更新の準備

まず、WSL 2 の導入に必要な Windows のオプション機能を有効にします。
Windows の「設定」を開き、[アプリ]をクリックして、「関連設定」の [プログラムと機能] をクリックします。そして、そこで開くウィンドウの [Windows の機能を有効化または無効化] をクリックします。
次に、そこで表示される「Windows の機能」ダイアログで、「仮想マシン プラットフォーム」にチェックを入れて、[OK] をクリックします。しばらくすると Windows の再起動を促す画面が表示されるので、指示に従って再起動します。

WSL 2 への更新

Windows が再起動したら、コマンドプロンプトを開き、以下のコマンドを実行し、インストールされている Linux ディストリビューションの名前と WSL バージョンを確認します。

C:\>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         1

この例では、Linux ディストリビューションの名前は Ubuntu-20.04 で、WSL バージョンが 1 であることがわかります。
続いて、次のコマンドで、WSL 2 に更新します。ここで入力している Ubuntu-20.04 は上記で確認した、Linux ディストリビューションの名前です。2 は新たに設定する WSL バージョンです。

C:\>wsl --set-version Ubuntu-20.04 2
変換中です。この処理には数分かかることがあります...
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください

変換にはしばらく時間がかかりますが、以下のようなメッセージが表示され、変換が行われなかった場合は、PC の BIOS 設定で仮想化が無効になっているかもしれません。BIOS 設定は機種により違いがあるので、詳しくはお使いの PC のマニュアル等を参考にしてください。「Virtualization」などのキーワードで探すとよいかと思います。

Windows の仮想マシン プラットフォーム機能を有効にして、BIOS で仮想化が有効になっていることを確認してください。
詳細については、https://aka.ms/wsl2-install を参照してください

その他、なんらかの理由で変換ができない場合は、Microsoft の文書「WSL 2 に更新する」などを参考にしてみてください。

変換が完了すると以下のようなメッセージが表示されますので、前述のコマンドでバージョンを確認すると、バージョンが 2 になっていることがわかります。

変換が完了しました。

C:\>wsl -l -v
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         2

Swift の REPL の利用

WSL 2 に更新後は、Swift の REPL が利用できるようになっていると思います。
Ubuntu 20.04 LTS を起動し、以下のように swift とだけ入力してコマンドを実行すると、REPL の入力待ち画面が表示されます。

$ swift
Welcome to Swift version 5.2.5 (swift-5.2.5-RELEASE).
Type :help for assistance.
  1>

Copyright © 2020-2021 Jun Takahashi <junt@aihara.co.jp>