Rcpp包调用GSL库的方法
2022年5月20日
编程
前段时间做 R 包 [**hgwrr**](https://cran.r-project.org/web/packages/hgwrr/index.html) 需要用到 GSL 库,就涉及到如何让R在编译的时候能够链接到GSL的 `libgsl.so` 和 `libgslcblas.so` 两个库。虽然有 **RcppGSL** 包,但是这个包只是提供了R与GSL数据转换的功能,并不能解决链接时的问题。CRAN的编译环境中是包含有GSL库的,所以我们可以通过编译配置文件解决。 # Linux和macOS 在Linux和macOS上,我们需要编写 `configure` 文件来链接GSL。然后将配置的参数传递到 `Makevars.in` 文件来生成 `Makevars` 文件,然后让 R 去编译。 ## configure 我们可以先写 `configure.ac` 文件,放在R包代码根目录中。 ```shell # configure.ac AC_INIT([name], 0.2-2) AC_LANG(C++) AC_REQUIRE_CPP AC_PATH_PROG([GSL_CONFIG], [gsl-config]) if test "${GSL_CONFIG}" != ""; then GSL_CFLAGS=`${GSL_CONFIG} --cflags` GSL_LIBS=`${GSL_CONFIG} --libs` else AC_MSG_ERROR([gsl-config not found, is GSL installed?]) fi AC_SUBST(GSL_CFLAGS) AC_SUBST(GSL_LIBS) AC_CONFIG_FILES([src/Makevars]) AC_OUTPUT ``` 我个人也不是很懂 GNU 的 autoconf 配置,大意就是检测 `gsl-config` 是否存在,存在的话就运行下面两行命令 ```bash gsl-config --cflags gsl-config --libs ``` 并将第一行命令输出结果作为 C++ 编译参数,第二行的结果作为链接的参数。注意这里和 **RcppGSL** 包给出的配置示例不同,该包文档中给出的示例是 ```diff if test "${GSL_CONFIG}" != ""; then GSL_CFLAGS=`${GSL_CONFIG} --cflags` - GSL_LIBS=`${GSL_CONFIG} --libs` + GSL_LIBS=`${GSL_CONFIG} --libs-without-cblas` else AC_MSG_ERROR([gsl-config not found, is GSL installed?]) fi ``` 这样会导致 `libgslcblas.so` 在Fedora系统上链接不到的问题。本人也是在提交的包被打回来之后才意识到这个问题。 然后使用下面的命令生成 `configure` 文件 ```bash autoconf -o configure configure.ac ``` 然后将生成的cache删除即可。 ## Makevars 在目录 `src` 中编写 `Makevars` 文件是R的要求,其实就是一个 Makefile 文件。但是我们在 `configure.ac` 文件中指定了让 `configure` 去配置 `src/Makevars` 文件,所以只需要在 `src` 中写一个“模板”,叫做 `Makevars.in` 。 ```makefile # Makevars.in CXX_STD = CXX11 GSL_LIBS = @GSL_LIBS@ GSL_CFLAGS = @GSL_CFLAGS@ PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) $(GSL_CFLAGS) PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(GSL_LIBS) ``` 这里面变量 `PKG_CXXFLAGS` 是编译标志,`PKG_LIBS` 是链接标志。以 `PKG_CXXFLAGS` 为例,这个变量将 `GSL_CFLAGS` 作为自己的一部分,而 `GSL_CFLAGS` 被设置为了 `@GSL_CFLGAS@` ,这个用一对 `@` 符号包围起来的,就是 configure 要替换下来的字符串。 也就是说,configure 在调用 gsl-config 之后,将后者返回值保存在 `GSL_CFLAGS` 中,然后它根据 `Makevars.in` 去生成 `Makevars` 文件,期间把 `Makevars.in` 文件中的字符串 `@GSL_FLAGS@` 替换成自己的 `GSL_CFLAGS` 的值,这个值就顺势传导到 `Makevars` 中的 `GSL_CFLAGS` 变量,并最终作为编译参数传递给编译器。 # Windows 在 Windows 上就比较简单了。由于 Windows 上不需要运行 configure ,而且也不能运行,我们只需要编写一个 `Makevars.win` 就可以了,而且路径也是固定的,变化没有那么多。 ```makefile # Makevars.win CXX_STD = CXX11 GSL_LIBS = -L$(R_HOME)/lib -lgsl -lgslcblas PKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) $(LIBHGWR_CXXFLAGS) PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) $(GSL_LIBS) ``` 也就是默认 GSL 安装在 R 家目录的 `lib` 目录中,这也是CRAN的配置。包含目录我们默认就是 R 家目录的 `include` 目录,必然已经指定过了,所以指定不指定都无所谓。
感谢您的阅读。本网站 MyZone 对本文保留所有权利。