RcppArmadillo:使用 autoconf 禁用 OpenMP

RcppArmadillo: Using autoconf to disable OpenMP

在 Dirk 对 的评论中,我被指向 RcppArmadillo 使用的 configure.ac 脚本,以便在构建时以编程方式检查 [=93= 上是否支持 OpenMP ] X. 然后我觉得这对我来说听起来太复杂和不必要了,但我尝试了一些方法来避免 OpenMP 问题,但当我在 Travis 上测试它时它似乎仍然存在。

所以我现在所做的是:

1。 configure.ac

我已经(有点公然,但我当然会尊重 GPL-2 许可证)复制了 RcppArmadillo 使用的 configure.ac 脚本,删除了一些部分(例如 LAPACK 检查)和调整名称等到我的包裹

2。 Makevars

已将 src/Makevars 重命名为 src/Makevars.in,现在显示为

PKG_CXXFLAGS = -I../inst/include @OPENMP_FLAG@
PKG_LIBS= @OPENMP_FLAG@ $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

src/Makevars.win

PKG_CXXFLAGS = -I../inst/include -I. $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

3。清理

添加了一个 cleanup 文件,其中包含

#!/bin/sh
rm -f config.* src/Makevars src/config.h inst/include/pkgConfigGenerated.h

4。 pkgConfigGenerated.h

添加了一个文件 inst/include/pkgConfigGenerated.h.in 如下所示:

#ifndef pkg__pkgConfigGenerated__h
#define pkg__pkgConfigGenerated__h
@HAVE_OPENMP@
#endif

5。 pkgConfig.h

基于 RcppArmadilloConfig.h 文件,我将 inst/include/pkgConfig.h 创建为

#if defined(WIN32) || defined(_WIN32)
   #define ARMA_USE_OPENMP
#else
   #include <pkgConfigGenerated.h>
#endif

我的问题:


可行的解决方案

根据德克的回答,我做了以下操作。我从 RcppArmadillo 借来了 configure.ac 文件,并包含了我需要的部分并做了一些小改动(我把所有的都包含在这里以供将来参考):

## Copyright Dirk Eddelbuettel for RcppArmadillo (GPL-2)
AC_PREREQ(2.61)
AC_INIT([pkg], 0.1.0)

: ${R_HOME=$(R RHOME)}
if test -z "${R_HOME}"; then
    AC_MSG_ERROR([Could not determine R_HOME.])
fi

CXX=$(${R_HOME}/bin/R CMD config CXX)
CXXFLAGS=$("${R_HOME}/bin/R" CMD config CXXFLAGS)

AC_LANG(C++)
AC_REQUIRE_CPP

openmp_flag=""
openmp_cflag=""

AC_MSG_CHECKING([for macOS])
RSysinfoName=$("${R_HOME}/bin/Rscript" --vanilla -e 'cat(Sys.info()[["sysname"]])')
if test x"${RSysinfoName}" == x"Darwin"; then
   AC_MSG_RESULT([found])
   AC_MSG_WARN([OpenMP unavailable and turned off.])
   openmp_flag="-DARMA_DONT_USE_OPENMP"
else
   AC_MSG_RESULT([not found as on ${RSysinfoName}])
   AC_MSG_CHECKING([for OpenMP])
   allldflags=$(${R_HOME}/bin/R CMD config --ldflags)
   hasOpenMP=$(echo ${allldflags} | grep -- -fopenmp)
   if test x"${hasOpenMP}" == x""; then
      AC_MSG_RESULT([missing])
      openmp_flag="-DARMA_DONT_USE_OPENMP"
   else
      AC_MSG_RESULT([found])
      openmp_flag='$(SHLIB_OPENMP_CXXFLAGS)'
      openmp_cflag='$(SHLIB_OPENMP_CFLAGS)'
   fi
fi

AC_SUBST([OPENMP_CFLAG], ["${openmp_cflag}"])
AC_SUBST([OPENMP_FLAG], ["${openmp_flag}"])
AC_CONFIG_FILES([src/Makevars])
AC_OUTPUT

我的主要错误是我以为autoconf是自动调用这个configure.ac文件来获取configure的,其实不是!

对应的Makevars.in

PKG_CXXFLAGS = @OPENMP_FLAG@
PKG_LIBS= @OPENMP_CFLAG@ $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

(也许这两个标志可以简化为一个,但不要修复未损坏的...)

现在我通过了 Linux 和 OS X 的构建(除了 OS X 和 devel 版本的 R,当 RcppArmadillo 失败时安装,但这似乎是一个不同的问题)。

一到四好像还好;我什至认为你不需要两个文件。只需设置 ARMA_USE_OPENMP 其补充 ARMA_DONT_USE_OPENMP

想想看,也可以分别通过 -DARMA_USE_OPENMP-DARMA_DONT_USE_OPENMP 添加到编译标志中。

Five 有点麻烦,因为您似乎不知道如何设置包含标志。更多不依赖额外文件的理由,嗯? ;-)

让我们看看情况如何。我们可以决定帮助提供一个 R 级函数,您可以从脚本 configure 调用(然后可以在 bash 中,或使用 Rscript)。

编辑: 刚刚意识到一个更简单的修复,您 可以 使用:简单地将 C++98 作为编译标准。正如 Writing R Extensions 所说:

Conversely, to ensure that the C++98 standard is assumed even when this is not the compiler default, use

 SystemRequirements: C++98 

or

 CXX_STD = CXX98

这也将关闭 Armadillo 对 OpenMP 的偏好,OpenMP 在 C++11 下始终处于开启状态。

在您链接的 PR 中查看我的评论:

(Being unable to use OpenMP) is only the case for RcppArmadillo. Using OpenMP on macOS with Rcpp is possible via // [[Rcpp::plugins(openmp)]]. Though, you need to be wary of the dragons that exist since R is single threaded.

You can manually regain OpenMP (in RcppArmadillo) by modifying the local install of RcppArmadillo's inline.R to include -fopenmp and removing the #define ARMA_DONT_USE_OPENMP 1 in inst/include/RcppArmadilloConfigGenerated.h

因此,您 运行 对 Travis 构建遇到的问题是 RcppArmadillo(来自 CRAN)的二进制构建在 macOS 构建中永久禁用了 OpenMP。

R 包编写 自己的 配置脚本 不会 覆盖 RcppArmadilloConfigGenerated.h 文件包含在已安装的 RcppArmadillo 包中。该文件随后被 RcppArmadillo.h 调用。唯一可以更改的方法是修改上游 RcppArmadillo,这又依赖于 Base R 提供适当的 OpenMP 检测挂钩。