Подтвердить что ты не робот

Перемещение из sourceCpp в пакет с помощью Rcpp

В настоящее время у меня есть файл .cpp, который я могу скомпилировать с помощью sourceCpp(). Как и ожидалось, создается соответствующая функция R, и код работает так, как ожидалось.

Вот он:

#include <Rcpp.h> 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector exampleOne(NumericVector vectorOne, NumericVector vectorTwo){

    NumericVector outputVector = vectorOne + vectorTwo; 

    return outputVector;
}

Теперь я конвертирую свой проект в пакет с помощью Rcpp. Поэтому я создал скелет с rStudio и начал смотреть, как конвертировать вещи.

В Hadley отличный праймер на Cpp, он говорит в разделе "Использование Rcpp в пакете":

Если ваши пакеты используют атрибут Rcpp:: export, то добавляется еще один шаг в процессе сборки пакета. Функция compileAttributes проверяет исходные файлы в пакете для атрибутов Rcpp:: export и генерирует код, необходимый для экспорта функций в R.

Вы должны повторно запускать compileAttributes всякий раз, когда функции добавляются, удаляются или изменяются подписи. Обратите внимание: если вы создаете свой пакет с помощью RStudio или devtools, то этот шаг выполняется автоматически.

Итак, похоже, что код, скомпилированный с помощью sourceCpp(), должен работать так же, как в пакете.

Я создал соответствующий R файл.

exampleOne <- function(vectorOne, vectorTwo){
    outToR <- .Call("exampleOne", vectorOne, vectorTwo, PACKAGE ="testPackage")
    outToR
}

Затем я (re) построил пакет, и я получаю эту ошибку:

Error in .Call("exampleOne", vectorOne, vectorTwo, PACKAGE = "voteR") : C symbol name "exampleOne" not in DLL for package "testPackage"

Кто-нибудь имеет представление о том, что еще мне нужно делать, когда вы делаете код, который компилируется с помощью sourceCpp(), а затем используете его в пакете?

Я должен отметить, что я прочитал: "Написание пакета, использующего Rcpp" http://cran.rstudio.com/web/packages/Rcpp/vignettes/Rcpp-package.pdf, и понять представленную там базовую структуру. Однако, посмотрев исходный код RcppExamples, кажется, что структура в виньетках не совсем такая же, как в примере пакета. Например, не используются файлы .h. Также ни виньетка, ни исходный код не используют атрибут [[Rcpp:: export]]. Это все затрудняет отслеживание того, где моя ошибка.

4b9b3361

Ответ 1

Вот моя "прогулка" о том, как перейти от использования sourceCpp() к пакету, который использует Rcpp. Если есть ошибка, вы можете отредактировать это или сообщить мне, и я отредактирую его.

[ПРИМЕЧАНИЕ: Я настоятельно рекомендую использовать RStudio для этого процесса.]

Итак, у вас есть свойство sourceCpp(), и теперь вам нужно создать пакет. Это не сложно, но может быть немного сложнее, потому что информация о создании пакетов с Rcpp варьируется от исчерпывающей полной документации, которую вы хотите с любым пакетом R (но это выше вашей головы как новичок), и новичок, чувствительный (которые могут не учитывать детали, которые вам понадобятся).

Здесь я использую oneCpp.cpp и twoCpp.cpp как имена двух файлов .cpp, которые вы будете использовать в своем пакете.

Вот что я предлагаю:

а. Сначала я предполагаю, что у вас есть версия theCppFile.cpp, которая компилируется с помощью sourceCpp() и работает так, как вы ожидаете. Это не обязательно, но если вы новичок в Rcpp OR-пакетах, приятно убедиться, что ваш код работает в этой простой ситуации, прежде чем переходить к более сложному случаю ниже.

В. Теперь создайте свой пакет с помощью Rcpp.package.skeleton() или используйте мастер проекта Project > Create Project > Package w/Rcpp в RStudio (настоятельно рекомендуется). Вы можете найти информацию об использовании Rcpp.package.skeleton() в [hadley/devtools] [1] или [Rcpp Attributes Vignette] [2]. Полная документация для написания пакетов с Rcpp находится в [Написание пакета, который использует Rcpp] [3], однако это предполагает, что вы хорошо знаете свой путь по С++ и не используете новый способ "Атрибуты" для выполнения Rcpp. Это будет неоценимо, хотя если вы перейдете к созданию более сложных пакетов.

Теперь у вас должна быть структура каталогов для вашего пакета, которая выглядит примерно так:

yourPackageName
- DESCRIPTION
- NAMESPACE
- \R\
    - RcppExports.R 
- Read-and-delete-me
- \man\
    - yourPackageName-package.Rd
- \src\
    - Makevars
    - Makevars.win
    - oneCpp.cpp 
    - twoCpp.cpp
    - RcppExports.cpp

Как только все настроено, выполните "Сборка и перезагрузка" при использовании RStudio или compileAttributes(), если вы не находитесь в RStudio.

С. Теперь вы должны увидеть в своем каталоге \R файл с именем RcppExports.R. Откройте его и проверьте. В RcppExports.R вы должны увидеть функции обертки R для всех файлов .cpp, которые у вас есть в каталоге \src. Довольно мило, а?..

D) Попробуйте выполнить функцию R, соответствующую функции, которую вы написали в theCppFile.cpp. Это работает? Если это так, продолжайте.

E) Теперь вы можете просто добавить новые .cpp файлы, такие как otherCpp.cpp, в каталог \src при их создании. Затем вам просто нужно перестроить пакет, и обертки R будут сгенерированы и добавлены к RcppExports.R для вас. В RStudio это просто "Build and Reload" в меню "Построение". Если вы не используете RStudio, вы должны запустить compileAttributes()

Ответ 2

Короче говоря, трюк заключается в вызове compileAttributes() из корня пакета. Так, например, для пакета foo

$ cd /path/to/foo
$ ls
DESCRIPTION  man  NAMESPACE  R  src
$ R
R> compileAttributes()

Эта команда генерирует отсутствующие RcppExports.cpp и RcppExports.R.

Ответ 3

Вам не хватает леса для деревьев.

sourceCpp() - это недавняя функция; это часть того, что мы называем атрибутами Rcpp, у которого есть собственная виньетка (с тем же названием, в пакете, на моем веб-сайте и на CRAN), которую вы можете прочитать. В нем, помимо прочего, подробно описано, как превратить что-то, скомпилированное и запущенное с помощью sourceCpp() в пакет. Это то, что вы хотите.

Случайное переключение между документацией не поможет вам, и в конце подлинной исходной документации авторы пакетов могут быть предпочтительнее. Или для того, чтобы развернуть его: вы используете новую функцию, но старую документацию, которая ее не отражает. Попробуйте написать базовый пакет с Rcpp, то есть приступить к нему с другого конца.

Наконец, есть список рассылки...

Ответ 4

Я изменил policyEconomist и Calimo ответы на коды, которые создают пакет из одного простого файла Rcpp.

package_name = "abc"
fpath_cpp_func = "C:/temp/cppfile.cpp" #a file generates no errors in soruceCpp(fpath_cpp_func)
path_build = "c:/r/rtoolbox"
r_exe = "C:/r/r-3.3.1/bin/r.exe"


#convert one file Rcpp .cpp file to a package
require(Rcpp)

setwd(path_build)

#create package skeleton , new folder
Rcpp.package.skeleton(package_name)

#copy cpp file to src/
file.copy(fpath_cpp_func , file.path(package_name,"src"))

#copy other R codes to R/ (optional)
#file.copy(fpath_R_func,  file.path(package_name,"R"))

#compileAttributes()
compileAttributes(pkgdir = package_name)

#to generate manual, edit .Rd files in man/

#build, create 'abc_1.0.tar.gz'
cmd = paste0( '"' ,r_exe, '"',  " CMD build ", package_name)
shell(cmd)

#check, 
#cmd_check = paste0( '"' ,r_exe, '"',  " CMD check ", package_name)                #to generate manual
cmd_check = paste0( '"' ,r_exe, '"',  " CMD check ", package_name, " --no-manual") #no manual
shell(cmd_check)

#install
install.packages(paste0(package_name, "_1.0.tar.gz"))

#load package
#require(package_name, character.only=TRUE)