简体   繁体   English

如何从R会话中更改C宏变量(预处理器定义指令)?

[英]How to change a C macro variable (preprocessor define directive) from inside an R session?

Questions 问题

  1. Is it bad practice to compile shared libraries from inside an R session using system() or shell() then dynamically load them? 使用system()shell()从R会话内编译共享库然后动态加载它们是不好的做法吗?
  2. Is there a "better" way (than the code below) to change the value of a macro variable in a C source file based on user input from an R session? 是否有一种“更好”的方式(比下面的代码)根据来自R会话的用户输入更改C源文件中的宏变量的值?

Background 背景

Objective 目的

In an R session, I want to create a function that 在R会话中,我想创建一个函数

  1. changes the value of a macro variable in a template C source file, 更改模板C源文件中的宏变量的值,
  2. gives the edited source file a new name, 为编辑后的源文件指定一个新名称,
  3. compiles a shared library of the new program, and 编译新程序的共享库,和
  4. dynamically loads the new shared library into the current R session 动态地将新共享库加载到当前R会话中

Call the template C source file template.tmp and let it look something like: 调用模板C源文件template.tmp ,让它看起来像:

...
#define VAR
...

(I don't plan on actually compiling template.tmp , hence the .tmp file extension. I merely use it as a template to create other source files where only the #define directive changes.) (我不打算实际编译template.tmp ,因此是.tmp文件扩展名。我只是将它用作模板来创建只有#define指令发生变化的其他源文件。)

Below is the R function, I created to do the steps above. 下面是我创建的R函数,用于执行上述步骤。 For simplicity, I removed lines of code that declare correct path names or add portability to Windows and other Unix-alikes. 为简单起见,我删除了代码行,这些代码声明了正确的路径名,或者为Windows和其他类似的Unix添加了可移植性。

myfunc <- function(val){
  # create commands for system()
  subst_cmd <- paste0("sed 's/define VAR/define VAR ", val, "/' template.tmp > newprog.c")
  shlib_cmd <- paste0("R CMD SHLIB newprog.c")

  # submit commands to system()
  system(subst_cmd)
  system(shlib_cmd)

  # dynamically load shared library
  dyn.load(newprog.so)
}

Thus, myfunc(12345) will create a new C source file with the following lines, and will also compile it to a shared library and dynamically load it into the current R session. 因此, myfunc(12345)将使用以下行创建一个新的C源文件,并将其编译为共享库并将其动态加载到当前的R会话中。

...
#define VAR 12345
...

Motivation 动机

I have a function where speed is very important as the function could be called thousands of times. 我有一个功能,其中速度非常重要,因为该功能可以被调用数千次。 Passing values to the function in my C source file tremendously slows down the speed when compared to using a #define preprocessor directive. 与使用#define预处理程序指令相比,将值传递到C源文件中的函数会极大地降低速度。 My thinking was to some how edit the file within R then compile it and load it into the R session. 我的想法是如何在R中编辑文件然后编译它并将其加载到R会话中。 But I do not know if this is good practice or if there is another way to accomplish the same task. 但我不知道这是不是很好的做法,还是有另一种方法可以完成同样的任务。 One problem I have already encountered occurs when I remote into a computer cluster where the login node has compiling capabilities but the computing nodes do not. 我已遇到的一个问题发生在我远程进入计算机集群时,其中登录节点具有编译功能但计算节点没有。

Disclaimer: I dont have much knowledege about R. I am answering this using my experiance of using C shared library. 免责声明:我没有太多关于R的知识。我正在使用我使用C共享库的经验来回答这个问题。

Is it bad practice to compile shared libraries from inside an R session using system() or shell() then dynamically load them? 使用system()或shell()从R会话内编译共享库然后动态加载它们是不好的做法吗?

Yes it is not a good practise. 是的,这不是一个好习惯。 As you say it may be called 1000s of time changing the file and compiling every time is not a good option. 正如你所说,它可能被称为1000s的时间更改文件和每次编译不是一个好的选择。

Is there a "better" way (than the code below) to change the value of a macro variable in a C source file based on user input from an R session? 是否有一种“更好”的方式(比下面的代码)根据来自R会话的用户输入更改C源文件中的宏变量的值?

If the only requirement is changing the value of a macro then why not convert it to a variable and pass that variable when calling the function in dynamically loaded library? 如果唯一的要求是更改宏的值,那么为什么不将它转换为变量并在动态加载的库中调用函数时传递该变量?

Consider following example:(The code below is for dynamic library) 请考虑以下示例:(以下代码适用于动态库)

foo.h foo.h中

#ifndef foo_h__
#define foo_h__

extern void foo(int var);

#endif  // foo_h__

foo.c foo.c的

#include <stdio.h>
int global_var;

void foo(int var)
{
    global_var= var;
}

Call the above function from R by passing the desired value of var to foo function. 通过将所需的var值传递给foo函数,从R调用上述函数。 (I hope you know how to do this) (我希望你知道怎么做)

I don't plan on actually compiling template.tmp, hence the .tmp file extension. 我不打算实际编译template.tmp,因此是.tmp文件扩展名。 I merely use it as a template to create other source files where only the #define directive changes. 我只是将它用作模板来创建只有#define指令发生变化的其他源文件。

I suggest not to do this. 我建议不要这样做。 Even if you have more then one such macros you can still use above logic to handle it. 即使你有多个这样的宏,你仍然可以使用上面的逻辑来处理它。 My suggestion is to compile the library once and then call initialisation function (foo in above example) passing it the required values. 我的建议是编译一次库,然后调用初始化函数(上例中的foo)传递所需的值。 This will also avoid loading the library multiple times and hence make it efficient. 这也将避免多次加载库,从而使其高效。 This is better then what ur doing currently and easy to maintain and document. 这比你现在做的更好,易于维护和记录。

File operations are inherently slow if you are concerned about speed and efficiency. 如果您关注速度和效率,文件操作本身就很慢。 Your program may some day become large hence compiling it for every function call will further add some delay in execution. 你的程序有一天会变大,因此为每个函数调用编译它会进一步增加执行的延迟。 Its bad idea to compile the library every time. 每次编译库都是个坏主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM