windows 来自 C 的 R——最简单的 Helloworld
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2463437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
R from C -- Simplest Possible Helloworld
提问by jsight
What is the simplest possible C function for starting the R interpreter, passing in a small expression (eg, 2+2), and getting out the result? I'm trying to compile with MingW on Windows.
启动 R 解释器、传入一个小表达式(例如 2+2)并输出结果的最简单的 C 函数是什么?我正在尝试在 Windows 上使用 MingW 进行编译。
采纳答案by Shane
You want to call R from C?
你想从 C 调用 R 吗?
Look at section 8.1 in the Writing R Extensionsmanual. You should also look into the "tests" directory (download the source package extract it and you'll have the tests directory). A similar question was previously asked on R-Help and here was the example:
查看“编写 R 扩展”手册中的第 8.1 节。您还应该查看“tests”目录(下载源包解压缩它,您将拥有测试目录)。之前在 R-Help 上问过类似的问题,这里是示例:
#include <Rinternals.h>
#include <Rembedded.h>
SEXP hello() {
return mkString("Hello, world!\n");
}
int main(int argc, char **argv) {
SEXP x;
Rf_initEmbeddedR(argc, argv);
x = hello();
return x == NULL; /* i.e. 0 on success */
}
The simple example from the R manual is like so:
R 手册中的简单示例如下所示:
#include <Rembedded.h>
int main(int ac, char **av)
{
/* do some setup */
Rf_initEmbeddedR(argc, argv);
/* do some more setup */
/* submit some code to R, which is done interactively via
run_Rmainloop();
A possible substitute for a pseudo-console is
R_ReplDLLinit();
while(R_ReplDLLdo1() > 0) {
add user actions here if desired
}
*/
Rf_endEmbeddedR(0);
/* final tidying up after R is shutdown */
return 0;
}
Incidentally, you might want to consider using Rinsideinstead: Dirk provides a nice "hello world" exampleon the project homepage.
顺便说一句,您可能需要考虑使用Rinside:Dirk在项目主页上提供了一个不错的“hello world”示例。
In you're interested in calling C from R, here's my original answer:
如果您有兴趣从 R 调用 C,这是我的原始答案:
This isn't exactly "hello world", but here are some good resources:
这不完全是“hello world”,但这里有一些很好的资源:
- Jay Emerson recently gave a talk on R package development at the New York useR group, and he provided some very nice examples of using C from within R. Have a look at the paper from this discussion on his website, starting on page 9. All the related source code is here: http://www.stat.yale.edu/~jay/Rmeetup/MyToolkitWithC/.
- The course taught at Harvard by Gopi Goswami in 2005: C-C++-R (in Statistics). This includes extensive examples and source code.
- Jay Emerson 最近在纽约的 userR 组做了一个关于 R 包开发的演讲,他提供了一些在 R 中使用 C 的非常好的例子。在他的网站上看看这个讨论中的论文,从第 9 页开始。所有相关的源代码在这里:http: //www.stat.yale.edu/~jay/Rmeetup/MyToolkitWithC/。
- Gopi Goswami 2005年在哈佛讲授的课程:C-C++-R(统计学)。这包括大量示例和源代码。
回答by Jeff
Here you go. It's the main function, but you should be able to adapt it to a more general purpose function. This example builds an R expression from C calls and also from a C string. You're on your own for the compiling on windows, but I've provided compile steps on linux:
干得好。这是主要功能,但您应该能够将其调整为更通用的功能。此示例从 C 调用和 C 字符串构建 R 表达式。在 windows 上编译是你自己的,但我已经在 linux 上提供了编译步骤:
/* simple.c */
#include <Rinternals.h>
#include <Rembedded.h>
#include <R_ext/Parse.h>
int
main(int argc, char *argv[])
{
char *localArgs[] = {"R", "--no-save","--silent"};
SEXP e, tmp, ret;
ParseStatus status;
int i;
Rf_initEmbeddedR(3, localArgs);
/* EXAMPLE #1 */
/* Create the R expressions "rnorm(10)" with the R API.*/
PROTECT(e = allocVector(LANGSXP, 2));
tmp = findFun(install("rnorm"), R_GlobalEnv);
SETCAR(e, tmp);
SETCADR(e, ScalarInteger(10));
/* Call it, and store the result in ret */
PROTECT(ret = R_tryEval(e, R_GlobalEnv, NULL));
/* Print out ret */
printf("EXAMPLE #1 Output: ");
for (i=0; i<length(ret); i++){
printf("%f ",REAL(ret)[i]);
}
printf("\n");
UNPROTECT(2);
/* EXAMPLE 2*/
/* Parse and eval the R expression "rnorm(10)" from a string */
PROTECT(tmp = mkString("rnorm(10)"));
PROTECT(e = R_ParseVector(tmp, -1, &status, R_NilValue));
PROTECT(ret = R_tryEval(VECTOR_ELT(e,0), R_GlobalEnv, NULL));
/* And print. */
printf("EXAMPLE #2 Output: ");
for (i=0; i<length(ret); i++){
printf("%f ",REAL(ret)[i]);
}
printf("\n");
UNPROTECT(3);
Rf_endEmbeddedR(0);
return(0);
}
Compile steps:
编译步骤:
$ gcc -I/usr/share/R/include/ -c -ggdb simple.c
$ gcc -o simple simple.o -L/usr/lib/R/lib -lR
$ LD_LIBRARY_PATH=/usr/lib/R/lib R_HOME=/usr/lib/R ./simple
EXAMPLE #1 Output: 0.164351 -0.052308 -1.102335 -0.924609 -0.649887 0.605908 0.130604 0.243198 -2.489826 1.353731
EXAMPLE #2 Output: -1.532387 -1.126142 -0.330926 0.672688 -1.150783 -0.848974 1.617413 -0.086969 -1.334659 -0.313699
回答by Simon Urbanek
I don't think any of the above has answered the question - which was to evaluate 2 + 2 ;). To use a string expression would be something like:
我认为以上任何一个都没有回答这个问题——这是为了评估 2 + 2 ;)。使用字符串表达式将类似于:
#include <Rinternals.h>
#include <R_ext/Parse.h>
#include <Rembedded.h>
int main(int argc, char **argv) {
SEXP x;
ParseStatus status;
const char* expr = "2 + 2";
Rf_initEmbeddedR(argc, argv);
x = R_ParseVector(mkString(expr), 1, &status, R_NilValue);
if (TYPEOF(x) == EXPRSXP) { /* parse returns an expr vector, you want the first */
x = eval(VECTOR_ELT(x, 0), R_GlobalEnv);
PrintValue(x);
}
Rf_endEmbeddedR(0);
return 0;
}
This lacks error checking, obviously, but works:
显然,这缺少错误检查,但有效:
Z:\>gcc -o e.exe e.c -IC:/PROGRA~1/R/R-213~1.0/include -LC:/PROGRA~1/R/R-213~1.0/bin/i386 -lR
Z:\>R CMD e.exe
[1] 4
(To get the proper commands for your R use R CMD SHLIB e.c
which gives you the relevant compiler flags)
(为您的 R 使用获得正确的命令,R CMD SHLIB e.c
它为您提供相关的编译器标志)
You can also construct the expression by hand if it's simple enough - e.g., for rnorm(10)
you would use
如果足够简单,您也可以手动构建表达式 - 例如,因为rnorm(10)
您会使用
SEXP rnorm = install("rnorm");
SEXP x = eval(lang2(rnorm, ScalarInteger(10)), R_GlobalEnv);
回答by Dirk Eddelbuettel
I think you can't do much better than the inlinepackage (which supports C, C++ and Fortran):
我认为你不能比内联包(支持 C、C++ 和 Fortran)做得更好:
library(inline)
fun <- cfunction(signature(x="ANY"),
body='printf("Hello, world\n"); return R_NilValue;')
res <- fun(NULL)
which will print 'Hello, World' for you. And you don't even know where / how / when the compiler and linker are invoked. [ The R_NilValue is R's NULL version of a SEXP and the .Call()
signature used here requires that you return a SEXP -- see the 'Writing R Extensions' manual which you can't really avoid here. ]
它将为您打印“你好,世界”。而且您甚至不知道在何处/如何/何时调用编译器和链接器。[ R_NilValue 是 SEXP 的 R NULL 版本,.Call()
此处使用的签名要求您返回 SEXP - 请参阅“编写 R 扩展”手册,在这里您无法真正避免。]
You will then take such code and wrap it in a package. We had great success with using inlinefor the Rcppunit tests (over 200 and counting now) and some of the examples.
然后,您将获取此类代码并将其包装在一个包中。我们在 Rcpp单元测试(超过 200 个并且现在还在增加)和一些示例中使用内联取得了巨大成功 。
Oh, and this inlineexample will work on any OS. Even Windoze provided you have the R package building tool chain installed, in the PATH etc pp.
哦,这个内联示例适用于任何操作系统。甚至 Windoze 也提供您在 PATH 等 pp 中安装了 R 包构建工具链。
Edit:I misread the question. What you want is essentially what the littlerfront-end does (using pure C) and what the RInsideclasses factored-out for C++.
编辑:我误读了这个问题。您想要的本质上是较小的前端所做的(使用纯 C)以及RInside类为 C++ 分解出的内容。
Jeff and I never bothered with porting littlerto Windoze, but RInsidedid work there in most-recent release. So you should be able to poke around the build recipes and create a C-only variant of RInsideso that you can feed expression to an embedded R process. I suspect that you still want something like Rcppfor the clue as it gets tedious otherwise.
杰夫和我从来没有与移植困扰利特勒到Windoze,但RInside在最近期的版本是否在那里工作。因此,您应该能够浏览构建配方并创建RInside的 C-only 变体,以便您可以将表达式提供给嵌入式 R 进程。我怀疑你仍然想要像Rcpp这样的东西作为线索,否则它会变得乏味。
Edit 2:And as Shane mentions, there are indeed a few examples in the R sources in tests/Embedding/ along with a Makefile.win. Maybe that is the simplest start if you're willing to learn about R internals.
编辑 2:正如 Shane 提到的,在测试/嵌入/中的 R 源代码中确实有一些示例以及 Makefile.win。如果您愿意了解 R 的内部结构,这可能是最简单的开始。