我想优化构建包的过程。我在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关于检查的章节)。
答案很长
我认为你的问题可能与三个问题有关:
- 软件包安装前后的目录结构之间的差异。(您可能想阅读Hadley的package结构一章的"What is a package?"部分——幸运的是,命令提示符下的
R CMD build
或R中的devtools::build()
会帮您解决这个问题) - 使用
INSTALL
与BUILD
(从注释到本答案的原始版本) - 设置包以调用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代码正确设置包。我采取的步骤是:
- 使用
devtools::create("FortranExample")
创建基本的包结构 - 消除
DESCRIPTION
中的"依赖"行,因为它设置了对R>=3.5.1的依赖,这将引发一个警告(我现在还修改了"许可证"字段,以消除关于未指定正确许可证的警告) - 制作一个
src/
目录,并在那里添加玩具Fortran代码(它只是将一个双值加倍) - 使用
tools::package_native_routine_registration_skeleton("FortranExample")
生成我放置在src/init.c
中的符号注册代码(请参阅写入R扩展,第5.4节) - 创建一个漂亮的R包装器,用于使用
.Fortran()
调用Fortran代码(放在R/example_function.R
中) - 在同一文件中,使用
#' @useDynLib FortranExample
Roxygen标记将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也会专门在那里查找您的依赖项,这样您就不会错过这些依赖项。非常粗糙的解决方案,但对我来说有效。