Вызовите функцию R cpp c ++ из кода R в том же пакете - PullRequest
3 голосов
/ 08 апреля 2020

Я хочу собрать пакет R cpp с кодом C ++ и R. Только с кодом C ++ (удаленный код R) все компилируется и работает хорошо, и после сборки и загрузки экспортируемые функции могут вызываться, как и ожидалось, как

<packageName>::<functionName>()

Однако при включении кода R с вызовом В коде C ++ при создании пакета возникает ошибка: объект не найден:

R CMD build <packageName>
[...]
** R
** byte-compile and prepare package for lazy loading
Error in <functionName>() :
  object '_<packageName>_<functionName>' not found
Error: unable to load R code in package '<packageName>'

Ошибка возникает после успешной компиляции кода C ++.

<functionName>()

отображается как

_<packageName>_<functionName>

в R/RcppExports.R как обычно, но не похоже, что он может быть загружен кодом R во время сборки.

Структура пакета обычна:

<packageName>
├── DESCRIPTION
├── man
│   ├── <functionName>.rd
│   └── <packageName>-package.rd
├── NAMESPACE
├── R
│   ├── <RCodeFileName>.R
│   └── RcppExports.R   
├── README.md
└── src
    ├── <C++CodeFileName>.cpp
    ├── <C++CodeFileName>.o
    ├── <packageName>.so
    ├── RCppExports.cpp
    ├── RCppExports.o
    └── symbols.rds

, где при компиляции пакета создаются файлы .o и .so.

Файл R вызывает функцию из Файл C ++ напрямую:

[other stuff]
[...]
<functionName>()

NAMESPACE Файл также как обычно:

useDynLib(<packageName>, .registration=TRUE)
importFrom(Rcpp, evalCpp)
exportPattern("^[[:alpha:]]+")

Это кажется очень простой и прямой проблемой (вызов кода C ++ из кода R в пакет R cpp). Тем не менее, мне кажется, что я не могу найти никаких указаний на то, как это должно быть сделано.

Редактировать (8 апреля 2020 г.): build против INSTALL

Проблема возникает в каждом случае для

R CMD INSTALL <packageName>_<version>.tar.gz

Если включенный файл справки

man/<packageName>-package.Rd

построен так, что он вызывает installing the package to process help pages, ошибка уже возникнет в

R CMD build <packageName>

, как описано выше.

Редактировать (8 апреля 2020 г.): шаги для воспроизведения с Rcpp.package.skeleton() (в любом случае на Unix -подобных системах)

Rscript -e 'Rcpp::Rcpp.package.skeleton("demo20200408")'
echo 'rcpp_hello_world()' > errorDemo/R/example.R
R CMD INSTALL errorDemo

1 Ответ

4 голосов
/ 08 апреля 2020

Возможно, вы захотите замедлить доу. Сам пакет R cpp поставляется с генератором демонстрационного пакета через функцию Rcpp.package.skeleton(). Запустите его!

Сравнение по частям с тем, что у вас есть.

Второй генератор например встроен в RStudio и доступен в меню Файл -> Новый проект -> Новый каталог -> Пакет с R cpp.

Иначе сложно сказать. Ты сделал что-нибудь прикольное с названием функции? Поскольку они сопоставлены с R и C ++, у вас есть ограничения от обоих. Т.е. вы не можете использовать точку (так как это было бы обозначением метода класса в C ++).

Наконец, даже когда не экспортировано функция C ++ должна быть доступна из Установленный и загруженный пакет через три двоеточия, т.е. mypkg:::myFun().

Наконец, быстрое демо:

Создайте его
edd@rob:/tmp$ Rscript -e 'Rcpp::Rcpp.package.skeleton("demo20200408")'
Creating directories ...
Creating DESCRIPTION ...
Creating NAMESPACE ...
Creating Read-and-delete-me ...
Saving functions and data ...
Making help files ...
Done.
Further steps are described in './demo20200408/Read-and-delete-me'.

Adding Rcpp settings
 >> added Imports: Rcpp
 >> added LinkingTo: Rcpp
 >> added useDynLib directive to NAMESPACE
 >> added importFrom(Rcpp, evalCpp) directive to NAMESPACE
 >> added example src file using Rcpp attributes
 >> added Rd file for rcpp_hello_world
 >> compiled Rcpp attributes 
edd@rob:/tmp$ 
Установите его
edd@rob:/tmp$ R CMD INSTALL demo20200408 
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
ccache g++ -I"/usr/share/R/include" -DNDEBUG  -I"/usr/local/lib/R/site-library/Rcpp/include"   -fpic  -g -O3 -Wall -pipe -pedantic  -c RcppExports.cpp -o RcppExports.o
ccache g++ -I"/usr/share/R/include" -DNDEBUG  -I"/usr/local/lib/R/site-library/Rcpp/include"   -fpic  -g -O3 -Wall -pipe -pedantic  -c rcpp_hello_world.cpp -o rcpp_hello_world.o
ccache g++ -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o demo20200408.so RcppExports.o rcpp_hello_world.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$ 
Запустите его
edd@rob:/tmp$ Rscript -e 'library(demo20200408); rcpp_hello_world()'
[[1]]
[1] "foo" "bar"

[[2]]
[1] 0 1

edd@rob:/tmp$ 
И добавьте функцию R и вызовите ее тоже
edd@rob:/tmp$ echo 'r_hello_world <- function() cat("hi there\n")' > demo20200408/R/foo.R
edd@rob:/tmp$ R CMD INSTALL demo20200408 
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
make: Nothing to be done for 'all'.
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$ Rscript -e 'library(demo20200408); r_hello_world()'
hi there
edd@rob:/tmp$ 
Все еще не проблема, несмотря на утверждения ОП

В последнем комментарии ниже утверждается, что сгенерированная функция не может быть вызвана. Это неверно.

edd@rob:/tmp$ editor demo20200408/R/foo.R    # subst. fave editor here
edd@rob:/tmp$ cat demo20200408/R/foo.R 
r_hello_world <- function() {
        cat("hi there\n")
        ignored <- rcpp_hello_world()
        NULL
}
edd@rob:/tmp$ R CMD INSTALL demo20200408 
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
make: Nothing to be done for 'all'.
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$ Rscript -e 'library(demo20200408); r_hello_world()'
hi there
NULL
edd@rob:/tmp$ 
...