備忘ログ

チラシの裏的備忘録&メモ

CRANからRのバイナリパッケージをdownload.packages()でダウンロードしたいときにうまくいかないときの対応メモ

RでCRANからパッケージをダウンロードする関数としてdownload.packages()がある。

この関数はダウンロードするパッケージの形式(ソースパッケージかバイナリパッケージかは)をtype引数で指定することができる。

環境ごとの設定によるが基本的には指定しないとソースパッケージがダウンロードされる。

download.packages("xfun", ".")
#>      [,1]   [,2]                
#> [1,] "xfun" "./xfun_0.49.tar.gz"

バイナリパッケージをダウンロードしたかったら、type引数に"binary"とするとWindowsで実行していると、Windows用のバイナリパッケージ(.zip)がダウンロードできる。Windows環境でmacOS用のバイナリパッケージ(.tgz)をダウンロードしたかったら"mac.binary.big-sur-arm64"などと指定すると環境によらず指定した環境向けのバイナリパッケージがダウンロードできる。

ドキュメントにはmacOS用のバイナリパッケージをダウンロードするには"mac.binary"でいいと書いているが、現状ではこれではうまくいかない。この点については過去記事の通り。

indenkun.hatenablog.com

……なのだが、ここでtype引数だけを指定してもうまくダウンロードできな事例に時折遭遇する。

例えば、先に上げたxfunパッケージなどはWindows環境(x86_64環境)のRからmacOS用のバイナリパッケージをダウンロードしようとすると次の用にうまくダウンロードできないという事例に遭遇する。

download.packages("xfun", ".", type = "mac.binary.big-sur-arm64")
#> Warning in download.packages("xfun", ".", type = "mac.binary.big-sur-arm64"):
#> no package 'xfun' at the repositories
#>      [,1] [,2]

CRANリポジトリ上に確かにxfunパッケージが存在するし、macOS用バイナリパッケージも存在するのに、なぜ、となってしまう。これはxfunパッケージ以外にも複数のパッケージで同様の事例が発生する。これを解決する方法のメモ。

まずは解決策を示すが、単回でよければ次のようにavailable = available.packages(type = "mac.binary.big-sur-arm64", filters = list())と指定するとダウンロードできる。

download.packages("xfun", ".", available = available.packages(type = "mac.binary.big-sur-arm64", 
    filters = list()), type = "mac.binary.big-sur-arm64")
#>      [,1]   [,2]             
#> [1,] "xfun" "./xfun_0.49.tgz"

ここでの、available.packages()内のtypedownload.packages()関数で指定するtypeでしていするものと同じである必要がある(mac.binary.big-sur-x86_64なら両方そうする)。

これはdonwload.packages()関数がリポジトリのパッケージリストやリポジトリのURLを参照するための関数である、available.packages()関数の挙動に関連するものとなっている。

available.packages()はその関数の名の通り、CRANリポジトリ上にあるすべてのパッケージのリストを返すのではなく利用可能なパッケージのリストを返してくれる。つまり、デフォルトでは利用中の環境(OSやアーキテクチャなど)で利用可能かをフィルターしてリストを返すという挙動をしてくれている。このavailable.packages()関数はinstall.packages()でインストールするためのパッケージをダウンロードするために使われており、インストールする環境で使えないパッケージのリストを返してもらっても普通は困るので都合がいいので既定の挙動はこれでいいのだが、OSやアーキテクチャなどの環境の異なるRのためにパッケージをダウンロードする場合にはこの仕様は都合が悪くなる。

そこでavailable.packages()がリストをフィルターするfilters引数を調整するといいだろうということになる。filters引数の既定値がNULLとなっておりここで、filters引数がNULLの場合には既定値ではc("R_version", "OS_type", "subarch", "duplicates")がフィルターの項目になている。特になにもフィルターしないようにするにはlist()などとする必要がある。重複項目を除く"duplicates"でもいい。多くの場合は悪さをしているのは"OS_type""subarch"なのでここをフィルターから除ければ問題ない。

ということで一旦解決。

複数パッケージをダウンロードする必要があるとき(例えばminiCRANパッケージなど)にはもう少し別のアプローチが有用となる。

特に、miniCRANは現在CRAN上で公開されている0.3.0ではfilters引数を指定することができないので、下記の対応をするほかない。github上で開発中の次期0.3.1ではmakeRepo()関数でfilters引数を指定できるようになるので上記のようにfilters = list()でも対応できるようになると思う。

もう少し詳しくavailable.packages()関数の挙動やドキュメントをみるとfilters引数がNULLのときのフィルターの項目はgetOption("available_packages_filters")で参照され、ここが指定されずNULLである場合にc("R_version", "OS_type", "subarch", "duplicates")がフィルターの項目になっていると分かる(utils:::available_packages_filters_defaultが呼び出されている)。

つまり、options(available_packages_filters = "duplicates")options(available_packages_filters = list()) などと事前に指定するとdownload.packages("xfun", ".", type = "mac.binary.big-sur-arm64")でもダウンロードできるようになる。

options(available_packages_filters = list())
download.packages("xfun", ".", type = "mac.binary.big-sur-arm64")
#>      [,1]   [,2]             
#> [1,] "xfun" "./xfun_0.49.tgz"

そのため、miniCRANパッケージでmakeRepo()addPackage()を実行する前にoptions(available_packages_filters = "duplicates")などと指定してダウンロードできないバイナリパッケージがなくなり解決となる。

miniCRANパッケージをつかってローカルリポジトリを作成するときに少しハマったのでメモしておく。