Migwell
Migwell

Reputation: 20147

Various C++ syntax errors resulting from expansion of macro ‘RcppExport’ within R Markdown

I have the following .cpp file, which I want to use within R:

#include <Rcpp.h>
#include <RcppEigen.h>

using Eigen::Map;
using Eigen::EigenBase;
using Eigen::HouseholderQR;
using Eigen::MatrixXd;
using Eigen::SparseMatrix;
using Eigen::SparseQR;
using Eigen::COLAMDOrdering;

// [[Rcpp::depends(RcppEigen)]]

// [[Rcpp::export]]
SEXP qr_dense_residop(Map<MatrixXd> X, Map<MatrixXd> Y){
  const HouseholderQR<MatrixXd> QR(X);
  return Rcpp::wrap(Y - (X * QR.solve(Y)));
}

// [[Rcpp::export]]
SEXP qr_sparse_residop(Map<SparseMatrix<double>> X, Map<SparseMatrix<double>> Y){
  const SparseQR<SparseMatrix<double>, COLAMDOrdering<int>> QR(X);
  return Rcpp::wrap(Y - (X * QR.solve(Y)));
}

If I compile it with Rcpp::sourceCpp(), it compiles correctly. However, I want to include the source code in an Rmarkdown document, and so I instead am including it like this:

```{Rcpp, file="resid.cpp"}
```

Then, when I knit the document, I get the following error:

using C++ compiler: ‘g++ (GCC) 11.3.0’
/stornext/System/data/apps/gcc/gcc-11.3.0/bin/g++ -std=gnu++17 -I"/stornext/System/data/apps/R/R-4.3.2/lib64/R/include" -DNDEBUG   -I"/home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/Rcpp/include" -I"/home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/RcppEigen/include" -I"/vast/scratch/users/milton.m/tmp/RtmpABumCC/sourceCpp-x86_64-pc-linux-gnu-1.0.12" -I/usr/local/include    -fpic  -g -O2  -w -c file153c34131d6db.cpp -o file153c34131d6db.o
In file included from /home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/RcppEigen/include/RcppEigenForward.h:26,
                 from /home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/RcppEigen/include/RcppEigen.h:25,
                 from file153c34131d6db.cpp:1:
file153c34131d6db.cpp: In function ‘SEXPREC* qr_sparse_residop(Eigen::Map<Eigen::SparseMatrix<double, 0, int> >, Eigen::Map<Eigen::SparseMatrix<double, 0, int> >)’:
/home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/Rcpp/include/RcppCommon.h:140:27: error: expected unqualified-id before string constant
  140 | #define RcppExport extern "C" attribute_visible
      |                           ^~~
file153c34131d6db.cpp:33:1: note: in expansion of macro ‘RcppExport’
   33 | RcppExport SEXP sourceCpp_1_qr_dense_residop(SEXP XSEXP, SEXP YSEXP) {
      | ^~~~~~~~~~
/home/users/allstaff/milton.m/R/x86_64-pc-linux-gnu-library/4.3/Rcpp/include/RcppCommon.h:140:27: error: expected unqualified-id before string constant
  140 | #define RcppExport extern "C" attribute_visible
      |                           ^~~
file153c34131d6db.cpp:45:1: note: in expansion of macro ‘RcppExport’
   45 | RcppExport SEXP sourceCpp_1_qr_sparse_residop(SEXP XSEXP, SEXP YSEXP) {
      | ^~~~~~~~~~
file153c34131d6db.cpp:54:2: error: expected ‘}’ at end of input
   54 | }
      |  ^
file153c34131d6db.cpp:20:81: note: to match this ‘{’
   20 | SEXP qr_sparse_residop(Map<SparseMatrix<double>> X, Map<SparseMatrix<double>> Y){
      |                                                                                 ^
make: *** [file153c34131d6db.o] Error 1

What is happening here, and how can I avoid this error?

Upvotes: 1

Views: 43

Answers (1)

Ada Lovelace
Ada Lovelace

Reputation: 1265

You are doing something wrong but it is not clear what. If you look at the existing documentation for knitr and its Rcpp engine, it is clear that having the // [[Rcpp::depends(RcppEigen)]] that is used by sourceCpp() should be enough ... as that is what knitr uses!

Here is a complete Rmd file setting up something simpler: the getEigenValues() from the README of the RcppEigen repo. It works. Maybe you can build up from this.

---
title: "RcppEigen in RMarkdown"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

Standard `getEigenValue` example from README


```{Rcpp, eigenValues}
#include <RcppEigen.h>

// [[Rcpp::depends(RcppEigen)]]

using Eigen::Map;                       // 'maps' rather than copies
using Eigen::MatrixXd;                  // variable size matrix, double precision
using Eigen::VectorXd;                  // variable size vector, double precision
using Eigen::SelfAdjointEigenSolver;    // one of the eigenvalue solvers

// [[Rcpp::export]]
VectorXd getEigenValues(Map<MatrixXd> M) {
    SelfAdjointEigenSolver<MatrixXd> es(M);
    return es.eigenvalues();
}
```

From `?eigen`:


```{r}
M <- cbind(c(1,-1), c(-1,1))
eigen(M)   # base R
getEigenValues(M)
```

It does the trick. (Eigen values are invariant to ordering so c(2,0) is equivalent to c(0,2).)

enter image description here

Upvotes: 2

Related Questions