Debian上にOSvビルド環境を構築してみた

Debian上にOSvビルド環境を構築してみた

OSvもくもく会#1 〜OSvで遊んでみよう〜 の予習を兼ねて、Debian上にOSvビルド環境を構築してみました。

OSv

OSvはマイナビニュースで説明されているように、「クラウドオペレーティングシステム」という位置づけになっています。https://github.com/cloudius-systems/osvの説明では、Debian,Fedoraでのビルド環境構築が可能なようであり、今回はそれを参照しながら作業してみました。

ビルド環境構築の流れ

以下の順番でビルド環境の構築を進めます。

Debian(amd64)のインストール

gcc-4.9.0のビルド・インストール

OSvのビルドにはgcc-4.8.0以上が必要ですが、Debianのパッケージはgcc-4.7が最新版であり、必要なgccバージョンを満たしていません。このため、gcc-4.9.0(2014/04/22にリリース)を自分でビルドします。

自分でビルドするものについては既存の環境と混ぜこぜにしたくないので、/opt以下にインストールする方針で作業を進めます。

Prerequisites for GCCにはgccのビルドに必要なツール、ライブラリが記載されています。gccのビルドの前に以下のライブラリをビルドします。バージョンの指定がある点に注意が必要です。

  • GNU Multiple Precision Library (GMP) version 4.3.2 (or later)
  • MPFR Library version 2.4.2 (or later)
  • MPC Library version 0.8.1 (or later)
  • ISL Library version 0.12.2
  • CLooG 0.18.1

gccビルドに関連するパッケージのインストール

まずはgccのビルド作業に必要となるツールをパッケージからインストールします。

$ sudo sudo apt-get install lzip     # .lz形式のgmp配布物の展開に必要
$ sudo sudo apt-get install autogen  # autogenが無いとgccのビルドでエラーになる

ソースファイルの準備(ダウンロード)

インストール前に決めておくこと

  • インストール先は/opt/gcc-4.9.0とする。

必要なライブラリのビルドとインストール

必要なソースアーカイブはあらかじめダウンロードしておきます。

$ ls Download/
cloog-0.18.1.tar.gz  gmp-6.0.0a.tar.lz   mpc-1.0.2.tar.gz
gcc-4.9.0.tar.gz     isl-0.12.2.tar.bz2  mpfr-3.1.2.tar.gz

ライブラリパスの設定

インストール先を/opt/gcc-4.9.0に想定しているので、作業前にライブラリパスを設定してしまいます。

後から設定しようとすると忘れてしまいがちで、make checkでテストがFAILしてからライブラリパスが未設定だったことに気づいたりします...。

$ export LD_LIBRARY_PATH=/opt/gcc-4.9.0/lib:$LD_LIBRARY_PATH
$ export LD_RUN_PATH=/opt/gcc-4.9.0/lib:$LD_RUN_PATH

gmpのビルド

gmpのみソースアーカイブがlzip形式のみでの提供になっています。

$ lzip -dc Download/gmp-6.0.0a.tar.lz | tar xvf -
$ cd gmp-6.0.0/
$ mkdir build ; cd build
$ ../configure --enable-cxx --prefix=/opt/gcc-4.9.0 2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

mpfrのビルド

$ tar zxvf Download/mpfr-3.1.2.tar.gz
$ cd mpfr-3.1.2/
$ mkdir build ; cd build
$ ../configure --prefix=/opt/gcc-4.9.0 \
               --with-gmp-include=/opt/gcc-4.9.0/include \
               --with-gmp-lib=/opt/gcc-4.9.0/lib \
               2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

mpcのビルド

$ tar zxvf Download/mpc-1.0.2.tar.gz
$ cd mpc-1.0.2/
$ mkdir build ; cd build
$ ../configure --prefix=/opt/gcc-4.9.0 \
               --with-gmp-include=/opt/gcc-4.9.0/include \
               --with-gmp-lib=/opt/gcc-4.9.0/lib \
               --with-mpfr-include=/opt/gcc-4.9.0/include \
               --with-mpfr-lib=/opt/gcc-4.9.0/lib \
               2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

islのビルド

$ tar jxvf Download/isl-0.12.2.tar.bz2
$ cd isl-0.12.2
$ mkdir build ; cd build
$ ../configure --prefix=/opt/gcc-4.9.0 \
               --with-gmp-builddir=/opt/gcc-4.9.0/lib \
               CFLAGS="-I/opt/gcc-4.9.0/include" \
               LDLAGS="-I/opt/gcc-4.9.0/lib" \
               2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

cloogのビルド

$ tar zxvf Download/cloog-0.18.1.tar.gz
$ cd cloog-0.18.1
$ mkdir build ; cd build
$ ../configure --prefix=/opt/gcc-4.9.0 \
               --with-isl=system \
               --with-isl-prefix=/opt/gcc-4.9.0 \
               --with-gmp=system \
               --with-gmp-prefix=/opt/gcc-4.9.0 \
               CFLAGS="-I/opt/gcc-4.9.0/include" \
               LDLAGS="-I/opt/gcc-4.9.0/lib" \
               2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

gcc-4.9.0のビルド・インストール

今回欲しいのはC++コンパイラなので、--enable-languages=c,c++を指定して必要なコンパイラのみビルドします(C言語も不要かもしれません)。

$ tar zxvf Download/gcc-4.9.0.tar.gz
$ cd gcc-4.9.0
$ mkdir build ; cd build
$ ../configure --prefix=/opt/gcc-4.9.0 \
               --disable-multilib \
               --program-suffix=-4.9.0 \
               --enable-stage1-languages=c,c++ \
               --enable-languages=c,c++ \
               --disable-isl-version-check \
               --with-mpc-include=/opt/gcc-4.9.0/include \
               --with-mpc-lib=/opt/gcc-4.9.0/lib \
               --with-mpfr-include=/opt/gcc-4.9.0/include \
               --with-mpfr-lib=/opt/gcc-4.9.0/lib \
               --with-isl-include=/opt/gcc-4.9.0/include \
               --with-isl-lib=/opt/gcc-4.9.0/include \
               --with-gmp-include=/opt/gcc-4.9.0/include \
               --with-gmp-lib=/opt/gcc-4.9.0/lib \
               CFLAGS="-I$/opt/gcc-4.9.0/include" \
               LDLAGS="-L/opt/gcc-4.9.0/lib -L/usr/lib" \
               2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ (date ; make check ; date) 2>&1 | tee -a _make_check.log
$ sudo make install 2>&1 | tee -a _make_install.log

簡単な動作確認

$ export LD_LIBRARY_PATH=/opt/gcc-4.9.0/lib:$LD_LIBRARY_PATH
$ export LD_RUN_PATH=/opt/gcc-4.9.0/lib:$LD_RUN_PATH
$ export PATH=/opt/gcc-4.9.0/bin:$PATH
$ which gcc-4.9.0
/opt/gcc-4.9.0/bin/gcc-4.9.0
$ which g++-4.9.0
/opt/gcc-4.9.0/bin/g++-4.9.0
$ gcc-4.9.0 --version
gcc-4.9.0 (GCC) 4.9.0
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++-4.9.0 --version
g++-4.9.0 (GCC) 4.9.0
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

qemu-2.0.0のビルド・インストール

OSvのビルド時にqemuの機能を利用しますが、Debianqemuパッケージだとvirtio-rng-pciなデバイスが利用できないため、ビルドエラーとなります。

https://github.com/cloudius-systems/osv/issues/127を見ると、./configure --enable-virtfsしたqemuを使う方法が紹介されており、これに倣いqemuを自分でビルドします。最初Debianqemuパッケージと同じバージョンのqemu(1.1.2)をビルドしましたが、そのバージョンではvirtio-rng-pciが提供されていないため、最新版のqemuを使います。

ビルドに必要なパッケージのインストール

$ sudo apt-get install pkg-config
$ sudo apt-get install libglib2.0-dev  # Development files for the GLib library
$ sudo apt-get install libcap-dev
$ sudo apt-get install libattr1-dev

libcap-dev,libattr1-devパッケージが無いと、configure --enable-virtfs時に以下のエラーとなります。

VirtFS is supported only on Linux and requires libcap-devel and libattr-devel
$ tar jxvf ./Download/qemu-2.0.0.tar.bz2
$ cd qemu-2.0.0
$ ./configure --prefix=/opt/qemu-2.0.0 \
              --target-list=x86_64-softmmu,x86_64-linux-user \
              --enable-virtfs \
              2>&1 | tee -a _configure.log
$ (date ; make ; date) 2>&1 | tee -a _make.log
$ sudo make install 2>&1 | tee -a _make_install.log

インストール後、virtio-rng-pciが使用可能デバイスに含まれていることを確認します。

$ qemu-system-x86_64 -device ? 2>&1 | grep virtio-rng-pci
name "virtio-rng-pci", bus PCI

OSvのビルド

環境変数の設定

/opt以下にインストールしたgcc-4.9.0,qemu-2.0.0と必要なライブラリを参照するよう、.bashrc等に以下を追加します。

LD_LIBRARY_PATH=/opt/gcc-4.9.0/lib64:$LD_LIBRARY_PATH
LD_LIBRARY_PATH=/opt/gcc-4.9.0/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH

LD_RUN_PATH=/opt/gcc-4.9.0/lib64:$LD_RUN_PATH
LD_RUN_PATH=/opt/gcc-4.9.0/lib:$LD_RUN_PATH
export LD_RUN_PATH

PATH=/opt/gcc-4.9.0/bin$PATH
PATH=/opt/qemu-2.0.0/bin:$PATH
export PATH=/opt/gcc-4.9.0/bin:/opt/qemu-2.0.0/bin:$PATH

export CXX=/opt/gcc-4.9.0/bin/g++-4.9.0

GitHubからOSvソースコードをclone

OSvのGitHubの手順にしたがいソースコードをcloneします。clone後、"git submodule update"が必要です。

$ git clone https://github.com/cloudius-systems/osv.git
$ git submodule update --init --recursive

OSvのビルド

$ cd osv
$ (date ; make ; date) 2>&1 | tee -a _make.log

OSv上でHello,Worldを動かす

OSvを実行する前に、kvm.koをロードします(デフォルトではkvm.koがロードされていない)。

$ sudo /sbin/modprobe kvm
$ lsmod | grep kvm
kvm                   287749  0

Hello,world.を動かしてみます。

$ cat apps/java-example/Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
$ make image=java-example
$ scripts/run.py -e "java.so -cp /java-example Hello"
OSv v0.08-60-g8dd67e0
eth0: 192.168.122.15
Hello, World!

ハマりどころ

何もかもが上手く進んだ場合、前述までの手順でOSvのビルドまで行えます、が、OSvのビルドではハマり所がたくさんあります(ありました...)。

何点かハマった点について、エラー内容と解消方法を以下に記載します。

Makeファイルのjar-jarsターゲットの実行でエラーが出る

jar-jarsターゲットの実行で以下のようなエラーが出る場合があります。

$ make
...中略...
  MVN java-jars
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project cloudius: Fatal error compiling: invalid target release: 1.7 -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
make[1]: *** [java-jars] Error 1
make[1]: Leaving directory `/home/fpig/work/osv_buld/osv/build/release'
make: *** [all] Error 2
$ make
...中略...
  MVN java-jars
[ERROR] BUILD ERROR
make[1]: *** [java-jars] Error 1
make[1]: Leaving directory `/home/fpig/work/osv_buld/osv/build/release'
make: *** [all] Error 2

私の環境では、Maven,JDKのバージョンを複数インストールしていたことが原因でした。

$ /usr/share/maven/bin/mvn --version
Apache Maven 3.0.4
Maven home: /usr/share/maven
Java version: 1.6.0_31, vendor: Sun Microsystems Inc.
Java home: /usr/lib/jvm/java-6-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.2.0-4-amd64", arch: "amd64", family: "unix"

$ /usr/share/maven2/bin/mvn --version
Apache Maven 2.2.1 (rdebian-8)
Java version: 1.6.0_31
Java home: /usr/lib/jvm/java-6-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux" version: "3.2.0-4-amd64" arch: "amd64" Family: "unix"

Maven 3.0.4が使われると思っていましたが、実際はMaven 2.2.1が使われていました。

$ mvn -version
Apache Maven 2.2.1 (rdebian-8)
Java version: 1.7.0_55
Java home: /usr/lib/jvm/java-7-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux" version: "3.2.0-4-amd64" arch: "amd64" Family: "unix"

さっそく切り替えます。

$ sudo update-alternatives --config mvn
There are 2 choices for the alternative mvn (providing /usr/bin/mvn).

  Selection    Path                       Priority   Status
------------------------------------------------------------
* 0            /usr/share/maven2/bin/mvn   200       auto mode
  1            /usr/share/maven/bin/mvn    150       manual mode
  2            /usr/share/maven2/bin/mvn   200       manual mode

Press enter to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/share/maven/bin/mvn to provide /usr/bin/mvn (mvn) in manual mode

これでOK。

$ mvn -version
Apache Maven 3.0.4
Maven home: /usr/share/maven
Java version: 1.7.0_55, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-7-openjdk-amd64/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.2.0-4-amd64", arch: "amd64", family: "unix"

ちなみに、mvn -eで詳細なエラー表示が行えます。Mavenまわりで上記以外のエラーが出た際はbuild.mk内のMVNに-eを追加すると原因切り分けが楽になるかもしれません。

$ man mvn
...中略...
       -e,--errors
              Produce execution error messages

JDKについても、私の環境ではこちらも予想と異なるjdkが使われていました。
(あれこれ試行錯誤する中でmaven2やopenjdk-6-jdkとかインストールしたのがマズかったようです...)

$ javac -version
javac 1.6.0_31
$ sudo update-alternatives --config javac
There are 2 choices for the alternative javac (providing /usr/bin/javac).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/java-6-openjdk-amd64/bin/javac   1061      auto mode
  1            /usr/lib/jvm/java-6-openjdk-amd64/bin/javac   1061      manual mode
  2            /usr/lib/jvm/java-7-openjdk-amd64/bin/javac   1051      manual mode

Press enter to keep the current choice[*], or type selection number: 2
update-alternatives: using /usr/lib/jvm/java-7-openjdk-amd64/bin/javac to provide /usr/bin/javac (javac) in manual mode

java,javac共にjava-7-openjdk-amd64を参照することを確認します。

$ java -version
java version "1.7.0_55"
OpenJDK Runtime Environment (IcedTea 2.4.7) (7u55-2.4.7-1~deb7u1)
OpenJDK 64-Bit Server VM (build 24.51-b03, mixed mode)
$ javac -version
javac 1.7.0_55

"undefined reference to `__cxa_throw_bad_array_new_length'"が発生する

これはエラーメッセージの通り、__cxa_throw_bad_array_new_length()が見つけられないことが原因です。

$ make
...中略...
  LD loader.elf
arch/x64/smp.o: In function `smp_init()':
/home/fpig/work/osv_buld/osv/arch/x64/smp.cc:78: undefined reference to `__cxa_throw_bad_array_new_length'
core/mempool.o: In function `memory::mark_smp_allocator_intialized::mark_smp_allocator_intialized()':
/home/fpig/work/osv_buld/osv/core/mempool.cc:386: undefined reference to `__cxa_throw_bad_array_new_length'
make[1]: *** [loader.elf] Error 1
...中略...

__cxa_throw_bad_array_new_length()は/opt/gcc-4.9.0/lib64/libstdc++.soにあります(前述のgccビルド手順を実施した場合)。

$ for i in `find /opt/gcc-4.9.0/ | grep \\.so$`;
  do
       nm $i | grep __cxa_throw_bad_array_new_length
       if [ $? -eq 0 ]; then
           echo $i
       fi
  done
000000000005d3a0 T __cxa_throw_bad_array_new_length
/opt/gcc-4.9.0/lib64/libstdc++.so

build.mkの中でlibstdc++.aの場所を指定しているので、/opt/gcc-4.9.0以下のライブラリを探索するようにbuild.mkを修正します。

$ diff -u build.mk.orig build.mk
--- build.mk.orig       2014-05-09 02:53:53.124712117 +0900
+++ build.mk    2014-05-09 08:37:33.570625829 +0900
@@ -784,6 +784,7 @@
 objects += $(addprefix fs/, $(fs))
 objects += $(addprefix libc/, $(libc))

+gccbase = /opt/gcc-4.9.0
 libstdc++.a = $(shell find $(gccbase)/ -name libstdc++.a)
 libsupc++.a = $(shell find $(gccbase)/ -name libsupc++.a)
 libgcc_s.a = $(shell find $(gccbase)/ -name libgcc.a |  grep -v /32/)

bare.imgの作成時に"qemu-system-x86_64: -device virtio-rng-pci: Parameter 'driver' expects device type"のエラーが出る

$ make
...中略...
Creating bare.img as qcow2


/home/fpig/work/osv_buld/osv/scripts/mkzfs.py -o bare.img -d bare.img.d -m /home/fpig/work/osv_buld/osv/build/release/bootfs.manifest
qemu-system-x86_64: -device virtio-rng-pci: Parameter 'driver' expects device type
QEMU 1.1.2 monitor - type 'help' for more information
(qemu) QEMU 1.1.2 monitor - type 'help' for more information
(qemu)
Traceback (most recent call last):
  File "/home/fpig/work/osv_buld/osv/scripts/mkzfs.py", line 44, in <module>
    upload_manifest.upload(osv, manifest, depends)
  File "/home/fpig/work/osv_buld/osv/scripts/upload_manifest.py", line 62, in upload
    s.connect(("127.0.0.1", 10000));
  File "/usr/lib/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused
make[1]: *** [bare.img] Error 1
make[1]: *** Deleting file `bare.img'
make[1]: Leaving directory `/home/fpig/work/osv_buld/osv/build/release'
make: *** [all] Error 2

これはDebianqemuパッケージではvirtio-rng-pciが利用できないことが原因です。前述のqemuビルドの手順を実施します。

まとめ

Debian上にOSvのビルド環境を構築し、Hello,Worldまで動かしてみました。ビルド環境構築にはいくつかハマり所があり、以下の点に気をつける必要がありました。

  • Debianamd64版を使用する(i386だとダメ)
  • OSvで2GBのメモリを使用するので、ビルド環境のマシンはそれを見越したメモリ量にする
  • MavenJDKは複数バージョンの混在に注意する
    • 混在していた場合は、update-alternativesで適切なバージョンを利用するよう設定する
  • gccは4.8.0以上を使用する
  • gccビルドではconfigure --disable-multilib,--enable-languages=c,c++を忘れずに指定する

参照ドキュメント

gcc4.9のビルド手順を調べるにあたり、以下のWebサイト・blogの内容を参考にさせていただきました。

変更履歴

  • 2014/05/17:OSvソースコードのclone手順に抜けがあったため追記しました。

「ポケットミクちゃんに何かいろいろさせる会(その1)」開催レポート

「ポケットミクちゃんに何かいろいろさせる会(その1)」開催レポート

ポケットミクちゃんに何かいろいろさせる会(その1)という会を開催してみました。

勉強会ではメモを書いたりするのですが、家に帰るとメモを見返すこともなく、せっかくのメモが埋もれてしまうパターンに陥っているので、ここは思い切って勉強会のメモを元に、(ものすごく)簡単なレポートを書き残すことにしてみました。

みんなでやってみたこと

運の良いことに、参加者のマシンがWindows,OSX,Linux,NetBSDとバラけており、Chromeさえあればポケミクアプリが利用できるという便利さを痛感しました(が、NetBSDのみChromeを動作させられなかったという残念なオチが...)。

得られたノウハウ

あれこれ試してみて、以下のようなノウハウが得られました。

  • 最初にみんなでキャリブレーション(ユーザーズ・マニュアルのP.13)をするも、以外にチューニングに手間取るケースが多かった。
  • UbuntuRosegardenでポケットミクから音が出せる
  • GarageBandのデフォルト機能ではMIDI出力が行えない。別途プラグインが必要。
  • GarageBandでは、ポケットミクのデバイス名が"Soundflower"になる。
  • DominoCubase(キューベス)でもポケットミクが利用できるらしい。
    • (どちらも使ったことが無いので分からない...)
  • NetBSDだと、midiplay(1)でMIDIファイルを指定し、ポケットミクに演奏させることができる
    • ただし、何回か演奏しているとOSごと刺さる(!)ことがある。
$ midiplay -l
0: PC speaker
1: <0 >0 on umidi0
$ midiplay -d 1 foo.mid
  • Ubuntuにもmidiplay(1)相等のコマンドがある(が、コマンド名を確認し忘れた...)

ポケミクアプリを動かしてみたり、ニコニコ超会議超ボカロサミットを一通り観たりしていると、飛び入りの参加者さんが。先ほどまで観ていたニコニコ動画に映っていた人に名前が似ている...と思っていると、その人本人(ポケットミク総合Pの@polymoogさん)ががが!

なんだか凄いことになっちゃったぞ((C)孤独のグルメ)と驚きながら、@polymoogさんからポケットミクのひみつを聞いたり、みんなでポケットミクを動かしてみた時に出てきた疑問を聞いてみました。
(※以下は私の理解による記述であり、間違って理解している可能性がある点にご注意ください)

  • 実は演奏中もキャリブレーション処理が走っているらしい。
  • カーボンキーボードのスキャン方法は2パターンあるらしい。
  • シーケンサ側から音色番号を指定して音をだせるが、ポケットミク単体でも可能かもしれない。
  • ポケットミクのカーボンキーボードでシーケンサに入力する際、同じ音程で入力される。これはピッチベンドで音を入れているため。
  • ユーザーズ・マニュアルの「デフォルト文字テーブル」にあるシステムエクスクルーシブデータ、さりげなく例を出しているが何かひみつがあるとか。
  • ポケットミクと共にWeb MIDI APIが広まって欲しい。
  • フィジカルコントローラとしてポケットミクを活用したい。
  • ポケットミクの本、5月中頃から6月頭にかけて刊行されるかも。

やはりポケットミクの開発に携わった方の話はとても興味を惹かれました。ユーザーズ・マニュアルに書かれていないひみつは多いようで、ポケットミクの本がとても待ち遠しいです。

思いついたアイディア

私の環境ではChromeブラウザが動作しないため、ポケミクアプリを利用することができませんでした。しかし、お話を聞いてみるとポケミクアプリが利用しているWeb MIDI APIに俄然興味が湧いてきました。みんなで話していると、ポケミクアプリの他にも以下のようなアイディアが出てきました。

  • フィジカルコントローラとしてのポケットミクの活用。
    • カーボンキーボードからの入力を利用したアルカノイド風ゲームを作成した人がいるとか。
  • カーボンキーボードで抑揚をつけたテキスト読み上げ
    • まるで喋っているかのようなリアルな読み上げができる?
  • ポケットミクで何か言葉を喋らせて、Siriやしゃべってコンシェルが音声認識できるか試してみたい。
    • 「神調教」と呼ばれる職人の腕前と音声認識の対決?

次回の予定

単にポケットミクを動かしてみようという所から始まった会ですが、実際に開催してみるとポケットミクの隠されたひみつやWeb MIDI API、フィジカルインタフェースとしての活用など、試してみたい項目がいろいろ出てきました。そこで今後も何回かこの会を継続してみようと考えています。

次回は6/28(土)を予定しています。告知ページは近日中に作成する予定ですので、皆様のご参加をお待ちしております。

追記

次回の告知ページを公開しました。

dtrace機能を有効にしたNetBSDインストールCDを作成してみた

dtrace機能を有効にしたNetBSDインストールCDを作成してみた

NetBSDのdtrace機能を試してみようと思い立ち、@akachochinさんのNetBSD dtrace格闘記その2を元にdtrace機能を有効にしたインストールCDの作成手順をまとめてみました。

インストールCD作成準備

@akachochinさんのblogでは、インストール済みのNetBSD環境に直接dtraceまわりのカーネルモジュールをインストールしています。私の環境ではdtraceを有効にしたNetBSDのインストールCDを作成したいため、まずはインストールCD作成用のNetBSD環境を準備します。

ソースコードを展開する

NetBSD-6.1.3-i386仮想マシンにインストールした後、ソースコードを展開します。

# mount /dev/cd0a /cdrom
# cd /cdrom/source/sets/
# ls -l *.tgz
-r--r--r--  1 root  wheel   43069713 Jan 19 20:15 gnusrc.tgz
-r--r--r--  1 root  wheel    7661899 Jan 19 20:16 sharesrc.tgz
-r--r--r--  1 root  wheel  203542266 Jan 19 20:14 src.tgz
-r--r--r--  1 root  wheel   40189162 Jan 19 20:15 syssrc.tgz
-r--r--r--  1 root  wheel  158393066 Jan 19 20:18 xsrc.tgz

ソースコードは/usr/src以下に展開します。

# for i in *.tgz; do tar zxvf $i -C /; done

カーネルコンフィグを修正してdtrace機能を有効化する

dtrace機能を有効にするためのカーネルコンフィグを追加します。INSECURE,KDTRACE_HOOKS,MODULARを有効にする必要がありますが、GENERICコンフィグではINSECURE,MODULARは既に有効になっていたため、KDTRACE_HOOKSのみ追加します。

# cd /usr/src/sys/
# diff -u arch/i386/conf/GENERIC.orig arch/i386/conf/GENERIC
--- arch/i386/conf/GENERIC.orig 2012-08-16 00:33:00.000000000 +0900
+++ arch/i386/conf/GENERIC      2014-04-13 02:23:38.000000000 +0900
@@ -74,6 +74,7 @@
 # Standard system options

 options        INSECURE        # disable kernel security levels - X needs this
+options                KDTRACE_HOOKS

 options        RTC_OFFSET=0    # hardware clock is this many mins. west of GMT
 options        NTP             # NTP phase/frequency locked loop

build.shを実行する

build.shを使用して一通りのビルドを行います。ビルドは時間がかかるので、以下のスクリプトを作成し、バッチ処理的にビルドを行うようにしました。

上記のスクリプトMac mini(2.4GHz Intel Core 2 Duo,メモリ 8GB)のVirtualBox上のNetBSDで走らせたところ、全てのビルドが完了するまで15時間程度かかりました。

ビルドが完了すると、以下の場所にdtrace機能が有効になったインストールCDが生成されます。

/usr/obj/distrib/i386/cdroms/installcd/NetBSD-6.1.3-i386.iso 

OSインストール後のdtrace機能を利用するための設定投入

インストールCDが作成できたので、このCDを使用してNetBSDを再度インストールします。インストール後、dtrace用にデバイスファイルを作成します(OSインストール後に一度行うだけで良い)。

# mkdir /dev/dtrace
# mknod /dev/dtrace/dtrace c dtrace 0

そして、OS起動時にdtraceに必要なカーネルモジュールをロードするよう設定します。もっとスマートな方法があると思うのですが、今回は/etc/rc.localに以下の処理を追加しました。

_MODULE="
solaris
dtrace
sdt
fbt
"
for i in ${_MODULE}
do
    echo "modload ${i}"
    modload ${i}
done

OSを再起動するとdtrace機能が利用可能になっています。

# dtrace -l | wc -l
  45326

dtrace機能を試してみる

NetBSDでdtraceが利用できるようになったので、例としてgetpid()システムコールをフックさせてみます。

"getpid"というキーワードにマッチする関数は、sys_getpid(),sys_getpid_with_ppid()の2つがあるようです。

# dtrace -l | grep getpid
21001        fbt            netbsd                        sys_getpid entry
21002        fbt            netbsd                        sys_getpid return
21003        fbt            netbsd              sys_getpid_with_ppid entry
21004        fbt            netbsd              sys_getpid_with_ppid return

どちらがgetpid()システムコールの実体か分からないので、"getpid"でマッチするようにしてみます。dtrace -nを実行すると、その端末内で出力待ちの状態になります。

# dtrace -n fbt:netbsd:*getpid*:entry
dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes

別の端末にて、getpid()を実行するサンプルプログラムを用意します。

# cat _getpid.c
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
        printf("%d\n", getpid());
        return 0;
}
# gcc -Wall -Werror -g -o _getpid _getpid.c

サンプルプログラムを実行すると、dtraceを実行している端末に以下が出力されます。

# dtrace -n fbt:netbsd:*getpid*:entry
dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0  21003       sys_getpid_with_ppid:entry
  0  21003       sys_getpid_with_ppid:entry

getpid()の実体はsys_getpid_with_ppid()のようです。プロセスの生成時にもsys_getpid_with_ppid()は呼ばれるようで、出力が2回になっています。

# cat -n /usr/src/sys/kern/kern_prot.c
    81  /* ARGSUSED */
    82  int
    83  sys_getpid_with_ppid(struct lwp *l, const void *v, register_t *retval)
    84  {
    85          struct proc *p = l->l_proc;
    86
    87          retval[0] = p->p_pid;
    88          retval[1] = p->p_ppid;
    89          return (0);
    90  }

まとめ

NetBSDでdtrace機能を試してみました。デフォルトインストールではdtrace機能が有効で無いため、カーネルカーネルモジュールの構築が必要です。インストールCDが欲しかったので、備忘録を兼ねた一通りのビルド手順についてもまとめてみました。

ポケットミクでテキスト読み上げ

ポケットミクでテキスト読み上げ

学研から発売された「歌うキーボード ポケットミク」を動かしてみました。

カーボンキーボードで演奏すると、初音ミクが「どーれーみー」という感じで歌ってくれます。また、MIDIデバイスとして利用でき、例えばNetBSDでは以下のdmesgが得られます(NetBSD-6.1-i386の場合です)。

Apr 29 07:12:32 hayase /netbsd: uaudio0 at uhub3 port 3 configuration 1 interface 0
Apr 29 07:12:32 hayase /netbsd: uaudio0: NSX-39 NSX-39, rev 2.00/1.00, addr 2
Apr 29 07:12:32 hayase /netbsd: uaudio0: audio descriptors make no sense, error=4
Apr 29 07:12:32 hayase /netbsd: umidi0 at uhub3 port 3 configuration 1 interface 1
Apr 29 07:12:32 hayase /netbsd: umidi0: NSX-39 NSX-39, rev 2.00/1.00, addr 2
Apr 29 07:12:32 hayase /netbsd: umidi0: (genuine USB-MIDI)
Apr 29 07:12:32 hayase /netbsd: umidi0: out=1, in=1
Apr 29 07:12:32 hayase /netbsd: midi1 at umidi0: <0 >0 on umidi0

すばらしいことに、GitHub上にはRuby,Python等のスクリプトからポケットミクを操作するためのライブラリが有志によって公開されており、Rubyからポケットミクを操作できるpoket_mikuがあります。

pocket_mikuのインストール

私の環境では、以下の手順でpocket_mikuをインストールしました。

  1. Gemfileを作成する

以下の内容でGemfileを作成します。

source :rubygems
gem 'pocket_miku', :git => "git://github.com/toshia/pocket_miku.git"
  1. gemでインストールする
$ sudo gem193 install pocket_miku
  1. 簡単なサンプルを試す

以下のサンプルを実行すると、初音ミクが「ふぁー ぼー」としゃべります。

#!/usr/bin/env ruby193
# -*- coding: utf-8 -*-

require 'pocket_miku'

PocketMiku.sing '/dev/rmidi1' do
  tempo 240
  ふぁ 75; ぼ 82;
end

ポケットミクでテキストを読み上げてみる

さて、無事にスクリプトから初音ミクにおしゃべりさせることができたワケですが、もう一歩進めて、今度はテキストを読み上げさせてみます。

以下のように、初音ミクにしゃべらせたい音をスクリプトから指定するだけでOKなのですが、「日本語」→「にほんご」のように、平仮名に直して指定する必要があります。

  ふぁ 75; ぼ 82;

ここはサクっとChasenを使ってテキストを平仮名に直すという方法を試してみました。

Chasenによる形態素解析では、以下のような出力が得られます。読みの第一候補(第二カラム)を使うとうまく行きそうです。 (実はこのカラムの名称を知らず、Chasenマニュアルを読む羽目に...)

$ chasen
今日は良い天気です
今日  キョウ    今日    名詞-副詞可能
は    ハ        は      助詞-係助詞
良い  ヨイ      良い    形容詞-自立     形容詞・アウオ段        基本形
天気  テンキ    天気    名詞-一般
です  デス      です    助動詞  特殊・デス      基本形
EOS

スクリプトは以下においてあります。

以下の手順でスクリプトを実行します(現状「!」とかの記号が入ったテキストだとエラーがでます...)。

$ echo 今日は良い天気です | chasen > data.txt
$ ./miksay.rb data.txt

テキストを読み上げたものの...

ポケットミクによるテキスト読み上げまで行えたのですが、いざ発声を聞いてみると、あまりよく聞き取れません。 しばらく聞いていて気がついたのですが、発声の「間」を調節しないと聞き取りにくいようです。

「キョウハ ヨイ テンキデス」という発声だと良いのですが、「キョウハヨイテンキデス」と一気に読み上げると、思っている以上に単語の区切りが分かりにくいです。日々会話する時にはほとんど意識しないのですが、この「間」は重要なのですね。

まとめ

スクリプトからポケットミクをしゃべらせてみました。形態素解析ツールを活用することでうまいこと仮名の切り出しが行えました。テキスト読み上げについては、発声の「間」などの考慮が必要そうで、まだまだ改良の余地ありです。

追記

肝心なことを忘れていました。5月6日に「ポケットミクちゃんに何かいろいろさせる会(その1)」という会を開催する予定です。ご興味のある方はぜひご参加ください。

「悪循環画像ジェネレータ」を作ってみた

悪循環画像とは

昨日くらいから、Twitter上で「悪循環コラ画像」というものが流行っているようです。元々はみやぎ県政だより(2010年12月号)http://www.pref.miyagi.jp/kohou/kenseidayori/backnumber/201012/special/special01.htmの薬物乱用防止の啓蒙記事にある、薬物依存の悪循環を示すイメージ図がオリジナルなのですが、妙に汎用性(?)があるのか、様々なジャンルでの悪循環コラが作られる状態になっています。

そこで悪循環コラ作成の一助になればと思い、「悪循環画像ジェネレータ」を作成してみました。ブラウザ上で文言を入力することで悪循環コラが作れるというものです。

悪循環画像ジェネレータ

URLは以下になります(2017/02/12追記:Bitbucketだと404 Requestが返されてしまうのでGitHub Pagesに引っ越しました)。

入力欄に文言を入力すると、オリジナル画像をテンプレ化(吹き出しの文字を消したもの)した画像に文言が反映されるという動作になっています。
(それしか機能がない……)

単に入力された文言をHTML5 CanvasのfillText()で描画するだけのはずだったのですが、<br>で改行できるようにしたところ、予想よりもちょっと複雑な処理になってしまいました。
というわけで、文言の中に<br>を入れると、改行文字として扱われ、かつ、配置も(ある程度)よきにはからってくれる動作になっています。

悪循環コラを作ってみる

簡単なサンプルとして、のんのんびよりの悪循環コラを作ってみました。
以下のような感じになります。

f:id:furandon_pig:20140104082917p:plain

このツールでさらに悪循環コラが増えてくれればと思います。

その他

このアプリケーションはTwitter Bootstrapを利用したのですが、あまり活用できていません。また、バージョンが上がったのか、デザインやレイアウトルールが以前(1年くらい前)と変わっているようでした。

アセンブラ短歌を詠みつつブログを始めてみた

あけましておめでとうございます。

2014年の幕開けにあわせて、人もすなる日記といふものを始めようと思いたちました。

最初の日記は新年らしく(?)アセンブラ短歌を詠んでみることにしました。

アセンブリ短歌とは、http://kozos.jp/asm-tanka/で紹介されているように、機械語命令がちょうど五・七・五・七・七の並びにおさまるようにしたプログラムのことであります。

さっそく九九の表を出力するアセンブラ短歌を読んでみます。環境はNetBSD-6.1-i386です。
(数値を出力したかったのですが、ASCII文字にマッピングした文字を出力しています...)

コメントの5,7,5...の部分が五・七・五の切れ目になっており、このmain関数はアセンブラ短歌が2首入っています。

.globl  main
main:
        mov     $0x01, %eax     # 5
xloop:  mov     $0x01, %ebx
yloop:  push    %eax
        nop                     # 7
        imul    %ebx
        add     $0x1f, %eax     # 5
        call    my_putchar
        mov     $0x20, %al      # 7
        call    my_putchar
        pop     %eax
        inc     %ebx            # 7
        cmp     $0x0a, %ebx
        jnz     yloop           # 5
ybreak: inc     %eax
        cmp     $0x0a, %al
        jz      xbreak
        push    %eax
        nop                     # 7
        mov     $0xa, %eax      # 5
        call    my_putchar
        pop     %eax
        nop                     # 7
        jmp     xloop
xbreak: nop
        nop
        nop
        nop
        ret                     # 7

.globl  my_putchar
my_putchar:
        sub     $0x10, %esp
        mov     %eax,(%esp)
        mov     %esp,%eax
        movl    $0x1, 0xc(%esp)
        movl    %eax, 0x8(%esp)
        movl    $0x1, 0x4(%esp)
        mov     $0x4, %ax
        int     $0x80
        add     $0x10, %esp
        ret

コンパイルと実行結果は以下のようになります。

$ gcc -Wall -Werror -g kuku.s
$ ./a.out
  ! " # $ % & ' (
! # % ' ) + - / 1
" % ( + . 1 4 7 :
# ' + / 3 7 ; ? C
$ ) . 3 8 = B G L
% + 1 7 = C I O U
& - 4 ; B I P W ^
' / 7 ? G O W _ g
( 1 : C L U ^ g p

1首目の短歌を逆アセンブルして見てみます。五・七・五・七・七のリズムで機械語命令を区切ることができます。

$ objdump -d a.out | grep -A20 '<main>:'
080486a0 <main>:
 80486a0:       b8 01 00 00 00          mov    $0x1,%eax

080486a5 <xloop>:
 80486a5:       bb 01 00 00 00          mov    $0x1,%ebx

080486aa <yloop>:
 80486aa:       50                      push   %eax
 80486ab:       90                      nop
 80486ac:       f7 eb                   imul   %ebx
 80486ae:       83 c0 1f                add    $0x1f,%eax
 80486b1:       e8 28 00 00 00          call   80486de <my_putchar>
 80486b6:       b0 20                   mov    $0x20,%al
 80486b8:       e8 21 00 00 00          call   80486de <my_putchar>
 80486bd:       58                      pop    %eax
 80486be:       43                      inc    %ebx
 80486bf:       83 fb 0a                cmp    $0xa,%ebx
 80486c2:       75 e6                   jne    80486aa <yloop>

080486c4 <ybreak>:
 80486c4:       40                      inc    %eax

アセンブラ短歌の詠み方としては、以下のような流れになります。

  1. アセンブリ言語でプログラムを書く
  2. アセンブルして動かしてみる(この段階では五・七・五は考えない)
  3. objdump -dで逆アセンブルし、五・七・五...になるよう調整する

x86アーキテクチャでは、意外と最初から五・七・五...になっていることも多いです。
機械語命令がうまいこと五・七・五...にならない場合、以下の方法で命令数を調整します。

  • nop(1byte命令)で埋める
  • movで代入するレジスタをeax→al等にして命令数を増減させる
  • 機械語命令の順番を入れ替える(入れ替えても問題がない場合のみ)

これ他にも機械語命令数の調整方法はあるかと思います。筆者は上記の3パターンで何とかアセンブラ短歌を詠めています。

皆様も新年はアセンブラ短歌で(プログラムの)書き初めをしてみてはいかがでしょうか。

【1/4追記】環境の記述が抜けていたので追記しました。