Search code examples
c++rrcppndebug

Is there any way to make Rcpp stop defining NDEBUG?


Why does assert not work here?

^ Apparently, Rcpp has a habit of defining NDEBUG on its own, even if not defined by myself.

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$ 

The answers to the SO question I linked to explain that (a) It is prohibited to call assert in packages uploaded to CRAN, because (b) C++ code should not halt R code and (c) I should throw exceptions instead, which are caught by Rcpp.

However:

  • I do not wish to upload my code to CRAN; instead, I'm writing the code for my own use;
  • Even if I wished to upload it to CRAN, I could compile it myself without NDEBUG for testing purposes and then define NDEBUG just before uploading to CRAN;
  • Since both R code as well as C++ code is written by myself for the same purpose (and I consider them both to be the same program), I would actually like the whole program to blow if a bug in any part of it is detected; continuing running R code if C++ code is faulty is pointless for me;
  • Since I did not know NDEBUG would be defined, I already have put quite a few asserts in my code and also printing diagnostics via std::cerr is wrapped in #ifndef NDEBUGs; these fail to work obviously;
  • I don't want to unconditionally throw exceptions since some asserts are computation heavy;
  • As of now, my C++ code blows my R code anyway because it crashes, I'm trying to investigate the issue but I can't because my diagnostics don't work.

Is there any way to make Rcpp stop defining NDEBUG? Or am I supposed to simply remove all asserts and anything else that depends on NDEBUG and switch to throwing exceptions and stop complaining?


Solution

  • First off, if you grep for NDEBUG in R's own Makeconf (which we can access via a convenience softlink from /etc/R on Debian and its derivatives due to how I set the .deb package up):

    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:~$ 
    

    you see that it imposed by R rather than Rcpp as per your question. So your assumption was wrong. It is under your local control: just edit R's Makeconf on your machine. You just cannot automate this for hypothetical other users of your code. But per you question, that does not appear to be an immediate concern anyway.

    Second, if you want a particular #define you can just define it:

    Code

    #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()
    */
    

    Output

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

    It is quite common to define other logging macros like DEBUG or FATAL or ... that behave like assert even if R by default (and for understandable reasons as a primarily-interactive tool) turns assert off.

    Third and last, you can follow the approach in this question and temporarily undefine NDEBUG to include cassert and then redefine it. That will give you assert() and terminate your session as I checked. Not my approach to debug with R but hey if you really must...