在 Apple 芯片(Big Sur、Monterey、Ventura)上为 Rcpp 和其他工具配置编译器

AFH*_*AFH 20 macos r build r-package apple-silicon

我正在尝试Rcpp在我的 M1 Mac 上使用 R 中需要的软件包,但在购买这台计算机后我一直无法启动并运行它。我将其更新到蒙特利,希望这能解决一些安装问题,但事实并非如此。我尝试从此页面Rcpp运行检查,但出现以下错误:

\n
> Rcpp::sourceCpp("~/github/helloworld.cpp")\n
Run Code Online (Sandbox Code Playgroud)\n
ld: warning: directory not found for option \'-L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0\'\nld: warning: directory not found for option \'-L/opt/R/arm64/gfortran/lib\'\nld: library not found for -lgfortran\nclang: error: linker command failed with exit code 1 (use -v to see invocation)\nmake: *** [sourceCpp_4.so] Error 1\nclang++ -arch arm64 -std=gnu++14 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I../inst/include   -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/Rcpp/include" -I"/Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library/RcppArmadillo/include" -I"/Users/afredston/github" -I/opt/R/arm64/include   -fPIC  -falign-functions=64 -Wall -g -O2  -c helloworld.cpp -o helloworld.o\nclang++ -arch arm64 -std=gnu++14 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/opt/R/arm64/lib -o sourceCpp_4.so helloworld.o -L/Library/Frameworks/R.framework/Resources/lib -lRlapack -L/Library/Frameworks/R.framework/Resources/lib -lRblas -L/opt/R/arm64/gfortran/lib/gcc/aarch64-apple-darwin20.2.0/11.0.0 -L/opt/R/arm64/gfortran/lib -lgfortran -lemutls_w -lm -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation\nError in Rcpp::sourceCpp("~/github/helloworld.cpp") : \n  Error 1 occurred building shared library.\n
Run Code Online (Sandbox Code Playgroud)\n

我知道它无法“找到” gfortran。我为蒙特雷安装了这个版本gfortran。当我which gfortran在终端中输入时,它返回/opt/homebrew/bin/gfortran. (也许这个版本gfortran需要太新的 Xcode 工具\xe2\x80\x94,它显示有关 13.2 的内容,当我运行时,clang --version它显示 13.0\xe2\x80\x94,但我没有看到gfortran蒙特利的另一个版本?)

\n

我还在 R 中附加了/opt/homebrew/bin:内容PATH,所以现在看起来像这样:

\n
> Sys.getenv("PATH")\n
Run Code Online (Sandbox Code Playgroud)\n
[1] "/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin:/Applications/RStudio.app/Contents/MacOS/postback"\n
Run Code Online (Sandbox Code Playgroud)\n

我检查过的其他事情:

\n
    \n
  • Xcode 命令行工具已安装(which clang返回/usr/bin/clang)。
  • \n
  • 文件~/.R/Makevars~/.Renviron存在。
  • \n
\n

这是我的会话信息:

\n
R version 4.1.1 (2021-08-10)\nPlatform: aarch64-apple-darwin20 (64-bit)\nRunning under: macOS Monterey 12.1\n\nMatrix products: default\nLAPACK: /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/lib/libRlapack.dylib\n\nlocale:\n[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8\n\nattached base packages:\n[1] stats     graphics  grDevices utils     datasets  methods   base     \n\nloaded via a namespace (and not attached):\n[1] compiler_4.1.1           tools_4.1.1              RcppArmadillo_0.10.7.5.0\n[4] Rcpp_1.0.7        \n
Run Code Online (Sandbox Code Playgroud)\n

Mik*_*gan 37

背景

目前(2023 年 4 月 14 日),CRAN 使用 Xcode 14.2 命令行工具中的 Apple Clang 以及 GNU Fortran 12 的实验性分支,为 Apple 芯片构建 R 4.3.z 二进制文件。

如果您从 CRAN 获取 R(即此处),那么您需要在构建包含源代码的 C/C++/Fortran 代码的 R 包之前(以及在使用Rcpp等之前)在系统上复制 CRAN 的编译器设置。此要求可确保您的包构建与 R 本身兼容。

更复杂的是 Apple Clang 不支持 OpenMP,因此您需要做更多工作来编译使用多线程的程序。您可以通过使用 LLVM Clang 构建 R 本身、所有 R 包以及所有外部库来规避这个问题, LLVM Clang确实支持 OpenMP,但这种方法很繁重,并且“仅适用于专家”。

还有另一种方法已经过一些人的测试,其中包括 macOS R 的维护者 Simon Urbanek。它是实验性的,而且“仅供专家使用”,但它可以在我的机器上运行,并且比学习自己构建 R 和其他库简单得多。

获取工作工具链的说明

警告:这些产品没有保修,并且随时可能损坏。假设您对 C/C++/Fortran 程序编译、Makefile 语法和 Unix shell 有一定程度的熟悉。鼓励每个人查阅官方文档,这比 SO 上的答案更有可能得到维护。像往常一样,sudo风险由您自己承担。

我将尝试同时解决编译器和 OpenMP 支持问题。我假设你是从零开始的。尽管您可能会发现重新开始很有帮助,但请随意跳过您已经采取的步骤。

我已经在运行 Ventura 的机器上测试了这些指令,但它们也应该适用于 Big Sur 和 Monterey。

  1. 从此处的CRAN 下载 R 4.3.z 二进制文件并安装。请务必选择为 Apple 芯片构建的二进制文件。

  2. 跑步

    $ sudo xcode-select --install
    
    Run Code Online (Sandbox Code Playgroud)

    在终端中安装最新版本的 Apple Xcode 命令行工具(好吧,支持您的 macOS 版本的最新版本),其中包括 Apple Clang。您可以在此处从浏览器获取旧版本。CRAN 使用 Xcode 14.2 为 macOS 11.0 及更高版本构建 R 4.3.z。

  3. 下载此处提供的 GNU Fortran 二进制文件并通过解压到 root 来安装:

    $ curl -LO https://github.com/R-macos/gcc-12-branch/releases/download/12.2-darwin-r0/gfortran-12.2-darwin20-r0-universal.tar.xz
    $ sudo tar xvf gfortran-12.2-darwin20-r0-universal.tar.xz -C /
    $ sudo ln -sfn $(xcrun --show-sdk-path) /opt/gfortran/SDK
    
    Run Code Online (Sandbox Code Playgroud)

    最后一个命令更新安装内部的符号链接,以便它指向命令行工具安装内部的SDK 。

  4. 在此处下载适合您的 Apple Clang 版本的 OpenMP 运行时,并通过解压到 root 来安装。您可以使用 查询您的 Apple Clang 版本clang --version。例如,我的版本是1403.0.22.14.1,所以我这样做了:

    $ curl -LO https://mac.r-project.org/openmp/openmp-15.0.7-darwin20-Release.tar.gz
    $ sudo tar xvf openmp-15.0.7-darwin20-Release.tar.gz -C /
    
    Run Code Online (Sandbox Code Playgroud)

    解压后,您应该在系统上找到以下文件:

    /usr/local/lib/libomp.dylib
    /usr/local/include/ompt.h
    /usr/local/include/omp.h
    /usr/local/include/omp-tools.h
    
    Run Code Online (Sandbox Code Playgroud)
  5. 将以下行添加到$(HOME)/.R/Makevars,并根据需要创建文件。

    CPPFLAGS += -I/usr/local/include -Xclang -fopenmp
    LDFLAGS += -L/usr/local/lib -lomp
    
    Run Code Online (Sandbox Code Playgroud)
  6. 测试您是否能够使用 R 编译支持 OpenMP 的 C 或 C++ 程序,同时链接 GNU Fortran 安装中的相关库(由-l输出中的标志表示R CMD CONFIG FLIBS)。

    最透明的方法是直接使用R CMD SHLIB。在临时目录中,创建一个空源文件omp_test.c并添加以下行:

    #ifdef _OPENMP
    # include <omp.h>
    #endif
    
    #include <Rinternals.h>
    
    SEXP omp_test(void)
    {
    #ifdef _OPENMP
        Rprintf("OpenMP threads available: %d\n", omp_get_max_threads());
    #else
        Rprintf("OpenMP not supported\n");
    #endif
        return R_NilValue;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    编译它:

    $ R CMD SHLIB omp_test.c $(R CMD CONFIG FLIBS)
    
    Run Code Online (Sandbox Code Playgroud)

    然后从 R 调用编译后的 C 函数:

    $ R -e 'dyn.load("omp_test.so"); invisible(.Call("omp_test"))'
    
    Run Code Online (Sandbox Code Playgroud)
    OpenMP threads available: 8
    
    Run Code Online (Sandbox Code Playgroud)

    如果编译器或链接器抛出错误,或者您发现 OpenMP 仍然不受支持,那么我们中的一个人就犯了错误。请报告任何问题。

    请注意,如果您不介意安装它,您可以使用Rcpp实现相同的测试:

    library(Rcpp)
    registerPlugin("flibs", Rcpp.plugin.maker(libs = "$(FLIBS)"))
    sourceCpp(code = '
    #ifdef _OPENMP
    # include <omp.h>
    #endif
    
    #include <Rcpp.h>
    
    // [[Rcpp::plugins(flibs)]]
    // [[Rcpp::export]]
    void omp_test()
    {
    #ifdef _OPENMP
        Rprintf("OpenMP threads available: %d\\n", omp_get_max_threads());
    #else
        Rprintf("OpenMP not supported\\n");
    #endif
        return;
    }
    ')
    omp_test()
    
    Run Code Online (Sandbox Code Playgroud)
    OpenMP threads available: 8
    
    Run Code Online (Sandbox Code Playgroud)

参考

一切都有点分散:

  • 有效!希望这对其他人有用。非常感谢您的耐心和帮助。 (3认同)

AFH*_*AFH 5

~/.R/Makevars我通过按照以下说明添加 gfortran 自制安装的路径解决了此问题: https://pat-s.me/transitioning-from-x86-to-arm64-on-macos-experiences-of-an- r-用户/#gfortran