kopug memo

名古屋で働くとあるWebエンジニアの覚書。

CPANモジュールを共存させる

通常CPANのモジュールをインストールする場合こんな感じですよね。

$ sudo perl -MCPAN -e 'install Module::Recursive::Require'

または、

$ sudo cpan

Terminal does not support AddHistory.
cpan shell -- CPAN exploration and modules installation (v1.7601)
ReadLine support available (try 'install Bundle::CPAN')

cpan > install Moduke::Recursive::Require

これでインストールをしてしまうと下記のフォルダにインストールされます。

/usr/lib/perl5/site_perl/5.8.5/Module/Recursive/Require.pm

そういえばPerlって use HOGE::FOO とか書くと何処のディレクトリを参照するんでしたっけ?
ということで調べてみます。

$ perl -e 'print join("\n",@INC),"\n"'

/usr/lib/perl5/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/5.8.5
/usr/lib/perl5/site_perl/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.4/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.3/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.2/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/site_perl/5.8.5
/usr/lib/perl5/site_perl/5.8.4
/usr/lib/perl5/site_perl/5.8.3
/usr/lib/perl5/site_perl/5.8.2
/usr/lib/perl5/site_perl/5.8.1
/usr/lib/perl5/site_perl/5.8.0
/usr/lib/perl5/site_perl
/usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.4/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.3/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.2/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.1/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
/usr/lib/perl5/vendor_perl/5.8.5
/usr/lib/perl5/vendor_perl/5.8.4
/usr/lib/perl5/vendor_perl/5.8.3
/usr/lib/perl5/vendor_perl/5.8.2
/usr/lib/perl5/vendor_perl/5.8.1
/usr/lib/perl5/vendor_perl/5.8.0
/usr/lib/perl5/vendor_perl
.

こんな感じで @INC の中身を直接見るか、または下記の方法でも調べることができます。

$ perl -V

Summary of my perl5 (revision 5 version 8 subversion 5) configuration:
  Platform:
    osname=linux, osvers=2.6.9-22.0.1.elsmp, archname=i386-linux-thread-multi
    uname='linux build-i386 2.6.9-22.0.1.elsmp #1 smp thu oct 27 13:14:25 cdt 2005 i686 i686 i386 gnulinux '
    config_args='-des -Doptimize=-O2 -g -pipe -m32 -march=i386 -mtune=pentium4 -Dversion=5.8.5 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dinc_version_list=5.8.4 5.8.3 5.8.2 5.8.1 5.8.0'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
    useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=undef uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='-O2 -g -pipe -m32 -march=i386 -mtune=pentium4',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBUGGING -fno-strict-aliasing -pipe -I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='3.4.4 20050721 (Red Hat 3.4.4-2)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lpthread -lc
    perllibs=-lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
    libc=/lib/libc-2.3.4.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.3.4'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.5/i386-linux-thread-multi/CORE'
    cccdlflags='-fPIC', lddlflags='-shared -L/usr/local/lib'


Characteristics of this binary (from libperl):
  Compile-time options: DEBUGGING MULTIPLICITY USE_ITHREADS USE_LARGE_FILES PERL_IMPLICIT_CONTEXT
  Built under linux
  Compiled at Dec 21 2005 06:35:04
  @INC:
    /usr/lib/perl5/5.8.5/i386-linux-thread-multi
    /usr/lib/perl5/5.8.5
    /usr/lib/perl5/site_perl/5.8.5/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.4/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.3/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.2/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.1/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.5
    /usr/lib/perl5/site_perl/5.8.4
    /usr/lib/perl5/site_perl/5.8.3
    /usr/lib/perl5/site_perl/5.8.2
    /usr/lib/perl5/site_perl/5.8.1
    /usr/lib/perl5/site_perl/5.8.0
    /usr/lib/perl5/site_perl
    /usr/lib/perl5/vendor_perl/5.8.5/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.4/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.3/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.2/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.1/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.5
    /usr/lib/perl5/vendor_perl/5.8.4
    /usr/lib/perl5/vendor_perl/5.8.3
    /usr/lib/perl5/vendor_perl/5.8.2
    /usr/lib/perl5/vendor_perl/5.8.1
    /usr/lib/perl5/vendor_perl/5.8.0
    /usr/lib/perl5/vendor_perl
    .

上記で@INCの中身が分かったので、treeコマンドやlsコマンドで眺めてみると恐らく
下記のディレクトリ以外は後からCPANでインストールしたモジュールや、
RPM形式のモジュールをインストールした際に入る場所のように見受けられます。
/usr/lib/perl5/5.8.5/i386-linux-thread-multi
/usr/lib/perl5/5.8.5

今回CPANのモジュールを自分で作ったアプリケーション配下にインストールするので、
上記のディレクトリ以外は@INCから除外してしまえば、
cpan > install HOGE::FOO とかしても、既にインストールされてるよ!とか言われなくなるので、
ちょっと強引ですが、mycpanコマンドを準備しておきます。

cpanコマンドが何処に存在するかを調べます。

$ which cpan

/usr/bin/cpan

自分のHOMEディレクトリ配下にcpanをコピーします。

$ cp /usr/bin/cpan ~/bin

@INCの中身から必要じゃないディレクトリを直接除外します。
# 他に推奨とされるやり方があれば教えてください。m(_ _)m

$ vi ~/bin/cpan

 #!/usr/bin/perl

 # * 以下を追加!
 BEGIN {
     @INC = grep { !/site_perl|vendor_perl/ } @INC;
 };
 # * ここまで

     eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
        if $running_under_some_shell;
 #!/usr/bin/perl
 # $Id: cpan,v 1.3 2002/08/30 08:55:15 k Exp $
 use strict;

 : : : 省略 : : :

これで@INCの中の余計なものは排除できたので、~/bin/cpan を起動してみる。

$ ~/bin/cpan

Terminal does not support AddHistory.

Your configuration suggests "/root/.cpan" as your
CPAN.pm working directory. I could not create this directory due
to this error: mkdir /root/.cpan: 許可がありません at /usr/lib/perl5/5.8.5/CPAN.pm line 553

Please make sure the directory exists and is writable.

1度root権限でcpanを起動しちゃうとこんな感じで /root/.cpan 配下を見にいってしまう。
しかしこれには回避方法があり、下記の手順をとります。

$ mkdir -p ~/.cpan/CPAN
$ vi ~/.cpan/CPAN/MyConfig.pm

$CPAN::Config
    = {
          cpan_home  => undef                       ,
          histfile   => "$ENV{HOME}/.cpan/histfile" ,
      };

1;

そこで再度 ~/bin/cpan を実行すると初期化処理が始まって利用できるのですが、その前にCPANモジュールをインストールする場所を作成しておきます。
今回CPANモジュールは下記のディレクトリに入れることします。

$ mkdir -p /var/www/myapp/lib/CPAN

次の環境変数に上記のディレクトリを登録しておきます。

$ export PERL5LIB=/var/www/myapp/lib/CPAN

じゃこのへんでハリキッテCPANモジュールをひとついれてみましょう。

$ ~/bin/cpan

We have to reconfigure CPAN.pm due to following uninitialized parameters:

cpan_home, keep_source_where, build_dir, build_cache, scan_cache, index_expire, gzip, tar, unzip, make, pager, makepl_arg, make_arg, make_install_arg, urllist, inhibit_startup_message, ftp_proxy, http_proxy, no_proxy, prerequisites_policy, cache_metadata

/home/masa/.cpan/CPAN/MyConfig.pm initialized.

CPAN is the world-wide archive of perl resources. It consists of about
100 sites that all replicate the same contents all around the globe.
Many countries have at least one CPAN site already. The resources
found on CPAN are easily accessible with the CPAN.pm module. If you
want to use CPAN.pm, you have to configure it properly.

If you do not want to enter a dialog now, you can answer 'no' to this
question and I'll try to autoconfigure. (Note: you can revisit this
dialog anytime later by typing 'o conf init' at the cpan prompt.)
 :   :   省略

長々と色々聞かれますが、取り敢えず全部デフォルトのままでOKです。
ただ、ダウンロード先は適当に選択して下さい。

初期化処理が終ると下記のようなプロンプトが表示されます。
o conf と打ってみて下さい。

 cpan > o conf

 CPAN::Config options from /usr/lib/perl5/5.8.5/CPAN/Config.pm:
    commit             Commit changes to disk
    defaults           Reload defaults from disk
    init               Interactive setting of all options

    build_cache        10
    build_dir          /home/kopug/.cpan/build
    cache_metadata     1
    cpan_home          /home/kopug/.cpan
    dontload_hash
    ftp                /usr/kerberos/bin/ftp
    ftp_proxy
    getcwd             cwd
    gpg                /usr/bin/gpg
    gzip               /bin/gzip
    histfile           /home/kopug/.cpan/histfile
    histsize           100
    http_proxy
    inactivity_timeout 0
    index_expire       1
    inhibit_startup_message 0
    keep_source_where  /home/kopug/.cpan/sources
    links
    make               /usr/bin/make
    make_arg
    make_install_arg
    makepl_arg
    ncftp
    ncftpget
    no_proxy
    pager              /usr/bin/less
    prerequisites_policy ask
    scan_cache         atstart
    shell              /bin/bash
    tar                /bin/tar
    term_is_latin      1
    unzip              /usr/bin/unzip
    urllist
        ftp://ftp.dti.ad.jp/pub/lang/CPAN/
    wget               /usr/bin/wget

現在の設定内容がでてくるので、ここの makepl_arg を変更します。

 cpan > o conf makepl_arg "LIB=/var/www/myapp/lib/CPAN PREFIX=/var/www/myapp/lib/CPAN INSTALLMAN1DIR=none INSTALLMAN3DIR=none"

 cpan > o conf commit

これで設定が反映されます。

あとは今までどおり普通にモジュールをインストールしてみてください。
/var/www/myapp/lib/CPAN 配下にモジュールが入るので、アプリケーション毎にCPANモジュールを別に入れることが可能となります。