移植GROOPS代码至Visual Studio2019

近期尝试将GROOPS代码移植到Visual Studio平台上,遇到了很多问题,踩了许多坑,故写下这篇文章供有需求的人参考。内容主要分为四个部分:

1、准备工作

准备软件:VS2019, CMake、One API Toolkit。
(a)为什么选择VS2019而不是最新的VS2022?因为2022版还没有完整的配套One API Toolkit。
(b)CMake下载地址:https://cmake.org/download/ (我下载的是3.24 release版本)
(c)One API Toolkit下载地址:https://www.intel.com/content/www/us/en/developer/tools/oneapi/toolkits.html#gs.67f2ch
安装参考:https://zhuanlan.zhihu.com/p/411167136

2、移植

移植工作比较简单:
(a)首先创建一个自己的VS2019空项目(×64),并创建source文件夹。如果需要调试的话建议生成Debug程序,如果发布建议生成Release来加快运行速度。
(b)后将GROOPS的source文件目录下自己需要的代码直接copy到VS2019工程目录下的source文件夹下,这里十分不建议改动GROOPS源码(.h .cpp)的相对路径,例如以GROOPS的source文件所在的路径为起点,archive.cpp和archive.h相对于source的路径为inputOoutput,要拷贝这两个代码需要将inputOutputarchive.cpp和archive.h都拷贝到自己的工程目录下,如果你改动了这一层关系,那你就需要在VS工程中狂改路径。
在这里插入图片描述
(c)进入VS工程,将需要的cpp与h文件分别组织在源文件和头文件中(下图红色方框内以(b)中提到的为例)。
在这里插入图片描述
在这里插入图片描述
(d)观察右侧”解决方案资源管理器“,右键你工程的名字->属性->C/C++ 常规->附加包含目录,把你工程source文件路劲拷贝进去,这一步是为了让VS从source开始寻找头文件与源文件,避免了从groops上直接移植的代码出现头文件引用错误的问题。

在这里插入图片描述

3、外部依赖库

外部依赖库这一部分主要讲lapack与blas这两个库的引用,这两个库在VS2019中使用需要自己来编译,官方编译流程:https://icl.utk.edu/lapack-for-windows/lapack/index.html#running(看Build Instructions for LAPACK 3.5.0 for Windows with Visual Studio这一部分) ,不喜欢看英文?那就往下看:
(a)首先下载lapack与blas的fortran源码并解压,下载地址:
http://www.netlib.org/lapack/#_lapack_version_3_10_1_2
(b)打开CMake的GUI界面,依次输入CMakeList.txt所在目录以及构建结果存放目录。
在这里插入图片描述
(c)点击左下角Configure按钮,在弹出的窗口选择Visual studio 2019,并在下方勾选Specify native compilers,在弹出的窗口中的fortran选项中找到icl.exe(在第一步安装的One API Base Toolkit目录下,我的在E:\one_API Base Toolkit\compiler\2022.1.0\windows\bin\intel64_ia32下,使用的是64位fortran编译器)
在这里插入图片描述
在这里插入图片描述
点击Finish后点击Config,第一次Config肯能会出现很多标红内容,再点即可,直到标红部分消失后,点击Generate即可在输出目录下获得一个sln工程,进入该工程,右键"ALL_BUILD"->生成,获得lapack.lib以及blas.lib静态库文件,即完成生成。

(d)下面结合groops代码将lapack于lbas库引入VS2019。创建一个新的fortran静态库工程:VS2019->static library(fortran),我的工程叫做external。将lapack.lib以及blas.lib放置在工程目录下,在将groops->source->blasWrapper.f 以及 lapackWrapper.f拷贝至lapack.lib以及blas.lib同一目录下并添加在sln中的源文件中。
在这里插入图片描述
右键external->属性,在附加依赖库中加入lapack.lib blas.lib,在附加库目录添加lapack.lib blas.lib所在的文件目录,确定。右键external->生成,可得到external.lib。
在这里插入图片描述
(e)打开要以移植的VS工程,添加头文件,并把lapack.lib blas.lib external.lib全部拷贝到工程的external目录下。
在这里插入图片描述
并右键工程,属性->链接器->常规->附加库目录,将lapack.lib blas.lib external.lib所在路径拷贝进去,并在属性->链接器>输入->附加依赖项写入lapack.lib blas.lib external.lib。以防万一,右键工程->添加,把lapack.lib blas.lib external.lib添加进去。除此之外,进入fortran.h,注释掉#define FORTRANCALL(lower,upper) lower ## _,解除#define FORTRANCALL(lower,upper) upper的注释,如此对项目进行编译就不会出现外部库引用的问题了。
在这里插入图片描述

4、写在最后

关于gfortran于IVF(One API Base Toolkit)。经过无数次失败、翻阅材料与重新尝试,笔者发现gfortran与IVF编译的fortran码有极大不同。gfortran是GNU下的编译工具,一般用于linux,而IVF是intel推出的编译工具,一般结合vs使用,下边有一个fortran代码:

 subroutine wrapdgeev(jobvl,jobvr,n,A,ldA,WR,WI,VL,ldVL,VR,ldVR,work,lwork,info)
      external dgeev
      integer   jobvl, jobvr
      character jobvlc, jobvrc
      if(jobvl.eq.0) then
        jobvlc = 'N'
      else
        jobvlc = 'V'
      endif
      if(jobvr.eq.0) then
        jobvrc = 'N'
      else
        jobvrc = 'V'
      endif
      call dgeev(jobvlc,jobvrc,n,A,ldA,WR,WI,VL,ldVL,VR,ldVR,work,lwork,info)
      end

函数名叫wrapdgeev对吧?gfortran编译后,它的函数名会变为wrapdgeev_, 而IVF编译后它的函数名将会变为WRAPDGEEV,这个差异如果没有注意,那么你在C++程序中引用该函数时就会出错”LINK2019 无法解析的外部符号 …“。因为C语言区分大小写,当它调用fortran库的函数时:

extern "C"
{
void wrapdgeev (const F77Int &jobvl, const F77Int &jobvr, const F77Int &n, F77Double A[], const F77Int &ldA, F77Double WR[], F77Double WI[], F77Double VL[], const F77Int &ldVL, F77Double VR[], 
}

它会按照你声明的这个名字去寻找fortran库中的函数,如果fortran函数编译出来是大写,那么C++就无法识别。fortran是不区分大小写的,所以在fortran程序中调用fortran外部库函数不需要注意这些。
关于IVF的编译问题,我推荐网站:
https://community.intel.com/t5/Intel-Fortran-Compiler/bd-p/fortran-compiler/topic/624981

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值