Gismo库杂谈——与Eigen库的冲突
问题描述
在较新版本的Gismo库中可能会出现与外部Eigen库冲突的问题,例如以下代码:
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
int main()
{
gismo::gsMatrix<real_t> A(2, 2);
Eigen::MatrixXd B(2, 2);
return 0;
}
这段代码在编译阶段会报错:“Eigen”:不是类或命名空间名称。
出现这个问题的原因在于库的创建者为了修复gismo与其他库中的Eigen冲突问题,将包含在gismo中的Eigen命名空间重命名为gsEigen,但其中Eigen库的所有头文件开头的保护性宏定义没有被修改,于是#include <Eigen/Dense>
引入的所有头文件的内容都在开头的#ifndef EIGEN_XXX_H
判断为非后被忽略掉了。
解决方案
参考官方issue #438中提到的 “Undefine all eigen guards so that loading again Eigen library from another source is possible.”
如果一定要使用外部的Eigen库,则应先取消掉一些宏定义,我们可以在gismo源目录中或安装好的gismo的include目录中打开终端,执行以下命令:
- 01
grep -rh "#ifndef EIGEN_.*_H" * | sed "s/#ifndef/#undef/g" > gsUndefEigenGuards.h
需要注意,这行命令涉及的两个程序grep
、sed
都是Unix系统下的,如果想在Windows下使用则需安装额外工具,我这里安装的是BusyBox.
执行了以上的命令后,文件夹中会多出来一个文件gsUndefEigenGuards.h
,里面每一行都是#undef EIGEN_XXX_H
的形式,这就是在取消掉Eigen的所有保护宏。当然如果这一步实在不会操作,我这边也提供了我输出的gsUndefEigenGuards.h
以供使用。(gsUndefEigenGuards.h)
在得到该文件后,将其加入到项目中并在#incude <gismo.h>
后引入它就可以解决问题了。
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
int main()
{
gismo::gsMatrix<real_t> A(2, 2);
Eigen::MatrixXd B(2, 2);
return 0;
}
替代性方案:
在gismo库中也含有一个内部的Eigen,但是由于Eigen命名空间被修改导致我们无法直接使用,所以如果考虑到前面的解决方案繁琐且存在隐患,也可以通过增加一行#define Eigen gsEigen
的方式来使用gismo内部的Eigen
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
int main()
{
gismo::gsMatrix<real_t> A(2, 2);
Eigen::MatrixXd B(2, 2);
return 0;
}
补充说明
以上的方案通过在#include <gismo.h>
后引入一个取消Eigen保护宏的头文件来解决问题,然而如果Eigen库是在gismo之前引入的呢?那我们则需要在Eigen之后,gismo之前引入这个头文件:
- 01
- 02
- 03
当然在复杂的场景下,比如多文件编译,我们需要在合适的位置引入这个头文件,在使其发挥作用的同时还需避免如下所示的在两次重复引入Eigen之间引入此头文件导致Eigen中的内容重定义。
- 01
- 02
- 03