包的R检查:优化DLL的构建和检查方式



我想优化构建包的过程。我在pckgname/src中有一些fortran代码(f90):

pckgname/src/FortranFile1.f90   
pckgname/src/FortranFile2.f90   

我在RStudio。当我构建包时,它会创建src-i386和src-x64文件夹,其中会生成.o中的可执行文件

pckgname/src-i386/FortranFile1.o  
pckgname/src-i386/FortranFile2.o   
pckgname/src-x64/FortranFile1.o  
pckgname/src-x64/FortranFile2.o   

然后dll文件从.o文件生成到每个文件夹中:

pckgname/src-i386/dllname.dll
pckgname/src-x64/dllname.dll

此后,如果我想成功检查代码,我需要手动将dll复制粘贴到这两个文件夹中(在问题的前一版本中,我写的是代码而不是dll,这可能会导致误解)

pckgname/inst/libs/x64/dllname.dll
pckgname/libs/X64/dllname.dll  

我的问题是:我必须这样做是正常的吗?还是有一种更短的方法不必手动复制粘贴dllname.dll
到这两个文件夹中?这确实可能是错误的根源。

注意:如果我不将dll复制到上述文件夹中,我会收到以下错误消息(从法语翻译过来):

Error in inDL(x, as.logical(local), as.logical(now), ...) : 
impossible to load shared object 'C:/Users/username/Documents/pckgname/inst/libs/x64/dllname.dll':
LoadLibrary failure:  The specified module can't be found
Error in inDL(x, as.logical(local), as.logical(now), ...) : 
impossible to load shared object 'C:/Users/username/Documents/pckgname/libs/x64/dllname.dll':
LoadLibrary failure:  The specified module can't be found.
[...]
`cleanup` is deprecated 

简短答案

我必须这样做正常吗?

。如果path/to/package是您开发包的目录,并且您已经为包设置了正确调用Fortran子例程的所有内容(请参阅"长答案"),则可以运行

R CMD build path/to/package

在命令提示符下,将为您构建一个tarball,并将所有内容都放在正确的位置(请注意,您需要Rtools)。然后你应该能够运行

R CMD check packagename_versionnumber.tar.gz

从命令提示符检查您的包,没有任何问题(由于.dll文件放错了位置——您可能有其他问题,在这种情况下,我建议您用问题中列出的ERROR、WARNING或NOTE来问一个新问题)。

如果你喜欢只在R上工作,你甚至可以

devtools::check("path/to/package")

而不必运行devtools::build()R CMD build("devtools::check()…[b]在检查包之前解开包"——Hadley关于检查的章节;另见Karl Broman关于检查的章节)。

答案很长

我认为你的问题可能与三个问题有关:

  1. 软件包安装前后的目录结构之间的差异。(您可能想阅读Hadley的package结构一章的"What is a package?"部分——幸运的是,命令提示符下的R CMD build或R中的devtools::build()会帮您解决这个问题)
  2. 使用INSTALLBUILD(从注释到本答案的原始版本)
  3. 设置包以调用Fortran子例程的正确方法

在开发R包的过程中,您可能需要一些建议。一些好的指南包括(按细节递增的顺序):

  • Karl Broman的R包装底漆
  • Hadley-Wickham的R包
  • 书写R扩展手册

特别是,您可能需要了解在R包中编译代码的一些细节。您可能想先阅读Hadley关于编译代码的章节(Broman没有),但之后您确实需要阅读《编写R扩展》手册的大部分内容,特别是第1.1、1.2、1.5.4和1.6节,以及所有第5和第6章。

同时,我在这里设置了一个GitHub存储库,它演示了一个玩具示例R包FortranExample,它展示了如何使用Fortran代码正确设置包。我采取的步骤是:

  1. 使用devtools::create("FortranExample")创建基本的包结构
  2. 消除DESCRIPTION中的"依赖"行,因为它设置了对R>=3.5.1的依赖,这将引发一个警告(我现在还修改了"许可证"字段,以消除关于未指定正确许可证的警告)
  3. 制作一个src/目录,并在那里添加玩具Fortran代码(它只是将一个双值加倍)
  4. 使用tools::package_native_routine_registration_skeleton("FortranExample")生成我放置在src/init.c中的符号注册代码(请参阅写入R扩展,第5.4节)
  5. 创建一个漂亮的R包装器,用于使用.Fortran()调用Fortran代码(放在R/example_function.R中)
  6. 在同一文件中,使用#' @useDynLib FortranExampleRoxygen标记将useDynLib(FortranExample)添加到NAMESPACE文件;如果你不使用Roxygen,你可以手动把它放在那里(参见编写R扩展1.5.4和5.2)

现在我们有了一个正确设置的包来处理Fortran代码。我已经在Windows机器上测试了运行的两种路径(运行Windows 8.1和R 3.5.1)

R CMD build FortranExample
R CMD check FortranExample_0.0.0.9000.tar.gz

从命令提示符,以及运行

devtools::check("FortranExample")

来自R。没有任何错误,唯一的警告是上面提到的"许可证"问题。

在清理了运行devtools::check("FortranExample")的后遗症之后(由于某种原因,cleanup选项现在已被弃用;请参阅下面的R函数,以获得受devtools::clean_dll()启发而处理此问题),我使用了

devtools::install("FortranExample")

成功安装软件包并测试其功能,得到:

FortranExample::example_function(2.0)
# [1] 4

我提到的清理功能是

clean_source_dirs <- function(path) {
paths <- file.path(path, paste0("src", c("", "-i386", "-x64")))
file_pattern <- "\.o|so|dll|a|sl|dyl"
unlink(list.files(path = paths, pattern = file_pattern, full.names = TRUE))
}

不,这是不正常的,有解决这个问题的方法。请使用Makevars.win。问题的原因是.dlls正在环境变量PATH定义的位置和链接过程中定义的相对路径中查找依赖项。在运行命令R CMD INSTALL时进行链接,如Mingw首选项中所述,加上文件Makevars.win中定义的一些自定义参数(取决于Windows平台)。一旦复制了结果库,到dependent.dll所在位置的绑定可能会中断,因此,如果将dll放在通常依赖库所在的位置,例如$(R_HOME)/bin/$(ARCH)/

cp -f <your library relative path>.dll $(R_HOME)/bin/$(ARCH)/<your library>.dll

在检查过程中,R也会专门在那里查找您的依赖项,这样您就不会错过这些依赖项。非常粗糙的解决方案,但对我来说有效。

最新更新