Author:Zengqiang Date:2013-3-29
为了能在32位和64位windows平台VS或VC环境下的C/C++工程能够调用fortran语言编写的科学计算库函数或者自己编写的fortran函数,这里采用MinGW软件在windows平台下用unix环境下的GNU make 3.81和相关工具编译出动态链接库。
Step1 下载MinGW32or MinGW64工具并配置
MinGW软件是一款在Unix/Linux和Windows平台生成本地的Windows程序的开源免费工具集,含有部分Windows特定头文件和GNU工具集,对于Windows和Unix/Linux两个平台下的交叉编译应用提供了极大的方便。
MinGW提供了32位版本安装包和64位MinGW64-project,以及MSYS工具(32位和64位皆可用),这些软件可以在MinGW官网下载:
http://www.mingw.org/
关于MinGW32和MinGW64的安装、配置和使用,请参考下文中的第一部分,有详细的步骤说明:
http://blog.csdn.net/guillotine007/article/details/8636647
到此为止,我们认为您已经正确安装和配置好了MinGW32或MinGW64,接下来切入正题。
Step2编写您的Makefile并编译出object文件
这里用实例来说明,代码可以参考使用。
我有一系列fortran源文件实现了特征值和特征向量的求解,这些文件如图所示,我把它们放在了一个名为dsdrvlib的文件夹下:
Debug.h和stat.h里面是部分变量的声明,与外部的调用接口函数定义在dsdrv3.f中。现在要编译出所有f源文件的目标文件。
Makefile文件内容如下:
ARPACKLIB = dsdrv.a
.SUFFIXES: .SUFFIXES: .f .o
FC = gfortran FFLAGS = AR = ar ARFLAGS = rv RANLIB = ranlib
DOBJ = daxpy.o dcopy.o ddot.o dgemv.o dgeqr2.o dger.o dgetv0.o dgttrf.o \ dgttrs.o dlacpy.o dlae2.o dlaev2.o dlamch.o dlanst.o dlapy2.o dlarf.o\ dlarfg.o dlarnv.o dlartg.o dlaruv.o dlascl.o dlaset.o dlasr.o dlasrt.o\ dlassq.o dmout.o dnrm2.o dorm2r.o dsaitr.o dsapps.o dsaup2.o dsaupd.o\ dscal.o dsconv.o dsdrv3.o dseigt.o dsesrt.o dseupd.o dsgets.o dsortr.o\ dstats.o dsteqr.o dstqrb.o dswap.o dvout.o ivout.o lsame.o second.o\ xerbla.o
.f.o: $(FC) $(FFLAGS) -c $<
all: double
double: $(DOBJ) $(AR) $(ARFLAGS) $(ARPACKLIB) $(DOBJ) $(RANLIB) $(ARPACKLIB)
help: @$(ECHO) "usage:make ?"
.PHONY:clean clean: rm -f *.o a.out core |
使用了make的隐含规则,这里没有给出.h文件的依赖,它会自动找到.h文件的依赖。
这里使用的是make 3.81版本,也是目前应用最广泛的版本,新版的GNU-GCC工具集中用gfortran代替了以前的f77工具,所以这里的FC变量设成了gfortran,各位如果有类似的实例,只需要替换Makefile中的DOBJ里的.o文件即可修改成适合自己的Makefile,启动msys.bat,再进入dsdrvlib目录:
此时已经准备好了Makefile文件,输入make命令等待编译完成并查看结果:
除了多了所有.f文件对应的.o文件,还有一个dsdrv.a文件,该文件是所有.o文件的一个打包文件,也称为静态库,在Unix/Linux下为.a文件,在windows下为.lib文件,该文件在Unix/Linux系统下可以被C/C++直接链接了,但是在windows系统下,由于一些调用约定对函数名称的wrap修饰,会导致直接链接找不到对应的函数。
OK,一步一步来,现在已经得到了所有的object文件了。
Step3使用MinGW32/64来得到Windows下使用的库
仍然使用msys工具进入dsdrvlib文件夹中,使用dllwrap工具生成dll和def文件,dll文件中是所有object文件的集合,是代码的二进制实现,def文件包含了dll文件中的函数名称和在dll文件中的入口地址,dllwrap命令使用如下:
dllwrap --export-all-symbols *.o -lgfortran --output-def dsdrv32.def -o dsdrv32.dll
其中dsdrv32.def和dsdrv32.dll是我自己定义的输出文件名。
如果你使用的是MinGW64中的相关工具集,那么以上的步骤完全相同,产生出来的文件是专门用于64位windows应用的,64位下可以把名称修改为dsdrv64.def和dsdrv64.dll来区分。
dllwrap--export-all-symbols *.o -lgfortran --output-def dsdrv64.def -o dsdrv64.dll
msys在执行完该命令后:
查看文件夹,发现多了2个文件,一个是dsdrv32.def,一个是dsdrv32.dll文件。此时如果你在Windows下想使用显式链接的方式使用动态链接库,那么在你的C/C++工程中调用Windows的API:
HINSTANCE hDLL; //Handle to DLL
hDLL = LoadLibrary("MyDLL"); //Load DLL
…
FreeLibrary(hDLL); //Free DLL
此时只需要将dll文件拷贝到你的工程中使用即可咯!
如果你想使用隐式链接的方式加载DLL,那么请继续往下看咯!
隐式链接的方式是指不适用Windows的API来加载dll,而是在源文件中使用e
xtern调用的形式来加载dll:
#ifdef __cplusplus
extern "C" {
#endif
void dsdrv3_(int *row, int *col, double *vv, double *dvalue, double *a_mat, double *b_mat, double *binv_mat);
#ifdef __cplusplus
}
#endif
当然,如果源文件是c文件就只需要:
extern "C" void dsdrv3_( int *row, int *col, double *vv, double *dvalue, double *a_mat, double *b_ mat, double *binv_mat);
用这种隐式链接的方式加载dll,就需要lib文件了,lib文件可以用微软VS/VC平台中自带的lib.exe工具生成,前提是需要dll对应的def文件,前面我们已经得到了dsdrv64.def文件。
lib.exe的路径:
D:\MySoftWares\Microsoft VisualC++\VC98\Bin\LIB.EXE
找到你的VC安装路径替换即可找到lib.exe了。
如果你使用的是Visual Studio,在相应路径下也可找到,例如:
C:\Program Files(x86)\Microsoft Visual Studio 8\VC\bin\lib.exe
找到lib.exe后,将其路径加入环境变量,当然一般VS/VC安装时该目录已经加入环境变量了。
lib /machine:X86 /def:dsdrv32.def
这里得到的是32位下的lib,如果你想使用64位下的lib,一定要使用VS平台下64位的lib工具,输入命令:
lib /machine:X64 /def:dsdrv64.def
在运行命令前,请确保你已经得到了响应的def文件。
来看看目录里的结果:可以看到,目录中多了一个文件dsdrv32.lib,你就可以把lib和dll文件拷贝到你的C/C++工程中使用了,64位下的方法步骤是一样的,只是用的工具都是64位下对应的工具!
OK,希望能帮助到各位,文中有不当之处尽请指正!
Zeng qiang
2013-03-30