用Rcpp包装Fortran函数

4
这起初对我来说是一个简单的任务,但我无法使以下内容正常工作。我正在尝试将Fortran子程序包装成Rcpp调用,以便在R中使用该函数。目标是将该函数合并到软件包中,因此仅使用dyn.load()在特定*.so文件上不可行(除非有人能向我展示如何?)。从阅读类似的帖子,我怀疑在makevars文件中指定标志可以解决问题,但提供的信息非常简洁,在此链接中,需要进一步澄清。
我已经尽可能接近文档进行了以下操作:
1. 使用Rcpp.package.skeleton创建软件包结构 2. 将我的Fortran文件(hello.f)放置在src目录中 3. 为Rcpp包装器创建了一个基本的cpp文件(hello.cpp) 4. 创建一个R文件来创建“干净”的函数调用(即避免用户使用.Call,并允许在.Call之前运行其他内部计算)
然而,当我尝试构建我的软件包(使用RStudio)时,我会得到以下错误输出:
==> R CMD INSTALL --no-multiarch --with-keep.source fortran

g++ -shared -o fortran.so RcppExports.o hello.o hello.o rcpp_hello_world.o -lgfortran -lm -lquadmath -L/usr/lib/R/lib -lR
* installing to library ‘/home/.../R/x86_64-pc-linux-gnu-library/3.0’
* installing *source* package ‘fortran’ ...
** libs
hello.o: In function `hello_wrapper':
/home/.../r_code/fortran/src/hello.cpp:16: multiple definition of `hello_wrapper'
hello.o:/home/.../r_code/fortran/src/hello.cpp:16: first defined here
collect2: error: ld returned 1 exit status
make: *** [fortran.so] Error 1
ERROR: compilation failed for package ‘fortran’
* removing ‘/home/.../R/x86_64-pc-linux-gnu-library/3.0/fortran’

Exited with status 1.

我的文件如下所示: hello.f
subroutine hello()
    print *, "hello world"
end subroutine hello

hello.h

extern "C"
{
  void hello();
}

hello.cpp

#include <R.h>
#include <Rinternals.h>
#include <Rdefines.h>

#include "hello.h"

#ifdef __cplusplus
extern "C"
{
  SEXP hello_wrapper();
}
#endif

SEXP
hello_wrapper ()
{
  hello();
}

wrapper.R

hello_r <- function(){
  .Call("hello_wrapper");
}
2个回答

2

我认为问题很简单,当你包含多个具有不同扩展名的相同名称文件时,R会感到不满。尝试将hello.f重命名为hello_fortran.f,然后再进行操作。


是的,我也正要建议那个。除此之外,这应该很简单。 - Dirk Eddelbuettel
hello.f重命名为hello_fortran.f,将hello.cpp重命名为hello_cpp.cpp后,这使我更接近了,但现在出现了另一个错误:dyn.load... unable to load shared object /home/.../fortran.so: undefined symbol: hello - cdeterman
1
@DirkEddelbuettel,我已经了解到Fortran函数在头文件中和cpp文件中调用时需要加下划线。这样做后,软件包构建成功了。我会接受这个答案,因为它解决了我的初始问题,但是也感谢您的帮助,Dirk。 - cdeterman

1
如果你移除

,我认为这可能有效。
#ifdef __cplusplus
extern "C"
{
  SEXP hello_wrapper();
}
#endif

部分。还可以查看Rcpp Attributes文档--您不需要手动编写wrapper.R


谢谢您的回复,但这并没有解决问题。我仍然遇到“多次定义hello_wrapper()”的错误。我也会研究Rcpp属性。 - cdeterman
另外,你知道 .Fortran() 吗?在这里不必涉及 Rcpp。但是,在调用 Fortran 之前,您需要/想要在 C++ 级别上进行一些工作吗? - Dirk Eddelbuettel
我知道 .Fortran() 但是在某些 Fortran 调用之前我想做一些 C++。我已经看到其他包中这样做,现在我正在尝试使用这个简单的程序来复制它,但是遇到了这个错误而无法继续。 - cdeterman
这肯定是可行的,我们应该有一个例子。我暂时想不到一个,但我会再回复你的。 - Dirk Eddelbuettel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接