问题描述
我正在创建一个R包"lapacker",以使用R API头文件"R_ext/Lapack.h"为R提供和使用的内部LAPACK库提供C接口(仅具有双精度和双复数).源代码: https://github.com/ypan1988/lapacker/
项目结构:
/lapacker
/inst
/include
/lapacke.h
/someother header files
/R
/zzz.R
/src
/lapacke_dgetrf.c
/lapacke_dgetrf_work.c
/loads of other utility functions provided by LAPACKE
/rcpp_hello.cpp
DESCRIPTION
NAMESPACE
在项目内部,我尝试了rcpp_hello.cpp文件中的测试功能(请注意,此示例来自 https://www.netlib.org/lapack/lapacke.html#_calling_code_dgels_code ):
//'@export
// [[Rcpp::export]]
void example_lapacke_dgels()
{
double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
lapack_int info,m,n,lda,ldb,nrhs;
int i,j;
m = 5;
n = 3;
nrhs = 2;
lda = 3;
ldb = 2;
info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);
for(i=0;i<n;i++)
{
for(j=0;j<nrhs;j++)
{
printf("%lf ",b[i][j]);
}
printf("\n");
}
}
整个程序包可以正确编译而没有任何错误,并且在R中给出正确的答案(可以找到符号LAPACKE_dgels):
> example_lapacke_dgels()
2.000000 1.000000
1.000000 1.000000
1.000000 2.000000
但是,当我创建一个单独的C ++文件时,请说出具有完全相同功能的demo3.cpp
#include <Rcpp.h>
#include <lapacke.h>
// [[Rcpp::depends(lapacker)]]
// [[Rcpp::export]]
void lapacke_dgels_test()
{
double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
lapack_int info,m,n,lda,ldb,nrhs;
int i,j;
m = 5;
n = 3;
nrhs = 2;
lda = 3;
ldb = 2;
info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);
for(i=0;i<n;i++)
{
for(j=0;j<nrhs;j++)
{
printf("%lf ",b[i][j]);
}
printf("\n");
}
}
它不再正确编译(实际上我在macOS和ubuntu下都尝试过,存在相同的链接问题),并给出了链接错误消息(找不到符号LAPACKE_dgels):
> Rcpp::sourceCpp("~/Desktop/demo3.cpp", showOutput = TRUE)
/usr/lib/R/bin/R CMD SHLIB -o 'sourceCpp_6.so' 'demo3.cpp'
g++ -I/usr/share/R/include -DNDEBUG -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/Rcpp/include" -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/lapacker/include" -I"/home/yipan/Desktop" -fpic -g -O2 -fdebug-prefix-map=/build/r-base-AitvI6/r-base-3.4.4=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c demo3.cpp -o demo3.o
g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o sourceCpp_6.so demo3.o -L/usr/lib/R/lib -lR
Error in dyn.load("/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so") :
unable to load shared object '/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so':
/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so: undefined symbol: LAPACKE_dgels
我还检查了/R/x86_64-pc-linux-gnu-library/3.4/lapacker/libs下的lapacker.so,发现:
000000000000c6b0 g DF .text 00000000000001bf Base LAPACKE_dgels
我是否错过了一些东西来使demo3.cpp正确编译?非常感谢您的耐心和时间!
您在这里面临着一个难题.您要解析的LAPACKE_dgels
符号是lapacker.so
的一部分,是在软件包安装期间生成的.问题是R软件包的库不用于链接.取而代之的是,它们在运行时由R动态加载.基本上,我看到了四种可能性:
- 将
lapacke
转换为仅标头的库,然后将其安装在inst/include
(c.f.RcppArmadillo
)中. - 链接到
lapacke
的系统安装(在Linux上很容易...) - 向R注册所有功能,并使用R提供的方法链接到它们(参见 WRE 和
nloptr
). - 编译用于链接的库,并将其与R软件包一起安装.您仍然需要一个插件才能正常工作,因为必须将
-L<path/to/lib> -l<libname> ....
添加到PKG_LIBS
.
我确定CRAN上有使用方法4的示例,但现在还没有想到.但是,作为代码kata",我转换了我最近的测试包以使用此结构,请参见c.f. https://github.com/rstub/levmaR/tree/static .. >
(原始不完整答案.)
在src/Makevars
中,您拥有
PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
通过Rcpp属性编译cpp文件时,需要模拟设置.最好的方法是使用Rcpp插件c.f. RcppArmadillo的解决方案(未经测试的调整!):
inlineCxxPlugin <- function(...) {
plugin <-
Rcpp::Rcpp.plugin.maker(
include.before = "#include <lapacke.h>",
libs = "$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)",
package = "lapacker"
)
settings <- plugin()
settings$env$PKG_CPPFLAGS <- "-I../inst/include"
settings
}
顺便说一句,当RcppArmadillo已经这样做时,为什么要直接与LAPACK交互?
I am creating an R package 'lapacker' to provide the C interface for internal LAPACK library provided and used by R (with double precision and double complex only) using the R API header file "R_ext/Lapack.h". The source code:https://github.com/ypan1988/lapacker/
And the project structure:
/lapacker
/inst
/include
/lapacke.h
/someother header files
/R
/zzz.R
/src
/lapacke_dgetrf.c
/lapacke_dgetrf_work.c
/loads of other utility functions provided by LAPACKE
/rcpp_hello.cpp
DESCRIPTION
NAMESPACE
Inside the project, I tried a test function in rcpp_hello.cpp file (Note this example is coming from https://www.netlib.org/lapack/lapacke.html#_calling_code_dgels_code):
//'@export
// [[Rcpp::export]]
void example_lapacke_dgels()
{
double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
lapack_int info,m,n,lda,ldb,nrhs;
int i,j;
m = 5;
n = 3;
nrhs = 2;
lda = 3;
ldb = 2;
info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);
for(i=0;i<n;i++)
{
for(j=0;j<nrhs;j++)
{
printf("%lf ",b[i][j]);
}
printf("\n");
}
}
The whole package can compile properly with no errors, and in R it gives the right answer(indicating symbol LAPACKE_dgels can be found):
> example_lapacke_dgels()
2.000000 1.000000
1.000000 1.000000
1.000000 2.000000
However, when I create a separate C++ file, say demo3.cpp with exactly the same function,
#include <Rcpp.h>
#include <lapacke.h>
// [[Rcpp::depends(lapacker)]]
// [[Rcpp::export]]
void lapacke_dgels_test()
{
double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
lapack_int info,m,n,lda,ldb,nrhs;
int i,j;
m = 5;
n = 3;
nrhs = 2;
lda = 3;
ldb = 2;
info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);
for(i=0;i<n;i++)
{
for(j=0;j<nrhs;j++)
{
printf("%lf ",b[i][j]);
}
printf("\n");
}
}
it no longer compiles properly (actually I tried under both macOS and ubuntu, same linking problem), and gives linking error messages (Cannot find symbol LAPACKE_dgels):
> Rcpp::sourceCpp("~/Desktop/demo3.cpp", showOutput = TRUE)
/usr/lib/R/bin/R CMD SHLIB -o 'sourceCpp_6.so' 'demo3.cpp'
g++ -I/usr/share/R/include -DNDEBUG -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/Rcpp/include" -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/lapacker/include" -I"/home/yipan/Desktop" -fpic -g -O2 -fdebug-prefix-map=/build/r-base-AitvI6/r-base-3.4.4=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c demo3.cpp -o demo3.o
g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o sourceCpp_6.so demo3.o -L/usr/lib/R/lib -lR
Error in dyn.load("/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so") :
unable to load shared object '/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so':
/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so: undefined symbol: LAPACKE_dgels
I have also checked the lapacker.so under /R/x86_64-pc-linux-gnu-library/3.4/lapacker/libs and found:
000000000000c6b0 g DF .text 00000000000001bf Base LAPACKE_dgels
Do I miss something to get the demo3.cpp compile correctly? Thanks very much for your patience and time!
You are facing a difficult problem here. The Symbol you are trying to resolve LAPACKE_dgels
is part of lapacker.so
, build during package installation. Problem is, that the libraries for R packages are not meant for linking. Instead, they are loaded by R dynamically at run-time. Basically, I see four possibilities:
- Convert
lapacke
into a header only library and install that ininst/include
(c.f.RcppArmadillo
). - Link with a system installation of
lapacke
(easy on Linux ...) - Register all functions with R and use the methods provided by R to link to them (c.f. WRE and
nloptr
). - Compile a library meant for linking and install it with the R package. You will still need a plugin for that to work, since you have to add
-L<path/to/lib> -l<libname> ....
toPKG_LIBS
.
I am sure there are examples on CRAN that use method 4, but none comes to mind right now. However, as a "code kata" I have converted a recent test package of mine to use this structure, c.f. https://github.com/rstub/levmaR/tree/static.
(Original incomplete answer.)
In src/Makevars
you have
PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
You need an analogue setting when compiling a cpp file via Rcpp attributes. The best way achieve this is by using an Rcpp plugin, c.f. RcppArmadillo's solution (adjustments are untested!):
inlineCxxPlugin <- function(...) {
plugin <-
Rcpp::Rcpp.plugin.maker(
include.before = "#include <lapacke.h>",
libs = "$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)",
package = "lapacker"
)
settings <- plugin()
settings$env$PKG_CPPFLAGS <- "-I../inst/include"
settings
}
BTW, why do you want to interface with LAPACK directly, when RcppArmadillo does so already?
这篇关于R包与Rcpp的链接错误:“未定义符号:LAPACKE_dgels"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!