RcppEigen中#define在sourceCpp生效但R CMD build等场景失效原因问询
原因说明
该现象是sourceCpp和R包的编译机制差异导致的,核心源于Eigen控制宏的生效规则和两类编译场景的上下文区别:
EIGEN_INITIALIZE_MATRICES_BY_ZERO这类作用于Eigen库行为的宏,必须在首次引入Eigen相关头文件之前定义才能生效,头文件一旦被加载后再定义该宏不会产生任何效果。sourceCpp仅编译当前指定的单个.cpp文件,完全遵循文件内的代码顺序执行:先运行#define定义宏,再引入<RcppEigen.h>,宏完全生效,因此矩阵会按预期初始化为全0。- R包编译时的两类常见配置会导致宏失效:
- 你的包开启了预编译头(PCH)功能:预编译头会在所有
.cpp文件的代码执行前优先加载,如果预编译头中已经引入了<RcppEigen.h>,你在单个.cpp开头写的#define实际是在头文件引入之后才执行,自然不会生效。 - 包的公共头文件提前引入了Eigen:如果你的包有全局公共头文件(如
{包名}.h),且头文件中已经引入了<RcppEigen.h>,那么所有.cpp文件都会先加载公共头文件,你在单个.cpp中写的宏定义也会晚于头文件引入时机,不会生效。
- 你的包开启了预编译头(PCH)功能:预编译头会在所有
修复方案
要让该宏在整个R包范围内生效,最稳妥的做法是将宏定义添加到全局编译参数中,让编译器在所有头文件引入前就加载该宏:
- 在R包的
src目录下新建/修改Makevars(适配Linux、macOS)和Makevars.win(适配Windows)文件,添加如下内容:
PKG_CPPFLAGS += -DEIGEN_INITIALIZE_MATRICES_BY_ZERO
- 如果你不想修改编译配置文件,也可以逐一调整所有用到Eigen的
.cpp文件:保证每个文件的第一行就是#define EIGEN_INITIALIZE_MATRICES_BY_ZERO,同时不要在包的公共头文件、预编译头中提前引入<RcppEigen.h>。
修改完成后重新执行devtools::document()和R CMD build编译包,即可得到和sourceCpp一致的全0矩阵输出。
内容的提问来源于stack exchange,提问作者zdebruine
相关产品推荐
相关产品推荐

