D.

複数の Python, Ruby を併用する。

python 3.x 系及び ruby 1.9.x 系を利用したい。
とはいっても、現行のバージョン (python 2.x 系及び ruby 1.8.x 系) も必要である。
そこで、これら両方が共存できる環境を構築した。


Mac OS X の場合は非常に簡単である。
あらかじめ MacPorts で複数入れておいて、port activate/deactivate すれば必要なバージョンに切り替えられる。


UbuntuDebian GNU/Linux では、基本的には以下の手順で良い。

  1. ビルド時の ./configure で --prefix=/opt/hoge のようにディレクトリを指定する。
  2. update-alternatives にビルドしたパスを登録することで /usr/bin の下にシンボリックが作成され、複数のバージョンを切り替えられるようになる。


ただし、自分の場合はどのみちひとつのバージョンしか利用しないと考えて、すでに /usr/local/bin の下に独自にビルドした pythonruby をインストールしていた。

パスを抜粋すると以下の通りである。

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

この場合は上記の手順を踏んでも、/usr/local/bin のほうが優先されてしまうため、少し工夫が必要だ。

そこで以下のように解決した。

  1. /opt/bin, /opt/sbin をパスの先頭に追加し、update-alternatives で作成されるシンボリックリンクはここに作成することにする。
  2. /usr/local/bin の下にある pythonruby も update-alternatives の切り替え対象に加える。

結果として PATH はこのようになる。PATH に手を加えるのは抵抗があるが、/usr/local/bin の下も管理したいのでやむを得ないと考えた。

PATH=/opt/sbin:/opt/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

以下のスクリプトを利用して /opt/bin のシンボリックリンクから /usr/local/bin , /usr/bin , /opt/python/$VERSION/bin にそれぞれ関連付けをする。

python の場合。

remove_alternatives() {
  while [ $# -gt 0 ]
  do
    sudo update-alternatives --remove-all $1
    shift
  done 
}

update_alternatives() {
    sudo update-alternatives \
      --install $1/python                  python                  $2/python$4 $3\
      --slave   $1/python-config           python-config           $2/python-config$4\
      --slave   $1/pydoc                   pydoc                   $2/pydoc$4\
      --slave   $1/idle                    idle                    $2/idle$4\
      --slave   $1/ipython                 ipython                 $2/ipython\
      --slave   $1/easy_install            easy_install            $2/easy_install\
      --slave   $1/py_compilefiles         py_compilefiles         $2/py_compilefiles\
      --slave   $1/pygettext               pygettext               $2/pygettext\
      --slave   $1/pygmentize              pygmentize              $2/pygmentize\
      --slave   $1/pycolor                 pycolor                 $2/pycolor\
      --slave   $1/pycentral               pycentral               $2/pycentral\
      --slave   $1/pysupport-parseversions pysupport-parseversions $2/pysupport-parseversions\
      --slave   $1/pysupport-movemodules   pysupport-movemodules   $2/pysupport-movemodules\
      --slave   $1/2to3                    2to3                    $2/2to3\
      --slave   $1/django-admin.py         django                  $2/django-admin.py
}

make_all_alternatives() {
    TARGET=/opt/bin
    SOURCE=/usr/bin
    PRIORITY=90
    SUFFIX=
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
    SOURCE=/usr/local/bin
    PRIORITY=100
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
    SOURCE=/opt/python/2.6.4/bin
    PRIORITY=120
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
    SOURCE=/opt/python/3.1.1/bin
    PRIORITY=150
    SUFFIX=3
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
}

remove_alternatives python python-config pydoc idle ipython easy_install py_compilefiles \
pygettext pygmentize pycolor pycentral pysupport-parseversions pysupport-movemodules 2to3 django
make_all_alternatives

これで sudo update-alternatives --config python 等のコマンドで、/usr/local/bin を含めた形で複数バージョンを切り替えられる。


ruby の場合。

remove_alternatives() {
  while [ $# -gt 0 ]
  do
    sudo update-alternatives --remove-all $1
    shift
  done 
}

update_alternatives() {
    sudo update-alternatives \
      --install $1/ruby   ruby   $2/ruby$4 $3\
      --slave   $1/gem    gem    $2/gem$4\
      --slave   $1/irb    irb    $2/irb$4\
      --slave   $1/rake   rake   $2/rake$4\
      --slave   $1/rdoc   rdoc   $2/rdoc$4\
      --slave   $1/erb    erb    $2/erb$4\
      --slave   $1/testrb testrb $2/testrb$4
}

make_all_alternatives() {
    TARGET=/opt/bin
    SOURCE=/usr/bin
    PRIORITY=90
    SUFFIX=1.8
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
    SOURCE=/usr/local/bin
    PRIORITY=100
    SUFFIX=
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
    SOURCE=/opt/ruby/1.9.1/bin
    PRIORITY=150
    update_alternatives $TARGET $SOURCE $PRIORITY $SUFFIX
}

remove_alternatives ruby gem irb rake rdoc erb testrb
make_all_alternatives


ビルドするときはこのような感じで、原則として --prefix を必ず指定するようにすると良い。

make_and_install() {
    cd Python-$1
    test -n "$2" || ./configure
    test -n "$2" && ./configure --prefix $2
    make
    sudo make install
    cd ..
}

get_python() {
    mkdir install_python
    cd install_python
    wget http://www.python.org/ftp/python/$1/Python-$1.tar.bz2
    test -f Python-$1.tar.bz2 || exit 1
    tar xjvf Python-$1.tar.bz2
    test "$2" = "sourceonly" || make_and_install $1 $2
    test -d /usr/local/src/python || sudo mkdir -p /usr/local/src/python
    sudo cp $OPTIONS Python-$1 /usr/local/src/python
    cd ..
    rm -rf install_python
}

case $OSTYPE in
  *darwin*)
    OPTIONS=-pR
    ;;
  *)
    OPTIONS=-a
    ;;
esac

test -n "$1" || exit 1
get_python $1 $2

case $OSTYPE in
  *darwin*)
    sudo chown -R root:wheel /usr/local/src/python
    ;;
  *)
    sudo chown -R root:root /usr/local/src/python
    ;;
esac


udzura さんの記事を参考にしました。

Ruby1.8.7、1.9.1、1.9.2preview1を簡単に切り替える@Ubuntu9.10
http://blog.udzura.jp/2009/12/13/switch-your-ruby-on-ubuntu910/