我从源代码编译了 R,但没有找到证书

I compiled R from source and it doesn't find certificates

我正在多个虚拟桌面上部署多个 R 版本。我从 Ubuntu 18.04.3 LTS 上的源代码构建了 3.6.34.1.2 R。其中 None 在 /etc/R 中找到系统范围的 Rprofile.site 文件或在 /usr/share/ca-certificates 中找到系统证书。但是安装了APT的R(3.4.4)就没有这样的问题。我使用了 Ansible,但为了这个问题,我使用 shell 脚本为一台主机复制了部署。

#!/bin/bash
set -euo pipefail

# install build dependecies
(command -v apt && apt-get build-dep r-base) || (command -v dnf && dnf builddep R)


version='4.1.2'
major_version=$(echo "$version" | cut -c 1)

wget "https://cran.rstudio.com/src/base/R-$major_version/R-$version.tar.gz"
tar -xzf R-$version.tar.gz
cd R-$version

./configure \
        --prefix=/opt/R/$version \
        --sysconfdir=/etc/R \
        --enable-R-shlib \
        --with-pcre1 \
        --with-blas \
        --with-lapack
make -j 8
make install

注意:它应该 运行 在大多数 Linux 带有 APT 或 RPM 包管理器的发行版上。增加make-j参数,如果你有足够的核心,但没有时间。

所以我将安装前缀定义为 /opt/R/$version ,但我希望它从 /etc/R(定义为 --sysconfdir=/etc/R)读取配置文件。但是,当我打开 R 交互式 shell (/opt/R/4.1.2/bin/R) 尝试安装包时:

install.packages("remotes")

然后会提示我选择一个R包镜像,但是已经定义在/etc/R/Rprofile.site:

local({
    r <- getOption("repos")
    r["CRAN"] <- "https://cloud.r-project.org"
    options(repos = r)
})

我可以通过使用 R_PROFILE 环境变量定义它来强制 R shell 找到 Rprofile.site 文件。

export R_PROFILE=/etc/R/Rprofile.site
/opt/R/4.1.2/bin/R

然后在 R shell 中再次调用 install.packages("remotes")。现在不会出现镜像选择提示,而是报如下错误:

Warning: unable to access index for repository https://cloud.r-project.org/src/contrib:
  cannot open URL 'https://cloud.r-project.org/src/contrib/PACKAGES'
Warning message:
package ‘remotes’ is not available for this version of R

A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages

所以它无法访问存储库索引(真正的问题),然后得出结论,“remotes”包不适用于我的 R 版本。这是 BS,因为它一开始无法读取索引。所以我在同一个 R shell.

中尝试了一个简单的 HTTP 调用
curlGetHeaders("https://example.com")

并收到此错误:

Error in curlGetHeaders("https://example.com") : libcurl error code 77:
        unable to access SSL/TLS CA certificates

因此无法在 /usr/share/ca-certificates 中找到 CA 证书。

由于APT安装的R有none个这样的问题。编译后的 R 不会搜索正确的位置。即使我省略 --sysconfdir=/etc/R 构建选项并复制或符号链接前缀下的 /etc/R 目录,它也会位于 /opt/R/4.1.2/etc。它仍然找不到它的配置文件。

更大的问题是我什至不知道如何指定/usr/share所以它可能会找到证书。 rsharedir 构建选项(makefile 中也缺少 --)将不起作用,因为它应该指向 /usr/share/R/ 而不是 /usr/share,无论如何这都是一个不好的做法。

我也用 3.6.3 R 版本尝试了所有这些并得到了相同的结果。

问题:如何使编译后的 R 安装找到系统范围或任何配置文件和证书。

更新 1

我 运行 Ubuntu 服务器上的构建脚本,我不使用相同的 Ansible 代码进行管理。在他们两个上,R 成功地找到了证书。所以问题不在于构建脚本,而在于系统状态。

更新 2

我创建了一个安装包的简单 R 脚本 (install-r-package.R):

install.packages("renv", repos="https://cran.wu.ac.at/")

然后我用 Rscript 执行它并跟踪它们在正确和错误的主机上打开了哪个文件:

 strace -o strace.log -e trace=open,openat,close,read,write,connect,accept ./Rscript install-r-package.R

事实证明,在有问题的系统上,R 甚至没有尝试打开证书文件。

正确系统上的相关跟踪片段:

connect(5, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("137.208.57.37")}, 16) = -1 EINPROGRESS (Operation now in progress)
openat(AT_FDCWD, "/etc/ssl/certs/ca-certificates.crt", O_RDONLY) = 6
read(6, "-----BEGIN CERTIFICATE-----\nMIIH"..., 200704) = 200704
read(6, "--\n", 4096)                   = 3
read(6, "", 4096)                       = 0
close(6)                                = 0

在有问题的系统上:

connect(5, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("137.208.57.37")}, 16) = -1 EINPROGRESS (Operation now in progress)
openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/nss/libsoftokn3.so", O_RDONLY|O_CLOEXEC) = 6
read(6, "7ELF[=20=][=20=][=20=][=20=][=20=][=20=][=20=][=20=][=20=][=20=]>[=20=][=20=][=20=][=20=]0A[=20=][=20=][=20=][=20=][=20=][=20=]"..., 832) = 832
close(6)                                = 0

在这两种情况下,R 都会连接到镜像 (137.208.57.37),然后在正确的系统上读取 ca-certificates.crt 证书文件和许多其他 .crt 文件。然而错误的系统完全跳过了这一步。

终于找到了解决办法:

因为两个系统都有arch和OS。我在它们之间交叉复制了 R 编译安装。在有问题的系统上编译但在正确系统上编译的 R 运行 在调用 install.packages("renv", repos="https://cran.wu.ac.at/")

后发出以下警告
Warning: unable to access index for repository https://cran.wu.ac.at/src/contrib:
  internet routines cannot be loaded
Warning messages:
1: In download.file(url, destfile = f, quiet = TRUE) :
  unable to load shared object '/opt/R/4.1.2/lib/R/modules//internet.so':
  libcurl-nss.so.4: cannot open shared object file: No such file or directory
2: package ‘remotes’ is not available for this version of R

A version of this package for your version of R might be available elsewhere,
see the ideas at
https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages

如果我反其道而行之,安装就会成功。

libcurl-nss.so.4: cannot open shared object file: No such file or directory 行给了我不同的 libcurl4 风格被用作构建依赖项的线索。我检查了系统上安装了哪些开发依赖项,libcurl4-nss-dev 7.58.0-2ubuntu3 安装在有问题的系统上,libcurl4-gnutls-dev 7.58.0-2ubuntu3.16 安装在正确的系统上。

所以我从有问题的系统中清除了 libcurl4-gnutls-dev

apt purge libcurl4-nss-dev -y

并安装了 libcurl4-gnutls-dev:

aptitude install libcurl4-gnutls-dev

我使用了 aptitude,因为我必须降级 libcurl3-gnutls 7.58.0-2ubuntu3.16 (now) -> 7.58.0-2ubuntu3 (bionic),它是 libcurl4-gnutls-dev 的依赖项,然后我 运行 在 R- 4.1.2 源码目录。最后,我重新运行问题中的构建脚本,得到了一个运行良好的 R,它可以读取证书,因此可以使用包镜像访问 HTTPS。