"not resolved from current namespace" 错误,从 R 调用 C 例程时
"not resolved from current namespace" error, when calling C routines from R
我最近正在使用 mgcv
GAM 进行一些计算测试。修改了一些原有的功能,增加了一些功能。为了不破坏兼容性,对于我要修改的每个函数,我都创建了一个新版本,函数名称中带有 .zheyuan
后缀。例如,使用 Sl.fit
函数进行惩罚最小二乘拟合,我将得到一个 Sl.fit.zheyuan
。我会简单地将我编写的所有 R 函数收集到一个独立的 R 脚本中 "zheyuan.R"。通过将此文件添加到 mgcv_1.8-17
package source 的 R
目录中,并将修改后的包编译到本地路径中,我可以加载它进行测试。
我加R例程没问题,加C例程就不行。安装修改后的包时没有发生错误,但是当我调用我添加的 C 例程的 R 包装器函数时,我会收到问题标题中的错误。如果您对我的案例感兴趣,您可以按照以下步骤重现此类错误。
第一步:下载最新包源
从上面link下载1.8-17版本。当在 CRAN 上发布新的 mgcv
版本时,这样的 link 将会消失。但您可以随时前往 mgcv
CRAN page 下载最新版本。
让我们untar
来源。首先,删除文件MD5
,这样我们在编译修改后的版本时就不会收到烦人的MD5警告了。下面,我们将在 R
目录和 src
目录中添加新内容。
第 2 步:创建 R 脚本
考虑以下 R 包装函数:
RX <- function (R, X) {
X <- X + 0
.Call("C_mgcv_RX", R, X)
X
}
创建一个 R 脚本 "zheyuan.R" 来放置此函数,并将其添加到 mgcv/R
。
步骤 3:添加 C 例程
关于矩阵计算的 C 例程通常在 src/mat.c
下。所以让我们在这个脚本的末尾追加一个新函数:
void mgcv_RX (SEXP R, SEXP X) {
int nrowX = nrows(X);
int ncolX = ncols(X);
double one = 1.0;
F77_CALL(dtrmm)("l", "u", "n", "n", &nrowX, &ncolX, &one, REAL(R), &nrowX, REAL(X), &nrowX);
}
这是一个简单的例程,将上三角矩阵 R
与矩形矩阵 X
相乘。输出矩阵将覆盖 X
。为此将调用 Level-3 BLAS dtrmm
。我们不需要担心 header 文件或 运行 时间 linking 到 BLAS 库。 Headers 在 mat.c
中可用,link 到 BLAS 由 R 管理。
第四步:注册C例程
以上内容还不够。 mgcv
中的每个 C 例程将出现在三个地方。例如,让我们尝试搜索本机 C 例程:
grep mgcv_RPPt mgcv/src/*
# mgcv/src/init.c: {"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
# mgcv/src/mat.c:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT) {
# mgcv/src/mgcv.h:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT);
我们还需要附加一个header文件mgcv.h
,并在init.c
.
中注册这个C例程
让我们追加
void mgcv_RX (SEXP R, SEXP X);
到 mgcv.h
的末尾,在 init.c
内,执行:
R_CallMethodDef CallMethods[] = {
{"mgcv_pmmult2", (DL_FUNC) &mgcv_pmmult2,5},
{"mgcv_Rpiqr", (DL_FUNC) &mgcv_Rpiqr,5},
{"mgcv_tmm",(DL_FUNC)&mgcv_tmm,5},
{"mgcv_Rpbsi",(DL_FUNC)&mgcv_Rpbsi,2},
{"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
{"mgcv_Rpchol",(DL_FUNC)&mgcv_Rpchol,4},
{"mgcv_Rpforwardsolve",(DL_FUNC)&mgcv_Rpforwardsolve,3},
{"mgcv_Rpcross",(DL_FUNC)&mgcv_Rpcross,3},
{"mgcv_RX",(DL_FUNC)&mgcv_RX,2}, // we add this line
{NULL, NULL, 0}
};
第 5 步:编译和加载
tar
修改mgcv
文件夹为mgcv.tar.gz
.
打开一个新的、干净的 R session(可能 start-up 需要 R --vanilla
)。然后指定本地库路径和 运行:
path <- getwd() ## let's just use current working directory
## make sure you move "mgcv.tar.gz" into current working path
install.packages("mgcv.tar.gz", repos = NULL, lib = path)
library(mgcv, lib.loc = path)
第 6 步:测试并得到错误
R <- matrix(runif(25), 5)
R[lower.tri(R)] <- 0
X <- matrix(runif(25), 5)
mgcv:::RX(R, X) ## function is not exported, so use `mgcv:::` to find it
# Error in .Call("C_mgcv_RX", R, X) :
# "C_mgcv_RX" not resolved from current namespace (mgcv)
谁能解释为什么以及如何解决这个问题?
我现在有一个临时 "fix"。而不是
.Call("C_mgcv_RX", R, X)
使用以下任一方法:
.Call(mgcv:::"C_mgcv_RX", R, X)
.Call(getNativeSymbolInfo("mgcv_RX"), R, X)
之所以想到这个,是因为我突然意识到C例程也可以被:::
提取出来。既然包编译成功,那么mgcv:::
不可能找不到这个C例程。是的,它有效。
要检查我们定义的 C 例程是否在加载的共享库中可用,请尝试
is.loaded("mgcv_RX")
# TRUE
要列出加载的共享库中所有已注册的 C 例程,请使用
getDLLRegisteredRoutines("mgcv")
我最近正在使用 mgcv
GAM 进行一些计算测试。修改了一些原有的功能,增加了一些功能。为了不破坏兼容性,对于我要修改的每个函数,我都创建了一个新版本,函数名称中带有 .zheyuan
后缀。例如,使用 Sl.fit
函数进行惩罚最小二乘拟合,我将得到一个 Sl.fit.zheyuan
。我会简单地将我编写的所有 R 函数收集到一个独立的 R 脚本中 "zheyuan.R"。通过将此文件添加到 mgcv_1.8-17
package source 的 R
目录中,并将修改后的包编译到本地路径中,我可以加载它进行测试。
我加R例程没问题,加C例程就不行。安装修改后的包时没有发生错误,但是当我调用我添加的 C 例程的 R 包装器函数时,我会收到问题标题中的错误。如果您对我的案例感兴趣,您可以按照以下步骤重现此类错误。
第一步:下载最新包源
从上面link下载1.8-17版本。当在 CRAN 上发布新的 mgcv
版本时,这样的 link 将会消失。但您可以随时前往 mgcv
CRAN page 下载最新版本。
让我们untar
来源。首先,删除文件MD5
,这样我们在编译修改后的版本时就不会收到烦人的MD5警告了。下面,我们将在 R
目录和 src
目录中添加新内容。
第 2 步:创建 R 脚本
考虑以下 R 包装函数:
RX <- function (R, X) {
X <- X + 0
.Call("C_mgcv_RX", R, X)
X
}
创建一个 R 脚本 "zheyuan.R" 来放置此函数,并将其添加到 mgcv/R
。
步骤 3:添加 C 例程
关于矩阵计算的 C 例程通常在 src/mat.c
下。所以让我们在这个脚本的末尾追加一个新函数:
void mgcv_RX (SEXP R, SEXP X) {
int nrowX = nrows(X);
int ncolX = ncols(X);
double one = 1.0;
F77_CALL(dtrmm)("l", "u", "n", "n", &nrowX, &ncolX, &one, REAL(R), &nrowX, REAL(X), &nrowX);
}
这是一个简单的例程,将上三角矩阵 R
与矩形矩阵 X
相乘。输出矩阵将覆盖 X
。为此将调用 Level-3 BLAS dtrmm
。我们不需要担心 header 文件或 运行 时间 linking 到 BLAS 库。 Headers 在 mat.c
中可用,link 到 BLAS 由 R 管理。
第四步:注册C例程
以上内容还不够。 mgcv
中的每个 C 例程将出现在三个地方。例如,让我们尝试搜索本机 C 例程:
grep mgcv_RPPt mgcv/src/*
# mgcv/src/init.c: {"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
# mgcv/src/mat.c:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT) {
# mgcv/src/mgcv.h:void mgcv_RPPt(SEXP a,SEXP r, SEXP NT);
我们还需要附加一个header文件mgcv.h
,并在init.c
.
让我们追加
void mgcv_RX (SEXP R, SEXP X);
到 mgcv.h
的末尾,在 init.c
内,执行:
R_CallMethodDef CallMethods[] = {
{"mgcv_pmmult2", (DL_FUNC) &mgcv_pmmult2,5},
{"mgcv_Rpiqr", (DL_FUNC) &mgcv_Rpiqr,5},
{"mgcv_tmm",(DL_FUNC)&mgcv_tmm,5},
{"mgcv_Rpbsi",(DL_FUNC)&mgcv_Rpbsi,2},
{"mgcv_RPPt",(DL_FUNC)&mgcv_RPPt,3},
{"mgcv_Rpchol",(DL_FUNC)&mgcv_Rpchol,4},
{"mgcv_Rpforwardsolve",(DL_FUNC)&mgcv_Rpforwardsolve,3},
{"mgcv_Rpcross",(DL_FUNC)&mgcv_Rpcross,3},
{"mgcv_RX",(DL_FUNC)&mgcv_RX,2}, // we add this line
{NULL, NULL, 0}
};
第 5 步:编译和加载
tar
修改mgcv
文件夹为mgcv.tar.gz
.
打开一个新的、干净的 R session(可能 start-up 需要 R --vanilla
)。然后指定本地库路径和 运行:
path <- getwd() ## let's just use current working directory
## make sure you move "mgcv.tar.gz" into current working path
install.packages("mgcv.tar.gz", repos = NULL, lib = path)
library(mgcv, lib.loc = path)
第 6 步:测试并得到错误
R <- matrix(runif(25), 5)
R[lower.tri(R)] <- 0
X <- matrix(runif(25), 5)
mgcv:::RX(R, X) ## function is not exported, so use `mgcv:::` to find it
# Error in .Call("C_mgcv_RX", R, X) :
# "C_mgcv_RX" not resolved from current namespace (mgcv)
谁能解释为什么以及如何解决这个问题?
我现在有一个临时 "fix"。而不是
.Call("C_mgcv_RX", R, X)
使用以下任一方法:
.Call(mgcv:::"C_mgcv_RX", R, X)
.Call(getNativeSymbolInfo("mgcv_RX"), R, X)
之所以想到这个,是因为我突然意识到C例程也可以被:::
提取出来。既然包编译成功,那么mgcv:::
不可能找不到这个C例程。是的,它有效。
要检查我们定义的 C 例程是否在加载的共享库中可用,请尝试
is.loaded("mgcv_RX")
# TRUE
要列出加载的共享库中所有已注册的 C 例程,请使用
getDLLRegisteredRoutines("mgcv")