1

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

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

so将使用此单个文件

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

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.

4

1 回答 1

0

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

  1. 为什么不直接做一个包?这样人们就可以安装和加载你的包,而不是dyn.load-ing 共享对象。
  2. .Call接口优先于接口.C;请参阅R-exts 手册的第 5 节。
  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. 制作一个包,不要只是构建和分发共享对象。请参阅 Hadley Wickham 的包开发指南。
  3. 查看RcppGSL
于 2013-11-15T18:51:36.247 回答