Windows 上の cygwinでSwift コンパイラ/インタプリタを使う方法


はじめに

Windows 7 以降の 64BIT 版 Windows には、64BIT 版の cygwin の中に Apple iOS の標準言語であるところの Swift をインストールして使うことが出来ます。

ただし、予め以下のもののインストールが必要です。

  • cygwin 64BIT バージョン。

  • cygwin 版 clang ver 8 パッケージ。
    cygwin用のパッケージとしては、ver6, ver8 は有りますが、ver7 は有りません。cygwinパッケージとしてではなく、Windows 用の clang ver7をLLVM公式サイトからインストールしてそこにパスを通している場合は、今回のバージョンの Swift とは恐らくコマンドラインの書き方の一部に互換性が無いようです。よって、必ず ver 8 の clang を使ってください。
    以下は、インストール作業には関係ない話ですので読み飛ばしてもらってかまいません。
    Swiftにおいて、clang または、clang を実装するためのコアライブラリが、llvm の backend として使われているようです。Swift処理系は、内部から本当の clang 処理系の実行ファイル(コマンド)も使用してはいるようですが、それだけではないかも知れないということです。ここでいうコアライブラリとは、clang をインストールしていなければ使えないようなものではなく Swift 自身が予め静的リンク/動的リンクしている可能性があるようなものです。Swift は、論理的には *.swift を、Swift Intermediate Language (SIL) というSwift 専用の中間言語ファイル *.sil にコンパイルした後、 可読的 LLVM 言語 *.ll に直し、LLVM バイナリ *.bc に直し、native のオブジェクトコード *.o に直し、最後にリンカの ld で native の実行ファイルの *.exe などにリンクする、ということをしています。ただし、ディスク上のファイルを出力せずに一気に *.o に変換することも出来ます。なお、一旦テンポラリディスクファイルを作ってから消しているとは限らず、中間形式はオンメモリで処理されている可能性も有ります。さらに、オンメモリにすら作られずに、一気に *.bc に直されている可能性があります。

  • cygwin 版 libiconv パッケージ。x86_64-w64-mingw32 というもの。

  • cygwin 版 libicu60 (6.0.2-1) パッケージ。

インストールすると、少なくとも以下のコマンドが使えるようになります:

  • swiftc : *.swift から cygwin で実行できる native binary を生成するコンパイラ。
    print("Hello World") をコンパイルして実行できることを確認済みです。
    また、LLVM の可読的中間言語(IR) の *.ll を出力できることも確認済みです。
    swiftc は、バックエンドに clang と ld を使っています。

  • swift : 対話式インタプリタ(REPL)。
    1 + 2[ret] と入れると 3 と出ます。

インストール方法

インストール方法を手順を追って説明します。

Win7, 64BIT に 64BIT 版 cygwin をインストール

cygwin の GUI インストーラーを使って、cygwin 公式サイトからインストールします。
以下で cygwin のインストールフォルダは、c:\cygwin64 とします。

その際、インストーラーで以下のパッケージをチェック状態にしておきます。

  1. clang の ver 8 のパッケージ。

  2. libiconv 系パッケージ。x86_64-w64-mingw32 的な名前のもの。これがインストールされると、
    /usr/x86_64-w64-mingw32/sys-root/mingw/lib
    に libiconv.a と libiconv.dll.a がインストールされる。これは、swiftc コンパイラが使う。

  3. Category: libs の Package: libicu60 (6.0.2-1) パッケージ。
    ICU とは、International Components for Unicode のこと。
    これをインストールすると、少なくとも C:\cygwin64\bin に cygicui18n60.dll, cygicuuc60.dll
    がインストールされます。これは、swiftc でコンパイルして生成された実行ファイルが起動されるときに動的ライブラリとして読み込まれます。

Swift のダウンロードと展開

https://swiftforwindows.github.io/news/2018/02/12/Swift-for-Windows-Cygwin-20180212/
https://github.com/tinysun212/swift-windows/releases/tag/swift-4.0.3+cygwin.20180212

にて、cygwin 用に非公式に公開されている swift-4.0.3.cygwin.20180212-bin.tar.gz をダウンロードします。*.7Z 形式の方がサイズがだいぶ小さいのでそちらの方が良いかも知れません。以下では、*.tar.gz の方で説明しておきます。

$ tar -xvzf swift-4.0.3.cygwin.20180212-bin.tar.gz

のようにして展開すると、xxx/usr/bin にコマンド類が、xxx/usr/lib にライブラリが配置されます。
ただし、xxx は、./swift-4.0.3.cygwin.20180212-bin となるはずです。

  • xxx/usr/bin には swift.exe と swiftc.exe が出来ています。
  • swiftc.exe がコンパイラで、swift.exe が対話式インタプリタです。
  • swiftc.exe は、*.ll のような LLVM コードを出力することも出来ます。

パスの設定

上記の xxx/usr/bin のフォルダのフルパスを、PATH 環境変数に追加しておきます。

swift-4.0.3.cygwin.20180212-bin.tar.gz を展開した場所が c:\xxx だった場合、以下の様になります。

$ export PATH=/cygdrive/c/xxx/usr/bin:$PATH

ライブラリパスの設定

上記でインストールした iconv のライブラリ libiconv.a と libiconv.dll.a に「ライブラリ検索パス」を通す必要があります。
これは、clang のリンカであるところの ld がライブラリの *.a やオブジェクトファイル *.o を探すパスです。このパスを指定するため、cygwin の端末の中から、

$ export LIBRARY_PATH=/usr/x86_64-w64-mingw32/sys-root/mingw/lib

とします。

テスト

以下の様なテストプログラムを作っておきます:

HelloWorld.swift
print("Hello World!")

コンパイル

$ swiftc -v HelloWorld.swift

とすると、

Swift version 4.0.3 (swift-4.0.3+cygwin.20180212)
Target: x86_64-unknown-windows-cygnus
/cygdrive/k/Commu/FromOther/cygwin/Swift/swift-4.0.3/usr/bin/swift -frontend -c -primary-file elloWorld.swift -target x86_64-unknown-windows-cygnus -disable-objc-interop -module-name HelloWorld -o /tmp/HelloWorld-1bba48.o
/cygdrive/k/Commu/FromOther/cygwin/Swift/swift-4.0.3/usr/bin/swift-autolink-extract tmp/HelloWorld-1bba48.o -o /tmp/HelloWorld-40659b.autolink
/usr/bin/clang++ -Xlinker -rpath -Xlinker /cygdrive/k/Commu/FromOther/cygwin/Swift/swift-4.0.3/usr/lib/swift/cygwin /tmp/HelloWorld-1bba48.o -L /cygdrive/k/Commu/FromOther/cygwin/Swift/swift-4.0.3/usr/lib/swift/cygwin -lswiftCore --target=x86_64-unknown-windows-cygnus @/tmp/HelloWorld-40659b.autolink -o HelloWorld

と出力されます。

実行テスト

$ ./HelloWorld
Hello World!

となります。

対話式インタプリタ

$ swift

とすると、対話式インタプリタが起動します。

備忘録

もし、shared library が見つからないと言うエラーが出たような場合、

cygcheck ./HelloWorld

とすると、どんな名前の shared library が見つからないかが、stderr に出力されます。ですので、

$ cygcheck ./HelloWorld 1>a 2>b

として、b のファイルをテキストエディタで見ればよいです。それは例えば、

cygcheck: track_down: could not find cygicui18n60.dll

cygcheck: track_down: could not find cygicuuc60.dll

のように出力されます。