假设我有一个c++代码(见下面的简单示例)。我想让它很容易为期刊裁判安装/运行它。
所以我想最简单的方法就是把它扭曲成一个简化的类似于R包的tar.gz文件,以便裁判可以安装它只需调用install。打包到本地的。tar.gz文件。
这样做的原因是我不知道是什么机器裁判在吸毒,但我很确定裁判会知道如何安装一个R包,所以它更容易把我的代码扭曲成一个R"包"——或者至少,和它足够相似的东西通过简单调用install.package()安装。
前面一个问题的答案似乎表明了这一点确实是可能的。我遵循了其中的建议用我的CPP代码创建了一个/src目录(如下所示)(见下图)和一辆Makevars。Win文件包含:
## This assume that we can call Rscript to ask Rcpp about its locations
## Use the R_HOME indirection to support installations of multiple R version
#PKG_LIBS = $(shell $(R_HOME)/bin/Rscript.exe -e "Rcpp:::LdFlags()")
PKG_CPPFLAGS = -I../inst/include -I.
PKG_CXXFLAGS = -DEIGEN_DONT_PARALLELIZE $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = $(shell $(R_HOME)/bin/Rscript.exe -e "Rcpp:::LdFlags()") $(SHLIB_OPENMP_CXXFLAGS)
和包含
的Makevars文件## Use the R_HOME indirection to support installations of multiple R version
#PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"`
# This was created by RcppEigen.package.skeleton, but the R script that is
# called creates error message:
# PKG_CPPFLAGS = `$(R_HOME)/bin/Rscript -e "RcppEigen:::RcppEigenCxxFlags()"`
PKG_CPPFLAGS = -I../inst/include
PKG_CXXFLAGS = -DEIGEN_DONT_PARALLELIZE $(SHLIB_OPENMP_CXXFLAGS)
PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` $(SHLIB_OPENMP_CXXFLAGS)
。我只是按照SO帖子中的答案四处寻找这是在其他包中完成的(我还将RcppEigen添加到依赖项列表中,因为这保证了Eigen被安装在目标机器上)。我还创建了一个包含文件MSE的/R目录。R包含:
fx01<-function(x){
x<-as.matrix(x)
Dp<-rep(0,ncol(x))
fit<-.C("mse",as.integer(nrow(x)),as.integer(ncol(x)),as.single(x),as.single(Dp))
as.numeric(fit[[4]])
}
和一个空的/inst/include和一个包含最小(但有效). rd文件的/man目录。我添加了一个命名空间文件,其中包含:
import(Rcpp)
import(RcppEigen)
useDynLib(MySmallExample)
问题是:
- c++函数编译/运行正常。有没有办法把它转换成一个R包,这样第三者可以很容易地安装/运行它。
下面是本例使用的c++代码。
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <functional>
#include <fstream>
#include <iostream>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/LU>
#include <Eigen/SVD>
using namespace std;
using namespace Eigen;
using Eigen::MatrixXf;
using Eigen::VectorXf;
float median(VectorXf& x) {
int n=x.rows();
int half=(n+1)/2;
half--;
float med;
nth_element(x.data(),x.data()+half,x.data()+x.size());
if((n%2)==1){
med=x(half);
} else {
float tmp0=x(half);
float tmp1=x.segment(half+1,half-1).minCoeff();
med=0.5*(tmp0+tmp1);
}
return med;
}
VectorXf fx01(MatrixXf& x){
int p=x.cols();
int n=x.rows();
VectorXf Recept(n);
VectorXf Result(p);
for(int i=0;i<p;i++){
Recept=x.col(i);
Result(i)=median(Recept);
}
return Result;
}
extern "C"{
void mse(int* n,int* p,float* x,float* medsout){
MatrixXf x_cen=Map<MatrixXf>(x,*n,*p);
VectorXf MedsOut=fx01(x_cen);
Map<VectorXf>(medsout,*p)=MedsOut.array();
}
}
你读过关于如何与R交互的"编写R扩展"手册吗?
您当然可以自由地在没有Rcpp的情况下这样做,但是我们编写Rcpp是为了我们使用,因为我们发现它使这些交换更容易。在CRAN上使用Rcpp的94个包似乎同意…
您正在使用Eigen,并且您希望将其打包给第三方("裁判")。现在,如果您要使用RcppEigen,您将确保Eigen存在于RcppEigen中。以你的工作,你不会…
另外,.C()
是一个比.Call()
更严格的接口。
拥有一个合适的DESCRIPTION文件非常重要。我用的是这个:
Package: MySmallExample
Type: Package
Title: MysmallExample
Version: 0.0.0
Date: 2012-12-24
Depends: Rcpp (>= 0.9.10)
Imports: RcppEigen (>= 0.2.0)
Suggests: mvtnorm
LinkingTo: Rcpp, RcppEigen
Description: A small minimal Package.
License: GPL (>= 2)
LazyLoad: yes
Authors@R: person("joe", "programer", email =
"joe.programer@joe_inc.com", role = c("aut", "cre"))
Collate: 'MSE.R'
Packaged: 2012-12-24 12:34:56 UTC; andi
Author: joe programer [aut, cre]
Maintainer: joe programer <joe.programer@joe_inc.com>
Repository: CRAN
Date/Publication: 2012-12-24 12:34:56
最重要的似乎是'Collate:'字段:它应该正确列出/R目录下的所有.R文件。The Depends &;Imports字段也应该与命名空间文件一致。
文件命名空间包含一行
也是非常重要的export("fx01","fx02")
,其中"fx01","fx02"为/R/*。R文件(在本例中为fx01)。
然后,我把整个东西打包成一个。tar.gz文件。和run
install.packages("MySmallExample.tar.gz",repos=NULL,type="source")
> install.packages("/MySmallExample.tar.gz",repos=NULL,type="source")
Installing package(s) into ‘/R/x86_64-pc-linux-gnu-library/2.15’
(as ‘lib’ is unspecified)
* installing *source* package ‘MySmallExample’ ...
** libs
g++ -I/usr/share/R/include -DNDEBUG -I../inst/include -I"/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/include" -I"/R/x86_64-pc-linux-gnu-library/2.15/RcppEigen/include" -DEIGEN_DONT_PARALLELIZE -fopenmp -fpic -O3 -pipe -g -c MSE.cpp -o MSE.o
g++ -shared -o MySmallExample.so MSE.o -L/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/lib -lRcpp -Wl,-rpath,/R/x86_64-pc-linux-gnu-library/2.15/Rcpp/lib -fopenmp -L/usr/lib/R/lib -lR
installing to /R/x86_64-pc-linux-gnu-library/2.15/MySmallExample/libs
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (MySmallExample)