如何(轻松)将c ++函数包装到易于安装的R'包'

时间:2012-12-26 00:08:33

标签: c++ r eigen

假设我有一个c ++代码(参见下面的一个简单示例)。 我希望日记裁判能够轻松安装/运行 它

所以我认为最简单的方法是将其变形为简化版 R包类似的tar.gz文件,所以裁判可以安装它 只需将install.packages调用到本地.tar.gz文件即可。

原因是我不知道什么机器了  裁判正在使用,但我很确定裁判会这样做 知道如何安装R软件包,因此更容易 我将我的代码变成R'包' - 无论如何, 与它完全相似的东西 通过简单调用install.package()安装。

对早期question的回答似乎暗示了这一点 确实可能。我按照其中的建议和 使用我的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)

e.g。我只是按照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目录。 我添加了一个包含以下内容的NAMESPACE文件:

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();
    }
}

2 个答案:

答案 0 :(得分:4)

您是否阅读了有关如何与R接口的`Writing R Extensions'手册?

当然在没有Rcpp的情况下可以自由地做到这一点,但是我们写了Rcpp供我们使用,因为我们发现它使这些交换变得更容易。使用Rcpp的CRAN上的94个软件包似乎同意......

您正在使用Eigen,并且您希望将其打包为第三方(“裁判”)。现在,如果您使用RcppEigen ,您可以确保Eigen存在,因为它在RcppEigen 中。做你做的,你不是......

另外,.C()是一个限制性更强的界面.Call()

答案 1 :(得分:2)

拥有正确的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

最重要的似乎是'Collat​​e:'字段:它应该正确列出 / R目录中的所有.R文件。取决于&amp; Imports字段也应该与NAMESPACE文件一致。

文件NAMESPACE包含一行

也非常重要
export("fx01","fx02")

其中“fx01”,“fx02”是其中所有R函数的名称 /R/*.R文件(在这种情况下,只是fx01)。

然后,我将整件事包裹在.tar.gz中。然后跑了

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)