【问题标题】:Is there any way to make Rcpp stop defining NDEBUG?有什么方法可以让 Rcpp 停止定义 NDEBUG?
【发布时间】:2019-05-19 16:16:31
【问题描述】:

Why does assert not work here?

^ 显然,Rcpp 有自己定义NDEBUG 的习惯,即使不是我自己定义的。

m@m-X555LJ:~/wtfdir$ cat WTF.r
#!/usr/bin/Rscript

library(Rcpp)

sourceCpp("WTF.cpp")
m@m-X555LJ:~/wtfdir$ cat WTF.cpp
#ifdef NDEBUG
#error WTF I did not define this
#endif
m@m-X555LJ:~/wtfdir$ ./WTF.r
WTF.cpp:2:2: error: #error WTF I did not define this
 #error WTF I did not define this
  ^~~~~
make: *** [WTF.o] Error 1
g++  -I"/usr/share/R/include" -DNDEBUG   -I"/home/m/R/x86_64-pc-linux-gnu-library/3.5/Rcpp/include" -I"/home/m/wtfdir"    -fpic  -g -O2 -fdebug-prefix-map=/build/r-base-3U0YWo/r-base-3.5.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g  -c WTF.cpp -o WTF.o
/usr/lib/R/etc/Makeconf:172: recipe for target 'WTF.o' failed
Error in sourceCpp("WTF.cpp") : Error 1 occurred building shared library.
Execution halted
m@m-X555LJ:~/wtfdir$ 

我链接的 SO 问题的答案解释了 (a) 禁止在上传到 CRAN 的包中调用 assert,因为 (b) C++ 代码不应该停止 R 代码和 (c) 我应该抛出异常而是被 Rcpp 捕获。

但是:

  • 我不想将我的代码上传到 CRAN;相反,我正在编写代码供自己使用;
  • 即使我希望将其上传到 CRAN,我也可以在没有 NDEBUG 的情况下自行编译以进行测试,然后在上传到 CRAN 之前定义 NDEBUG
  • 由于 R 代码和 C++ 代码都是我自己为相同目的编写的(并且我认为它们都是同一个程序),如果它的任何部分出现错误,我实际上希望整个程序崩溃被检测到;如果 C++ 代码出错,继续运行 R 代码对我来说毫无意义;
  • 因为我不知道NDEBUG 会被定义,所以我已经在我的代码中放入了很多asserts,并且通过std::cerr 打印的诊断信息也包含在#ifndef NDEBUGs 中;这些显然不起作用;
  • 我不想无条件抛出异常,因为某些 asserts 计算量很大;
  • 截至目前,我的 C++ 代码仍然损坏了我的 R 代码,因为它崩溃了,我正在尝试调查这个问题,但我不能,因为我的诊断程序不起作用。

有没有办法让 Rcpp 停止定义NDEBUG?还是我应该简单地删除所有 asserts 和任何其他依赖于 NDEBUG 并切换到抛出异常并停止抱怨?

【问题讨论】:

    标签: c++ r rcpp ndebug


    【解决方案1】:

    首先,如果您在 R 自己的 MakeconfgrepNDEBUG 提供 Makeconf(由于我如何设置 .deb 包,我们可以通过 Debian 及其衍生产品上的 /etc/R 的便捷软链接访问) :

    edd@rob:~$ grep NDEBUG /etc/R/Makeconf 
    R_XTRA_CPPFLAGS =  -I"$(R_INCLUDE_DIR)" -DNDEBUG
    ALL_CPPFLAGS =  -I"$(R_INCLUDE_DIR)" -DNDEBUG $(PKG_CPPFLAGS) $(CLINK_CPPFLAGS) $(CPPFLAGS)
    edd@rob:~$ 
    

    你看到它是由 R 而不是 Rcpp 根据你的问题强加的。所以你的假设是错误的。它在你的本地控制之下:只需在你的机器上编辑R的Makeconf。您只是不能为您的代码的假设其他用户自动执行此操作。但根据你的问题,这似乎不是一个直接的问题。

    其次,如果你想要一个特定的#define,你可以定义它:

    代码

    #include <Rcpp.h>
    
    // [[Rcpp::export]]
    void foo() {
    
    #ifdef DEBUG
      Rcpp::Rcout << "foo: Debug mode" << std::endl;
    #endif
    
      Rcpp::Rcout << "foo: Hello, world" << std::endl;
    }
    
    #define DEBUG 1
    
    // [[Rcpp::export]]
    void bar() {
    
    #ifdef DEBUG
      Rcpp::Rcout << "bar: Debug mode" << std::endl;
    #endif
    
      Rcpp::Rcout << "bar: Hello, world" << std::endl;
    }
    
    
    /*** R
    foo()
    bar()
    */
    

    输出

    R> sourceCpp("~/git/stackoverflow/56209693/answer.cpp")
    
    R> foo()
    foo: Hello, world
    
    R> bar()
    bar: Debug mode
    bar: Hello, world
    R> 
    

    定义其他日志宏是很常见的,例如 DEBUGFATAL 或 ... 即使 R 默认情况下(出于可理解的原因,作为主要交互式工具)关闭 assert,其行为也类似于断言.

    第三也是最后,您可以按照this question 中的方法暂时取消定义NDEBUG 以包含cassert,然后重新定义它。 给你assert() 并在我检查时终止你的会话。不是我用 R 进行调试的方法,但如果你真的必须...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      相关资源
      最近更新 更多