RcppArmadillo:使用autoconf禁用OpenMP

时间:2017-10-13 06:37:09

标签: c++ r rcpp

在Dirk对this question的评论中,我指出了RcppArmadillo使用的configure.ac脚本,以便在编译时以编程方式检查OS X上是否支持OpenMP。然后我想这对我来说听起来过于复杂和不必要,但我尝试了一些事情来避免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

我的问题:

  • 现在我猜我需要添加#include <pkgConfig.h>src中的cpp文件,因为这是我相信RcppArmadillo使用它的方式。它是否正确?当我在Linux上测试它时,它抱怨找不到它:fatal error: pkgConfig.h: No such file or directory。我需要做一些额外的链接吗?
  • 我还需要做其他事吗?

工作解决方案

根据Dirk的回答,我做了以下事情。我从configure.ac借用了RcppArmadillo文件,并将我需要的部分包含在内进行了一些细微的更改(我将其全部包含在此处以供将来参考):

## 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上都传递了构建版本(当devel无法安装时,OS X和RcppArmadillo版本的R除外,但这似乎是一个不同的问题)。

2 个答案:

答案 0 :(得分:2)

一到四个似乎很好;我甚至认为你不需要两个文件。只需设置ARMA_USE_OPENMP 其补充ARMA_DONT_USE_OPENMP即可。

考虑一下,也可以分别通过-DARMA_USE_OPENMP-DARMA_DONT_USE_OPENMP添加到编译标记中。

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

让我们看看这是怎么回事。我们可以决定帮助提供您可以从脚本configure调用的R级函数(可以使用bash,或使用Rscript)。

编辑:刚刚实现了可以使用的更简单的修复:只需将C ++ 98作为编译标准。正如编写R扩展所说:

  

相反,确保即使在何时使用C ++ 98标准   这不是编译器默认值,请使用

 SystemRequirements: C++98 
     

 CXX_STD = CXX98

这也将关闭Armadillo对OpenMP的偏好,它始终在C ++ 11下。

答案 1 :(得分:1)

请参阅您关联的PR中的评论:

  

(无法使用OpenMP)仅适用于 RcppArmadillo 。可以通过// [[Rcpp::plugins(openmp)]]在macOS上使用 Rcpp 使用OpenMP。但是,你需要警惕现存的龙,因为 R 是单线程的。

     

您可以通过修改 RcppArmadillo inline.R的本地安装来手动重新获得OpenMP(在RcppArmadillo中)以包含-fopenmp并删除{{3} } #define ARMA_DONT_USE_OPENMP 1

因此,您在Travis构建中遇到的问题是inst/include/RcppArmadilloConfigGenerated.h(来自CRAN)的二进制构建在macOS构建上永久禁用了OpenMP。

R 编写自己的配置脚本将不会覆盖已安装的{{3}中包含的RcppArmadilloConfigGenerated.h文件包。该文件随后由RcppArmadillo.h调用。唯一可以更改的方法是修改上游RcppArmadillo,而后者依赖于Base R 提供相应的OpenMP检测挂钩。