Kitura が 0.3.0 になって、先日に作った Ubuntu 環境が動かなくなったのでその原因を調べて対応しました。
Server Side Swift
数日前に構築した Kitura 環境を使って早速 Web アプリケーションを作ってみようと思ったところ、Kitura がバージョンアップして早くもビルドできなくなってしまいました。
そこで最新の Kitura をちゃんと使えるように環境を作りなおしてみます。
数日前に こちら
で整えた Ubuntu + Kitura のサーバーサイド Swift 環境ですけれど、さっそく実際に使ってみようとしたところ、Kitura プロジェクトの準備段階で swift build
を実行した時に、次のようなエラーが発生して、先へ進めませんでした。
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:43:26: error: use of unresolved identifier 'DISPATCH_QUEUE_CONCURRENT'
let concurrent = DISPATCH_QUEUE_CONCURRENT
^~~~~~~~~~~~~~~~~~~~~~~~~
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:44:13: warning: constant 'serial' inferred to have type '()', which may be unexpected
let serial = DISPATCH_QUEUE_SERIAL
^
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:44:13: note: add an explicit type annotation to silence this warning
let serial = DISPATCH_QUEUE_SERIAL
^
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:44:22: error: 'DISPATCH_QUEUE_SERIAL' is unavailable: use 'nil' instead of this imported macro
let serial = DISPATCH_QUEUE_SERIAL
^~~~~~~~~~~~~~~~~~~~~
Dispatch.DISPATCH_QUEUE_SERIAL:2:12: note: 'DISPATCH_QUEUE_SERIAL' has been explicitly marked unavailable here
public var DISPATCH_QUEUE_SERIAL: ()
^
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:57:9: error: use of unresolved identifier 'dispatch_async'
dispatch_async(osQueue, block)
^~~~~~~~~~~~~~
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:66:9: error: use of unresolved identifier 'dispatch_sync'
dispatch_sync(osQueue, block)
^~~~~~~~~~~~~
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/Queue.swift:80:13: error: use of unresolved identifier 'dispatch_async'
dispatch_async(dispatch_get_main_queue(), block);
^~~~~~~~~~~~~~
~/Kitura/ESApi/Packages/Kitura-sys-0.3.0/Sources/KituraSys/SysUtils.swift:31:9: error: use of unresolved identifier 'dispatch_once'
dispatch_once(lock, block)
^~~~~~~~~~~~~
<unknown>:0: error: build had 1 command failures
error: exit(1): ["/usr/bin/swift-build-tool", "-f", "/opt/Kitura/ESApi/.build/debug/Kitura-Sys.o/llbuild.yaml"]
もしかして環境作りに失敗していたのかと思ったのですけど、どうやら先日に環境を整えた後に Kitura が 0.3.0 にバージョンアップしていた様子です。それに伴って swift-corelibs-libdispatch
周りの処理でエラーが発生してしまっていた様子です。
環境を Kitura 0.3.0 対応にする
Kitura 0.3.0 を使えるようにするために、先日の Kitura 0.2.0 環境を更新してみることにします。
Swift Development Snapshot (February 25, 2016)
Kitura のインストール手順によると最新の Swift コンパイラを使うようにと記されているので、まずは最近にリリースされた Ubuntu 14.04 Swift Development Snapshot (February 25, 2016) をインストールしておくことにします。
これを こちら に記載したようにして、利用できるように設定します。
swift-corelibs-libdispatch を更新する
Kitura 0.3.0 になって swift-corelibs-libdispatch
のインストール方法が変わったようなので、それを更新します。
まず、以前の swift-corelibs-libdispatch
関連ファイルを削除しておきます。
sudo rm /usr/local/lib/libdispatch.*
sudo rm -r /usr/local/include/dispatch
sudo rm /usr/local/include/os/linux_base.h
sudo rm /usr/local/include/os/object.h
sudo rm -rf /toolchains/swift-current/usr/lib/swift/dispatch
sudo rm /usr/lib/swift/linux/x86_64/Dispatch.swiftmodule
sudo rm /usr/lib/swift/linux/x86_64/Dispatch.swiftdoc
それと swift-corelibs-libdispatch
をインストールするときにダウンロードしたソースコードも削除しておきます。今回は /usr/local/src/Kitura
ディレクトリにダウンロードして作業をしたので、それを削除することにします。
cd /usr/local/src/Kitura
rm -rf swift-corelibs-libdispatch
そうしたら、次のようにして swift-corelibs-libdispatch
のダウンロードとインストールを行います。前回の 0.2.0 とは少し手順が変わった様子です。
ちなみに途中の configure
では --with-swift-toolchain
と --prefix
オプションで、Swift をインストールしてある /toolchains/swift-current/usr
を指定しています。
git clone https://github.com/apple/swift-corelibs-libdispatch.git
cd swift-corelibs-libdispatch
git submodule init
git submodule update
./autogen.sh
./configure --with-swift-toolchain=/toolchains/swift-current/usr --prefix=/toolchains/swift-current/usr
make
sudo make install
これで swift-corelibs-libdispatch
のインストールが完了しました。
これまでは /usr/local/include
にインストールされてましたけど、今度は関連するライブラリファイルが、上の --prefix
で指定したディレクトリの中に、今回であれば /toolchains/swift-current/usr/lib/swift/linux/
にインストールされることになる様子です。
Swift のバージョンを切り替えた時の注意
なお、今回みたいに Swift のバージョンを切り替えた場合、上記の make
を実行したタイミングで次のようなエラーが発生することがありました。
/toolchains/swift-current/usr/bin/swiftc -Xcc -fmodule-map-file=/usr/local/src/Kitura/swift-corelibs-libdispatch/dispatch/module.map -I/usr/local/src/Kitura/swift-corelibs-libdispatch -parse-as-library -Xcc -fblocks -c -o /usr/local/src/Kitura/swift-corelibs-libdispatch/src/Dispatch.o /usr/local/src/Kitura/swift-corelibs-libdispatch/src/swift/Dispatch.swift
swift: /home/buildnode/jenkins/workspace/oss-swift-package-linux-ubuntu-14_04/llvm/tools/clang/lib/Serialization/ASTWriter.cpp:2371: unsigned int clang::ASTWriter::getSubmoduleID(clang::Module *): Assertion `(ID || !Mod) && "asked for module ID for non-local, non-imported module"' failed.
0 swift 0x00000000031229b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 40
1 swift 0x0000000003121186 llvm::sys::RunSignalHandlers() + 54
2 swift 0x00000000031234ea
3 libpthread.so.0 0x00002af32ac5c340
4 libc.so.6 0x00002af32c12acc9 gsignal + 57
5 libc.so.6 0x00002af32c12e0d8 abort + 328
6 libc.so.6 0x00002af32c123b86
7 libc.so.6 0x00002af32c123c32
8 swift 0x0000000001578f84 clang::ASTWriter::WritePreprocessor(clang::Preprocessor const&, bool) + 6052
9 swift 0x0000000001593d38 clang::ASTWriter::WriteASTCore(clang::Sema&, llvm::StringRef, std::string const&, clang::Module*) + 12216
10 swift 0x0000000001590d3d clang::ASTWriter::WriteAST(clang::Sema&, std::string const&, clang::Module*, llvm::StringRef, bool) + 589
11 swift 0x00000000015ccbf8 clang::PCHGenerator::HandleTranslationUnit(clang::ASTContext&) + 88
12 swift 0x00000000013d8f0c clang::MultiplexConsumer::HandleTranslationUnit(clang::ASTContext&) + 44
13 swift 0x00000000015d9aa6 clang::ParseAST(clang::Sema&, bool, bool) + 614
14 swift 0x00000000013b5695 clang::FrontendAction::Execute() + 69
15 swift 0x000000000137ed61 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) + 1153
16 swift 0x00000000030c102a llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) + 266
17 swift 0x00000000030c11b4
18 swift 0x000000000312444a
19 libpthread.so.0 0x00002af32ac54182
20 libc.so.6 0x00002af32c1ee47d clone + 109
Stack dump:
0. <eof> parser at end of file
make[2]: *** [/usr/local/src/Kitura/swift-corelibs-libdispatch/src/Dispatch.o] Aborted (core dumped)
これはどうやら、前に swift-corelibs-libdispatch
をインストールした時に Swift ツールチェイン内にコピーされた関連ファイルが干渉して発生しているようでした。これからビルドする swift-corelibs-libdispatch
で、過去に作ったそれを使おうとしているのかもしれません。
そのため swift-corelibs-libdispatch
をビルドするのに使う Swift ツールチェインで過去に swift-corelibs-libdispatch
をビルドしてある場合は、次のように以前にインストールしたファイルを削除してからビルドするようにします。
rm -rf /toolchains/swift-current/usr/lib/swift/dispatch
ライブラリのパスを環境変数に登録する
インストールした pcre2 ライブラリを使えるようにするために ~/.bash_profile
ファイルの中に次の内容を記載しておきます。
export LD_LIBRARY_PATH="/usr/local/lib":"${LD_LIBRARY_PATH}"
export LD_RUN_PATH="/usr/local/lib":"${LD_RUN_PATH}"
こうしたら、あとは次のようにして .bash_profile
の設定内容を反映します。
source ~/.bash_profile
Kitura サンプルを実行してみる
これで Kitura 0.3.0 の実行環境が整ったはずなので、Kitura のサンプルを動かしてみることにします。
以前のビルドファイルを削除
まずは、以前にダウンロードした Kitura リポジトリをアップデートしたり、Kitura 0.2.0 環境でビルドした KituraSample を消去したりしておきます。
/usr/local/src/Kitura/Kitura
git pull
swift build --clean
rm -rf Packages
上記の最後で Packages
ディレクトリを手動で削除していますが、これをしないと make
の時に次のエラーが発生してしまう様子でした。もっと適切なパッケージの消去方法があるのかもわかりませんけど、わからなかったのでこうしています。
swift build
warning: refname '0.2.0' is ambiguous.
warning: refname '0.2.0' is ambiguous.
Resolved version: 0.2.0
error: rename error: Directory not empty (39): /usr/local/src/Kitura/Kitura/Packages/Kitura-router -> /usr/local/src/Kitura/Kitura/Packages/KituraRouter-0.2.0
Kitura をビルドできるようにする
こうしたら、いよいよ Kitura のビルドに入るわけですけれど、そのままでは KituraSample
をビルドすることはできず、次のようなエラーが発生してしまいました。
Compiling Swift Module 'HeliumLogger' (1 sources)
<unknown>:0: error: module 'Dispatch' requires feature 'blocks'
<unknown>:0: error: could not build Objective-C module 'Dispatch'
<unknown>:0: error: module 'Dispatch' requires feature 'blocks'
<unknown>:0: error: could not build Objective-C module 'Dispatch'
<unknown>:0: error: module 'Dispatch' requires feature 'blocks'
<unknown>:0: error: could not build Objective-C module 'Dispatch'
<unknown>:0: error: module 'Dispatch' requires feature 'blocks'
<unknown>:0: error: could not build Objective-C module 'Dispatch'
<unknown>:0: error: build had 1 command failures
error: exit(1): /toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-02-25-a-ubuntu14.04/usr/bin/swift-build-tool -f /usr/local/src/Kitura/Kitura/.build/debug.yaml default
make: [make] Error 1 (ignored)
それともう一つ、次のようなエラーも発生しています。
make -f Packages/Kitura-net*/Makefile
make[1]: Entering directory `/usr/local/src/Kitura/Kitura'
make[1]: Packages/Kitura-net*/Makefile: No such file or directory
これについて、どうしたら良いかと1日ばかり考えあぐねていたのですけど、Twitter で @ki_machoさん にいろいろ教えて頂きました。
@es_kumagai こちらこそありがとうございます! https://t.co/JAMmJtwORH と https://t.co/8YSqybrCMs を参考にしつつ準備してMakefileの変更をすれば動くかと思います。https://t.co/iNqgE35Gq4
— akimacho (@ki_macho) 2016年2月26日
わかったこととしては、まず make -f Packages/Kitura-net*/Makefile
のところは、Swift パッケージマネージャーが更新されたか何かの都合で、ビルドの際にダウンロードされたパッケージの場所が Packages/KituraNet
になったことが原因だった様子でした。
これについては @ki_machoさん
の指摘どおり、Kitura の Makefile
内にある make
の記載を次のように編集することで対応できる様子でした。
make:
-swift build
make -f Packages/KituraNet*/Makefile
その他のエラーについて考える(無視可能)
もうひとつの error: module 'Dispatch' requires feature 'blocks'
については別のところでは無視して問題ないという話もあったのですけど、気持ち悪いので調べてみることにしました。
すると、どうやら swift build
を実行する時に -Xcc -fblocks
オプションを指定しないと、ビルドする Swift コード内で import Dispatch
を実行して GCD 関連の機能を使おうとした時に、このエラーが発生する様子でした。
これを改善するには先ほどの Makefile
をもう少しだけ調整して、次のようにすることで対応できます。
make:
-swift build -Xcc -fblocks
make -f Packages/KituraNet*/Makefile
これでもまだ次のエラーが残るものの、とりあえずこれで KituraSample
がビルドされて、動かすことができるようになりました。
Linking KituraSample
/usr/bin/ld: cannot find -lcurlHelpers
/usr/bin/ld: cannot find -lhttpParserHelper
clang: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: build had 1 command failures
error: exit(1): /toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-02-25-a-ubuntu14.04/usr/bin/swift-build-tool -f /usr/local/src/Kitura/Kitura/.build/debug.yaml default
ただ、やっぱりこれも残っているのは気持ちが悪いので調べてみたのですけど、これはどうやら curlHelpers
と httpParserHelper
という2つのライブラリが、最初の swift build
ではまだ生成されていないため、KituraSample
にリンクしようとして失敗した状況みたいです。
ただ、その後に実行される make -f Packages/KituraNet*/Makefile
の中でこれら2つのライブラリが生成されて、再び最後に swift build
が実行されてリンクされる様子なので、このエラーについてはひとまず無視しておくしかなさそうです。
ともあれここまで調べを進めてみると、最初の error: module 'Dispatch' requires feature 'blocks'
のエラーについても、その後のリンクのステップと合わせて、ちゃんと -Xcc -fblocks -Xlinker -L./.build/debug
付きの swift build
が改めて実行されるので、確かにそのまま無視しておいても普通に大丈夫そうなことがわかってきました。
そうすると、つまり最終的には Kitura 直下の Makefile
を、次のように最後の make
のところだけ書き換えておけば大丈夫そうですね。
make:
-swift build
make -f Packages/KituraNet*/Makefile
KituraSample をビルドする
ともあれ、このように Makefile
を修正することで、次のようにして Kitura サンプルをビルドできるようになりました。
make
初回ビルド時に1つだけ、次のエラーが発生しますけど、上記の通り、無視するしかないエラーな様子です。
Linking KituraSample
/usr/bin/ld: cannot find -lcurlHelpers
/usr/bin/ld: cannot find -lhttpParserHelper
clang: error: linker command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: build had 1 command failures
error: exit(1): /toolchains/swift-DEVELOPMENT-SNAPSHOT-2016-02-25-a-ubuntu14.04/usr/bin/swift-build-tool -f /usr/local/src/Kitura/Kitura/.build/debug.yaml default
Kitura 0.3.0 環境への移行完了
こんな感じで Kitura 0.3.0 環境への移行は無事に完了しました。
複雑な手順になりましたけど、現在の develop
ブランチを使えばこういったエラーに悩まされることは無くなるので、しばらくすれば、きっと master
ブランチに取り込まれて普通にビルドできるようになりそうです。
まとめ
まとめると、とりあえず今の問題としては、たぶん Swift パッケージマネージャーの仕様変更により Kitura-net
パッケージがダウンロードされるディレクトリが KituraNet
になったためにエラーが発生、それに手作業で対応しないといけない、ということに集約できそうでした。
その他の Dispatch に関するエラーとリンク失敗に関するエラーは驚くだけで、単に今の Makefile
の設計が、敢えて無視して先の手順へ進むようになっている、ということだったみたいでした。