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
我的问题:
- 现在我想我需要添加
#include <pkgConfig.h>
到 src
中的我的 cpp 文件,因为我相信 RcppArmadillo 就是这样使用它的。这个对吗?当我在 Linux 上测试它时,它抱怨找不到它:fatal error: pkgConfig.h: No such file or directory
。我需要做一些额外的链接吗?
- 我还需要做其他事情吗?
可行的解决方案
根据德克的回答,我做了以下操作。我从 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 检测挂钩。
在 Dirk 对 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
我的问题:
- 现在我想我需要添加
#include <pkgConfig.h>
到src
中的我的 cpp 文件,因为我相信 RcppArmadillo 就是这样使用它的。这个对吗?当我在 Linux 上测试它时,它抱怨找不到它:fatal error: pkgConfig.h: No such file or directory
。我需要做一些额外的链接吗? - 我还需要做其他事情吗?
可行的解决方案
根据德克的回答,我做了以下操作。我从 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
ininst/include/RcppArmadilloConfigGenerated.h
因此,您 运行 对 Travis 构建遇到的问题是 RcppArmadillo
(来自 CRAN)的二进制构建在 macOS 构建中永久禁用了 OpenMP。
为 R 包编写 自己的 配置脚本 不会 覆盖 RcppArmadilloConfigGenerated.h
文件包含在已安装的 RcppArmadillo
包中。该文件随后被 RcppArmadillo.h
调用。唯一可以更改的方法是修改上游 RcppArmadillo
,这又依赖于 Base R 提供适当的 OpenMP 检测挂钩。