3

我有一个将Rcpp用于某些内部功能的 R 包。这些函数不会导出供用户直接访问(请参阅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时发生的变化,因此可能是原因。

  1. 仅使用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);
    }
    
  2. 合并Stan后,文件中不再生成该代码src/RcppExports.cpp。相反,这似乎是由rstantoolssrc/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函数?

4

1 回答 1

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(),参见https://github.com/stan-dev/rstanarm/issues/190。从那里使用解决方法,即R CMD INSTALL --preclean首先解决问题,但不可靠。对我来说解决问题的是改变

R_useDynamicSymbols(dll, FALSE);

进入

R_useDynamicSymbols(dll, TRUE);

RcppExports.cpp. 这当然是有问题的,因为该文件可能会被覆盖,尤其是在使用 RStudio/devtools 时。一个相当老套的解决方案是添加

RcppExports.o: patch

patch:
        sed -i 's/R_useDynamicSymbols(dll, FALSE)/R_useDynamicSymbols(dll, TRUE)/' RcppExports.cpp

.phony: all clean patch

Makevars(.win). 但最终问题似乎是 Rcpp 模块的 C++ 代码是在包安装期间在src. 因此Rcpp::compileAttributes()不能在注册方法列表中包含相应的方法。我没有看到一个好的解决方案。现在包构建、检查和安装有两个注释:

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.
于 2018-06-05T10:43:03.620 回答