我有一个R包,它使用 Rcpp 来执行某些内部功能。这些函数不会导出以供用户直接访问(请参阅rcpptest存储库中的最低可重现性示例)。
我现在正在尝试将 Stan 代码添加到安装软件包时要编译的src/
目录中(rcppstan存储库中的可重现示例)。但是,当我修改包以使用Stan时,我在R CMD CHECK中收到以下错误:
#> ❯ checking R code for possible problems ... NOTE
#> meanC: no visible binding for global variable ‘_rcppstan_meanC’
#> Undefined global functions or variables:
#> _rcppstan_meanC
事实上,当我尝试调用使用meanC
函数的R函数时,我收到错误Error in meanC(x) : object '_rcppstan_meanC' not found
。
据我所知,当我修改包以使用 rstan 时,这就是正在发生的变化,因此可能是原因。
仅使用 Rcpp 时,以下内容属于src/RcppExports.cpp
:
static const R_CallMethodDef CallEntries[] = {
{"_rcpptest_timesTwo", (DL_FUNC) &_rcpptest_timesTwo, 1},
{NULL, NULL, 0}
};
RcppExport void R_init_rcpptest(DllInfo *dll) {
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, FALSE);
}
合并 Stan 时,src/RcppExports.cpp
文件中不再生成该代码。相反,它似乎是由 rstantools 包创建的src/init.cpp
文件处理。该文件中的相关块位于:
static const R_CallMethodDef CallEntries[] = {
{NULL, NULL, 0}
};
void attribute_visible R_init_rcppstan(DllInfo *dll) {
// next line is necessary to avoid a NOTE from R CMD check
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
R_useDynamicSymbols(dll, TRUE); // necessary for .onLoad() to work
}
为什么src/init.cpp
中的代码使 Rcpp 函数未定义?相反,有没有办法编辑src/init.cpp
,以便 Stan 模型能够正确编译和访问,同时仍允许定义 Rcpp 函数?
答案 0 :(得分:1)
init.cpp
注册方法,Makevars
禁止编译cpp
文件。通过Makevars
(和Makevars.win
)中的以下更改,我得到了编译:
diff --git a/src/Makevars b/src/Makevars
index 7aedc5b..3ea312e 100644
--- a/src/Makevars
+++ b/src/Makevars
@@ -1,8 +1,9 @@
STANHEADERS_SRC = `"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" --vanilla -e "cat(system.file('include', 'src', package = 'StanHeaders'))"`
PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error
-SOURCES = $(wildcard stan_files/*.stan)
-OBJECTS = $(SOURCES:.stan=.o) init.o
+CPP_SOURCES = $(wildcard *.cpp)
+STAN_SOURCES = $(wildcard stan_files/*.stan)
+OBJECTS = $(STAN_SOURCES:.stan=.o) $(CPP_SOURCES:.cpp=.o)
all: $(SHLIB)
@if test -e "/usr/bin/install_name_tool" && test -e "/usr/local/clang4/lib/libc++.1.dylib" && test -e "/usr/lib/libc++.1.dylib"; then /usr/bin/install_name_tool -change /usr/local/clang4/lib/libc++.1.dylib /usr/lib/libc++.1.dylib $(SHLIB); fi
调用Rcpp::compileAttributes()
后,方法注册再次出现在RcppExports.cpp
中。当我尝试R CMD INSTALL
时,我收到了来自.onLoad()
的错误,c.f。 https://github.com/stan-dev/rstanarm/issues/190。使用那里的解决方法,即R CMD INSTALL --preclean
首先解决了问题,但不可靠。为我解决问题的是改变
R_useDynamicSymbols(dll, FALSE);
到
R_useDynamicSymbols(dll, TRUE);
RcppExports.cpp
中的。这当然是有问题的,因为该文件可能被覆盖,特别是在使用RStudio / devtools时。一个相当hacky的解决方案是添加
RcppExports.o: patch
patch:
sed -i 's/R_useDynamicSymbols(dll, FALSE)/R_useDynamicSymbols(dll, TRUE)/' RcppExports.cpp
.phony: all clean patch
Makevars(.win)
中的。但最终问题似乎是在包安装期间在src
的子目录中生成了Rcpp模块的C ++代码。因此Rcpp::compileAttributes()
不能在已注册方法列表中包含相应的方法。我没有看到一个很好的解决方案。
现在,软件包构建,检查并安装两个NOTE:
N checking installed package size
installed size is 7.8Mb
sub-directories of 1Mb or more:
libs 7.7Mb
N checking for GNU extensions in Makefiles
GNU make is a SystemRequirements.