gpt4 book ai didi

c - 如何在 R 中创建用于测试和生产环境的单个共享对象(C 语言)

转载 作者:太空宇宙 更新时间:2023-11-04 04:46:50 25 4
gpt4 key购买 nike

我正在构建一个从 C 构建的共享对象 (.so) 文件,以便从 R 使用。我在链接/编译对象与所有源代码、测试代码和 header 时遇到问题文件。

.so 文件将使用R 中的dyn.load() 加载并调用相应的函数。

将使用这个单个so 文件

  • 通过testthat包在R中测试功能
  • 为包创建一个演示脚本
  • 为典型用户公开包中的所有功能

CMainFile.c 文件有一组全局变量(特定于随机数生成器),CMainFile.c 可以访问这些变量(当主函数被调用时) R 中的用户)和 testfile.c(当 R 中的用户在测试阶段调用测试函数时)。

如何创建允许从 R 调用函数 test_get_and_add(在 testfile 中)和 same_as_test_get_and_add(在 CMainfile 中)的共享对象。

我也不想要两个单独的共享对象(一个用于测试,一个供用户使用)(我已经尝试过并且有效)。

我在这里提供测试文件:

文件1.h

void myaddfunc(double *x, double *y, double *s);

文件2.h

void printadd(double *x, double *y, double *s);

全局变量.h

#include </usr/local/include/gsl/gsl_machine.h>
#include </usr/local/include/gsl/gsl_rng.h>
#include </usr/local/include/gsl/gsl_randist.h>
#include </usr/local/include/gsl/gsl_cdf.h>
extern const gsl_rng *gBaseRand; // global rand number generator
extern unsigned long randSeed;
extern const double lowest_double;
extern const double highest_double;
extern FILE *fp;

CMainFile.h

void set_pseudo_RNG(void);
void get_and_add(double *x, double *s);

文件1.c

#include <stdio.h>    
void myaddfunc(double *x, double *y, double *s){
*s = *x + *y;
}

文件2.c

#include <stdio.h>
#include "globalvars.h"
void printadd(double *x, double *y, double *s){
fprintf(fp, "\n Add %f and %f to get: %f. \n", *x, *y, *s);
}

CMainFile.c

#include <stdio.h>
#include <time.h>
#include </usr/local/include/gsl/gsl_machine.h>
#include </usr/local/include/gsl/gsl_rng.h>
#include </usr/local/include/gsl/gsl_randist.h>
#include </usr/local/include/gsl/gsl_cdf.h>

#include "globalvars.h"
#include "file1.h"
#include "file2.h"

// random number generation set up
const gsl_rng *gBaseRand; // global rand number generator
unsigned long randSeed;
const double lowest_double = -GSL_DBL_MAX;
const double highest_double = GSL_DBL_MAX;
FILE *fp = NULL;

// set the global pseudo random number generator
void set_pseudo_RNG(void){

/* specifying to use Mersenne twister as the uniform PRNG */
gBaseRand = gsl_rng_alloc(gsl_rng_mt19937);
srand(time(NULL)); /* initialization for rand() */
randSeed = rand(); /* returns a non-negative integer */
gsl_rng_set(gBaseRand, randSeed); /* seed the PRNG */
}

void same_as_test_get_and_add(double *x, double *s){
set_pseudo_RNG();
get_and_add(x, s);
}

// takes a numeric input x
// generates random y from normal distribution
// calls a function to add x & y. prints sum.
// RNG has to be set up before calling this function
void get_and_add(double *x, double *s){
double *y;
*y = gsl_ran_ugaussian(gBaseRand);
myaddfunc(x, y, s);
printadd(x, y, s);
}

测试文件.c

#include <stdio.h>

#include "globalvars.h"
#include "CMainFile.h"

void test_get_and_add(double *x, double *s){
set_pseudo_RNG();
get_and_add(x, s);
}

编译:

R CMD SHLIB CMainFile.c testfile.c file1.c file2.c -lgsl -lgslcblas
gcc -std=gnu99 -I/usr/local/R.framework/Resources/include -DNDEBUG -I/sw/include -I/usr/local/include -fPIC -g -O2 -c CMainFile.c -o CMainFile.o
gcc -std=gnu99 -I/usr/local/R.framework/Resources/include -DNDEBUG -I/sw/include -I/usr/local/include -fPIC -g -O2 -c testfile.c -o testfile.o
gcc -std=gnu99 -I/usr/local/R.framework/Resources/include -DNDEBUG -I/sw/include -I/usr/local/include -fPIC -g -O2 -c file1.c -o file1.o
gcc -std=gnu99 -I/usr/local/R.framework/Resources/include -DNDEBUG -I/sw/include -I/usr/local/include -fPIC -g -O2 -c file2.c -o file2.o
gcc -std=gnu99 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/sw/lib -L/usr/local/lib -o CMainFile.so CMainFile.o testfile.o file1.o file2.o -lgsl -lgslcblas -F/usr/local/R.framework/.. -framework R -lintl -Wl,-framework -Wl,CoreFoundation

但不在 R 中运行:

x = vector("numeric", 1)
s = vector("numeric", 1)
dyn.load("CMainFile.so")
.C("test_get_and_add:, as.double(x), as.double(s)

*** caught illegal operation ***
address 0x10484dcd2, cause 'illegal opcode'

Traceback:
1: .C("test_get_and_add", as.double(x), as.double(s))

Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace

same_as_test_get_and_add 也会发生同样的事情。

最佳答案

首先,有很多关于从 R 与 C 交互的信息,您可能会发现它们很有用:

  1. 为什么不做一个包呢?这样人们就可以安装和加载你的包而不是 dyn.load -ing 共享对象。
  2. .Call接口(interface)优先于 .C界面;见Section 5 R-exts 手册。
  3. 如果使用 Rcpp,您的生活会变得更轻松在 C++ 代码中对 R 对象进行操作。

另外,一个吹毛求疵的问题:你应该使用可移植的包含路径; <gsl/*>优于 </usr/local/gsl/*> .

就是说,在编译并尝试在 R -d gdb 中运行您的代码之后, 我明白了

[New Thread 0x170b of process 3829]
[New Thread 0x1803 of process 3829]
[New Thread 0x1903 of process 3829]

R 本身是单线程的,如果错误是由于生成这些线程、尝试修改 R 对象然后破坏所有内容而导致的,我不会感到惊讶。虽然我不确定这些线程究竟在哪里产生,因为我对 GSL 不太熟悉。

所以,

  1. 为什么不直接使用 R 随机数生成器?如果您愿意,可以设置类型:参见 ?RNG .我确信在 C 中也有一些方法可以处理它。
  2. 创建一个包,而不仅仅是构建和分发共享对象。查看package development由 Hadley Wickham 指导。
  3. 查看 RcppGSL .

关于c - 如何在 R 中创建用于测试和生产环境的单个共享对象(C 语言),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19996415/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com