4

Having a little bit of trouble trying to get some c++ functions to export when I try to load them in from my R package. Running devtools::check() yields

> checking R code for possible problems ... NOTE
  postRiverComp: no visible binding for global variable
    ‘_thmc_postRiverComp’
  preFlopComp: no visible binding for global variable ‘_thmc_preFlopComp’
  preRiverComp: no visible binding for global variable
    ‘_thmc_preRiverComp’
  preTurnComp: no visible binding for global variable ‘_thmc_preTurnComp’
  rcpp_hello_world: no visible binding for global variable
    ‘_thmc_rcpp_hello_world’
  Undefined global functions or variables:
    _thmc_postRiverComp _thmc_preFlopComp _thmc_preRiverComp
    _thmc_preTurnComp _thmc_rcpp_hello_world

I think I've done a pretty good job writing Roxygen comments, so I must've used the wrong function somewhere that uses them. To be clear, I can library(thmc) and no errors are thrown, but no functions are exported. I can see this because when I type search() it yields

 [1] ".GlobalEnv"        "package:thmc"      "devtools_shims"    "tools:rstudio"     "package:stats"    
 [6] "package:graphics"  "package:grDevices" "package:utils"     "package:datasets"  "package:methods"  
[11] "Autoloads"         "org:r-lib"         "package:base" 

Here's my src/do_comps.cpp file:

#include <Rcpp.h>
#include "easy_header.h"

using namespace Rcpp;


//' Calculate pre-flop probability estimates
//' 
//' @param your_cards your cards as a length-4 character vector.
//' @param num_sims number of simulations.
//' @param num_folders number of folders.
//' @param num_oppo number of opponents.
//' @export
// [[Rcpp::export]]
CharacterVector preFlopComp(CharacterVector your_cards, IntegerVector num_sims, IntegerVector num_folders,
                            IntegerVector num_oppo) {

  unsigned int _num_folders = num_folders[0];
  unsigned int _num_sims = num_sims[0];
  unsigned int _num_oppo = num_oppo[0];
  std::string val1 = Rcpp::as<std::string>(your_cards[0]);
  std::string suit1 = Rcpp::as<std::string>(your_cards[1]);
  std::string val2 = Rcpp::as<std::string>(your_cards[2]);
  std::string suit2 = Rcpp::as<std::string>(your_cards[3]);

  double percWon, percTie;

  // construct simulator object and add folders  
  Simulator s(_num_sims, _num_oppo); 
  for(size_t i = 0; i < _num_folders; ++i)
    s.addFolder();

  // add your cards
  s.addYouCard(Card::fromString(val1, suit1));
  s.addYouCard(Card::fromString(val2, suit2));

  // get final numbers
  s.doSim(percWon, percTie);

  return CharacterVector::create(s.prettyResults());
}

Note that it's got the two lines in the documentation file with the word "export." In R/RcppExports.R I have

# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#' Calculate pre-flop probability estimates
#' 
#' @param your_cards your cards as a length-4 character vector.
#' @param num_sims number of simulations.
#' @param num_folders number of folders.
#' @param num_oppo number of opponents.
#' @export
preFlopComp <- function(your_cards, num_sims, num_folders, num_oppo) {
    .Call(`_thmc_preFlopComp`, your_cards, num_sims, num_folders, num_oppo)
}

Maybe it's my NAMESPACE file. I've tried a few things for these. The most recent attempt was using advice I found here and here:

# Generated by roxygen2: do not edit by hand

importFrom(Rcpp, sourceCpp)
useDynLib(thmc, .registration=TRUE)
export(postRiverComp)
export(preFlopComp)
export(preRiverComp)
export(preTurnComp)

Running devtools::check() does change this file, though, by removing the importFrom and useDynLib calls. I have also tried adding the line exportPattern("^[[:alpha:]]+"), as per the suggestion in the official vignette, but it's of no use.

Also, I think I've checked all the boxes given by these answers here, still to no avail.

Taylor
  • 1,797
  • 4
  • 26
  • 51

1 Answers1

7

The importFrom and useDynLib calls in NAMESPACE are important. Either switch to a manually created NAMESPACE file or add

#' @useDynLib thmc, .registration = TRUE
#' @importFrom Rcpp evalCpp

to your roxygen2 code. Here with R-comments, since I would typically use thmc-package.R for this. You can also put this into do_comps.cpp when using C++-comments.

Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75
  • 1
    Not only are they important, they are also _automatically added when you use a package creation helper_ such as `Rcpp.package.skeleton()`. (Which had a recent bug fix for R 4.0.0 but that is another story... Just use Rcpp 1.0.4.12 from the drat repo.) – Dirk Eddelbuettel Jun 12 '20 at 10:56
  • thanks, but unfortunately, no luck. it's probably my fault in that it has something to do with something i didn't mention. – Taylor Jun 12 '20 at 17:23
  • for example, I do have a weird `src/Makevars` file that tries to set `-L` and `-l` flags and link with a separate library: `PKG_LIBS =-L/home/taylor/holdem_monte_carlo/Release/src -lhmc-lib -Wl,-rpath=/home/taylor/holdem_monte_carlo/Release/src ` It's not like I'm getting linker errors though. just silent export failures – Taylor Jun 12 '20 at 17:24
  • @Taylor Interesting. Are these two entries now in `NAMESPACE` consistently? Can you reduce your package to remove this external linkage? – Ralf Stubner Jun 12 '20 at 21:11
  • @RalfStubner sure, [here](https://github.com/tbrown122387/pokeRmc) it is. I gradually added in file by file, and it was working as long as I hit the "source" button at the top right of rstudio to source `src/do_comps.cpp`. But as soon as I do `devtools::install_github("tbrown122387/pokeRmc")` and `library(pokeRmc)`, it's the same problem. The only exported functions are in https://github.com/tbrown122387/pokeRmc/blob/master/src/do_comps.cpp – Taylor Jun 13 '20 at 01:20
  • 2
    @Taylor For me `R CMD build` plus `R CMD check` as well as `devtools::check` produce 2 WARNINGs and 1 NOTE and no error. Installing the package works as well as attaching it afterwards. Note that `Rcpp::sourceCpp`, which is called via the "source" button, is no viable check for a file that is part of a package. – Ralf Stubner Jun 13 '20 at 09:26
  • 4
    In case someone runs into this thread, it is also import to have `//' @export` in the C++ code before `// [[Rcpp::export]]` for the C++ functions to be added to the NAMESPACE by `roxygen2` and be available outside the package (if that is what you want). If you only need to call C++ functions from within your own R functions within the package `// [[Rcpp::export]]` alone is enough. – passerby51 Jan 11 '21 at 03:27
  • This worked for me as long as I imported `sourceCpp` instead of (or in addition to) `evalCpp`. Not sure why, though. – Waldir Leoncio Jul 05 '23 at 09:52