FORTRAN静态库动态库的生成.docx

上传人:b****6 文档编号:7912931 上传时间:2023-01-27 格式:DOCX 页数:13 大小:28.86KB
下载 相关 举报
FORTRAN静态库动态库的生成.docx_第1页
第1页 / 共13页
FORTRAN静态库动态库的生成.docx_第2页
第2页 / 共13页
FORTRAN静态库动态库的生成.docx_第3页
第3页 / 共13页
FORTRAN静态库动态库的生成.docx_第4页
第4页 / 共13页
FORTRAN静态库动态库的生成.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

FORTRAN静态库动态库的生成.docx

《FORTRAN静态库动态库的生成.docx》由会员分享,可在线阅读,更多相关《FORTRAN静态库动态库的生成.docx(13页珍藏版)》请在冰豆网上搜索。

FORTRAN静态库动态库的生成.docx

FORTRAN静态库动态库的生成

FORTRAN静态库、动态库的生成、维护与调用

闫昊明2006-9-10

一、FORTRAN静态库的生成与维护

FORTRAN静态库是经过编译的代码块,它与主程序相对独立,可以被主程序调用,是FORTRAN工程类型之一.静态库包含一系列子程序,但不包括主程序.静态库一般具有LIB扩展名并包含目标代码,且静态库存放在它们特定的目录中.FORTRAN静态库在组织大型程序和在不同程序之间共享子程序等方面具有较大的优点,其重要性不言而喻.当将静态库与主程序联系起来时,在主程序中调用静态库中的任何子程序将编译到相应的可执行程序.应用静态库的时候,只有所需要的子程序才在编译过程中插入到可执行文件(.EXE),这意味着这种可执行文件将比包含所有的子程序所生成的可执行文件小.而且,不必担心哪些子程序是需要的,哪些是不需要的,编译器将替你做出选择.同时,当更改静态库中的子程序时,相应的应用程序可以不做任何改变,而只需要对其进行重新的编译链接,即可获得新的结果,这无疑也是方便的.

目前,常用的FORTRAN静态库有很多种,WINDOWS操作系统下的CompaqVisualFORTRANversion6.5(简称CVF65)自带的数学统计库IMSL就是一个非常全面的静态库,可以用来解决线性代数和统计学上的很多经典问题.此外,在NCAR互联网站有很多有用的FORTRAN子程序(网址:

http:

//www.scd.ucar.edu/softlib/mathlib.html),其中包括地球物理科学问题、离散和快速Fourier变换、可分离的椭圆微分方程、插值、Legendre多项式、普通数学问题、本征值问题求解、线性方程求解、非线性方程求解、常微分方程求解、特殊函数、统计学等常用子程序集等.这些FORTRAN子程序可以解决很多基础性的问题,因此有很高的利用价值.

在WINDOWS操作系统下,可以用两个命令分别生成静态库.一个是用‘nmake’命令,它一般用来编译原来应用在UNIX环境下的FORTRAN子程序集,在编译过程中要读取makefile文件中的编译命令,类似于在UNIX下安装软件.另一个是用‘lib’命令,它可以在WINDOWS环境下编译任何需要集成为静态库的子程序集.

编译静态库在DOS命令行环境下比较方便,以后的命令行都指在此环境下运行.在编译静态库前,首先要安装CVF65,其次要完成要编译的FORTRAN子程序(*.f90).对于FORTRAN子程序,最好用FORTRAN90的标准来完成,应该放弃FORTRAN77标准。

FORTRAN90是FORTRAN语言从结构化走向面向对象化的重要一步,使FORTRAN语言更加接近C++。

在FORTRAN90标准中,对数组的操作既增强了功能又简化了使用,此外自由格式、MODULE、动态数组、指针等的应用大大丰富了FORTRAN语言,使得编程更加轻松。

目前,FORTRAN95和FORTRAN2000标准也在应用,它们与FORTRAN90标准比较类似,主要的改进在并行运算方面,因此目前在单机上应用的主要还是FORTRAN90.在DOS命令行环境下,进入到FORTRAN子程序所在的子目录,然后按下面两个步骤生成FORTRAN静态库.

(1)键入“df*.f90/c”,回车,可以看到CVF65编译器对所有的FORTRAN子程序(*.f90)进行编译,生成*.obj文件(注意,编译时,/c中的“c”必须小写).

(2)键入“lib*.obj/out:

libname.lib”,回车,可以看到链接生成libname.lib静态库.

需要注意的是,每次加入新的子程序或对静态库中的子程序修改以后,都要按上述两个步骤重新进行编译链接.生成静态库以后,可用“dumpbin/linkermemberlibname.lib”来查看静态库中可用的子程序名称.也可执行“lib/listlibname.lib”来查看静态库中的*.obj文件.

当然,也可以在CVF65集成环境下,生成静态库.步骤如下:

(a)进入到CVF65集成环境下,依次打开菜单File|New|FORTRANStaticLibrary.为新的静态库命名,如:

libname.lib.

(b)依次打开菜单Project|AddtoProject|Files,选择要编译的*.f90子程序到当前工作空间.

(c)依次打开菜单Build|Compile和Build|Build进行编译链接,生成libname.lib静态库(在当前目录中的debug子目录下).

当要编译的静态库需要其它静态库支持时,在步骤(b)中将支持库(*.lib)也加入到当前工作空间,即可顺利编译新的静态库.

从上面的介绍可以看出,无论采用哪种方法,其基本步骤是一致的,即首先生成目标文件*.obj,然后再将这些文件链接成一个静态库文件*.lib.对于简单的静态库可以按第一种方法在DOS环境下生成,对于需要其它静态库支持的子程序集则可以首先加入库的路径,再在编译时链接这些静态库,最后生成静态库文件.

静态库生成以后还要经常进行更新和维护,以便更有效的利用这些资源.下面给出维护静态库时常用的命令.

(Ⅰ)将一个编译好的obj文件(如:

ok.obj)加入到现有静态库(如:

libname.lib),命令为“libok.objlibname.lib/out:

libname.lib”.

(Ⅱ)将两个或多个静态库合并成一个(all.lib),命令为“lib1.lib2.lib3.lib/out:

all.lib”,或“lib*.lib/out:

all.lib”.

(Ⅲ)列出静态库中的成员(MEMBER),成员对大小写敏感,命令为“liblibname.lib/list:

[outputfilename]”,可给出静态库中的成员,即*.obj.

(Ⅳ)从静态库中解出(extract)特定成员,命令为“liblibname.lib/extract:

member”.

(Ⅴ)从库中删除成员,命令为“liblibname.lib/remove:

member”.

二、FORTRAN静态库的调用

FORTRAN静态库的调用主要有两种方式,第一种方式是在DOS环境下用命令行调用,其基本命令为“df*.f*.lib”,值得注意的是,在此种情况下,要设置合适的搜索路径(修改CVF65目录下的子目录bin中的文件dfvars.bat),也可以直接将自己的静态库拷贝到CVF65默认库目录下(CVF65根目录下的子目录lib中).第二种方式是在CVF65环境下调用.在此方式下有两种方法:

方法一:

首先对主程序进行编译,然后将静态库文件插入到当前工作空间(参考第一节步骤(b)),再进行链接,即可获得可执行文件.方法二:

对主程序编译后,依次打开菜单Project->settings…在对话框中选择Link选项卡,在Object/librarymodels项下加入静态库文件的名字,再进行链接,同样可以获得可执行文件.

上面所述的两种方法都比较麻烦。

下面介绍在FORTRAN90语言环境中应用MODULE来解决这一问题。

首先建立一个F90的module程序,名字为userlibmod.f90,对所有静态库中的子程序在此module程序中加入接口语句。

其基本结构如下(为便于叙述,在每行都加了行号,源程序中应无此行号):

1.MODULEuserlibmod

2.!

DEC$OBJCOMMENTLIB:

'LIBNAME.LIB'

3.interfacesumab

4.subroutineint_sumab(a,b,c)

5.integera,b,c

6.…

7.endsubroutineint_sumab

8.subroutinereal_sumab(a,b,c)

9.reala,b,c

10.…

11.endsubroutinereal_sumab

12.endinterfacesumab

13.INTERFACE

14.SUBROUTINECALENDAR(IY1,IM1,ID1,IY2,IM2,ID2,IUNITS,NDAYS)

15.INTEGER,INTENT(IN):

:

IY1,IM1,ID1,IY2,IM2,ID2,IUNITS

16.INTEGER,INTENT(OUT):

:

NDAYS

17.…

18.ENDSUBROUTINECALENDAR

19.ENDINTERFACE

20.ENDMODULE

从这个module的结构可以看出,第1行要给出module的名字,最好与文件名相同。

第2行告诉编译器要链接的静态库的名字(这里虽然看似注释语句,其实不是,此行可以在编译的过程中与编译器进行通讯,不能省略,不然可能造成编译错误)。

3到12行是一个有名接口语句,这里边有两个子程序(对整数和实数分别求和)。

我们可以用两个子程序名来分别调用对应的两个数求和,也可以用接口名来直接调用这两个子程序,当用接口名来调用时,如果输入的参数是整数,相当于调用int_sumab(a,b,c),如果输入的参数是实数,相当于调用real_sumab(a,b,c)。

所以在F90语言中,可以简化调用函数的个数。

13到19行定义了另外一个无名接口,接口中也可以加入多个类似14行到18行的子程序或函数,这些子程序或函数必须已经编译到静态库“LIBNAME.LIB”中。

20行是module的结束语句。

将编辑好的module程序存盘,在命令行下执行“dfuserlibmod.f90/c”,即可生成MOD文件“userlibmod.mod”。

将此MOD文件放入合适的地方,如“d:

/myforlib/include/”,再将生成的静态库文件放入相应的路径,如“d:

/myforlib/lib/”,则一个自己的静态库就建成了。

为了应用此静态库,首先要对CVF65设置合适的搜索路径。

打开CVF65集成环境,依次打开菜单“tools|options|directories”,在showdirectoriesfor下拉菜单中依次点击“includefiles”和“libraryfiles”,然后再下面的“directories”中在空白处依次将“d:

/myforlib/include/”和“d:

/myforlib/lib/”加入,点击“ok”按钮,即完成了对搜索路径的设置。

现在,就可以方便的调用静态库中的子程序或函数了,只需要在你自己的主程序中第一行加入如下语句“useuserlibmod”即可(如果第一行是“programyourprogramname”,则将其加入到此行的下一行)。

三、静态库的其它说明

如果你应用的FORTRAN编译器是INTELVISUALFORTRAN9.0(IVF)以上的版本,可以按照和上面的过程类似的方法来生成静态库,唯一的区别是编译命令不同,IVF用ifort命令进行编译,而lib命令是一致的;此外,对于IVF路径的设置是ifortvars.bat文件,其它的内容都是类似的。

需要注意的是,由于采用了不同的编译器,CVF和IVF编译的静态库一般不能共享,需要重新编译。

作者已经发布了自己编译的FORTRAN静态库软件WHIGGF90LIB(WFL),可以从访问。

有关静态库的问题可以发送email:

wfllib@

四、动态库与静态库的联系与区别

上面我们详细介绍了静态库的生成维护与使用,我们在此做一个小的总结。

静态库在使用的时候,首先把需要使用的函数编译成机器代码,保存在*.lib文件中,然后在主程序中调用这些静态库中的函数时,编译器会到指定的*.lib文件中找出所需要的函数代码(或称之为机器码),并把这些代码复制一份,从而一起放到可执行文件exe中,这样就可以使exe文件脱离lib文件,在操作系统中单独运行。

也就是说,这样编译得到的exe文件具有独立性。

当然,这是跟动态库相比而得出的结论。

再来说说动态库的使用,大家经常在计算机系统里面看到dll为后缀的文件,觉得很神奇,它就是系统中必不可少的动态链接库文件。

其实,动态库跟静态库类似,也是计算机中使用库函数的另一种技术,它同样是把多个功能不同的函数使用编译器编译成机器码,然后存储在*.dll文件中。

与静态库不同的是,如果主程序调用的是动态库函数,那么编译器在编译的时候将不会把动态库中的机器码复制到可执行文件exe中去。

编译器只会在exe文件中说明要调用的函数放在哪个动态库中,其位置在那里。

当exe文件执行到这些在动态库中的函数的时候,操作系统就会把dll文件中的函数拿出来交给exe文件去执行使用。

同windows系统类似,在unix/linux系统中也可以编译动态链接库,只不过他们的文件名是以*.a结尾而已,其编译器也略有不同而已。

DLL文件有三个好处。

第一,可以让Fortran语言很好的与其它语言,如c++,VC,VB,Delphi…等进行混合编程,这样可以利用各自的优点,如fortran强于计算,而c++,VB等做界面比较方便,从而给出界面更友好的计算软件,达到人机更好的对话的效果。

第二,可以有效的减少exe文件的大小。

我们可以把很多程序共同使用的函数放在特定的DLL文件中,让执行文件变小,以减少对硬盘资源的消耗。

如果使用静态库,每个exe文件所使用的函数都会复制在对应的exe文件中,执行文件将因此变大,这样的选择并不是最佳的。

第三,DLL文件容易更新,因为DLL文件和exe文件是分离的,不在同一个文件中,因此只要更新必要的DLL文件,而不需要重新编译exe可执行文件,这样就可以得到最新版本的链接库。

如果使用静态库,则必须重新编译exe可执行文件,才能链接新的更新库。

五.用FORTRAN语言编译动态链接库

使用Fortran语言来编译静态库,用CVF的命令行方式最直观,命令格式为:

df*.f90/dll:

dllfilename。

由于是编译动态库,Fortran源程序的内容要添加一部分内容,下面我们给一个具体的例子来说明。

1.Subroutineadd(a,b,c)

2.!

DEC$ATTRIBUTESDLLEXPORT:

:

ADD

3.!

DEC$ATTRIBUTESALIAS:

’_ADD’:

:

ADD

4.Implicitnone

5.real,intent(in):

:

a,b

6.real,intent(out):

:

c

7.c=a+b

8.contains

9.subroutineprt()

10.print*,a,b,c

11.endsubroutineprt

12.endsubroutineadd

我们首先把上面的代码储存为add.f90文件,在这个文件中,我们定义了一个subroutine名字为add,其目的是把a和b两个参数求和,然后返回c=a+b的值。

注意到,这个subroutine与一般的subroutine的不同点在第2和第3行,其中,第2行是必须的,而第3行可以省略。

第2行的作用是定义输出的dll函数名称,这样dll文件就可以告诉操作系统,在此dll里面,哪些函数是可以被调用的。

注意,第2行这个命令也是隐含在注释中的,但编译器遇到!

DEC$为开始的注释行会知道这是传递给FORTRAN编译器的功能选项,知道这是在dll中输出一个函数名。

在dll中,只有这种有明确输出接口的函数才能对外公开使用。

没有使用这种接口(或称之为命令,!

DEC$,对于不同的编译器,其dll接口的定义可能是不同的,比如以前也应用过!

MS$等,这个需要查找编译器的帮助文件,以便正确的理解何接口才是编译器认识的)的函数只对dll内部函数有效,对外是不可见的。

譬如,上例中的9到11行定义了一个内部函数prt,用来打印a,b,c三个值到屏幕上,这个函数对dll以外的函数是不可见的,也不能调用。

同样,prt函数也不能用!

DEC$ATTRIBUTESDLLEXPORT:

:

PRT来声明,这会导致编译错误。

现在在CVF的command命令行方式下,用dfadd.f90/dll:

TEST.DLL就可以生成一个TEST.DLL动态链接库。

在生成动态链接库的同时,还将生成以下文件TEST.LIB,TEST.EXP,其中TEST.LIB文件是在编译调用TEST.DLL动态链接库的主程序时必须提供的文件,TEST.LIB文件是TEST.DLL的辅助文件,它里面没有函数add的机器码,但是说明了add函数在哪个dll里。

TEST.EXP文件是由LIB工具从DEF文件生成的输出文件,其中包含了函数和数据项目的输出信息,LINK工具将使用EXP文件来创建动态链接库。

只有在编译DLL时才会生成,记录了DLL文件中的一些信息。

TEST.EXP文件对用户来讲,没有更多的实际作用。

六.动态链接库的调用

下面我们编辑一个主程序,用来调用TEST.DLL这个动态链接库。

程序名称为test.f90,内容如下:

1.moduletestdll

2.!

DEC$OBJCOMMENTLIB:

'TEST.LIB'

3.interface

4.subroutineadd(a,b,c)

5.!

DEC$ATTRIBUTESDLLIMPORT:

:

ADD

6.!

DEC$ATTRIBUTESALIAS:

’_ADD’:

:

ADD

7.real,intent(in):

:

a,b

8.real,intent(out):

:

c

9.endsubroutineadd

10.endinterface

11.endmoduletestdll

12.programtest

13.usetestdll

14.reala,b,c

15.a=1.0;b=2.5

16.calladd(a,b,c)

17.end

在命令行下或在IDE集成环境下对test.f90进行编译,命令行下的命令为dftest.f90。

注意,此时TEST.LIB文件要与TEST.F90在同一目录下,或是TEST.LIB文件在lib的搜索路径中。

这样就可以生成TEST.EXE可执行文件。

执行TEST.EXE可执行文件可能会出现找不到TEST.DLL错误这样一个对话框,这是因为TEST.DLL不在系统的搜索路径或不和TEST.EXE在同一目录,将TEST.DLL放到TEST.EXE的目录下或放到C:

\WINDOWS\SYSTEM32目录下,就可以顺利运行TEST.EXE。

注意,1到11行我们定义了一个module,这样使得主程序在调用dll时,有明显的接口,在接口中(3到10行)我们给出了add函数的接口,其中5和6行是告诉主程序要引入add这一dll中的函数。

第2行定义了需要链接的对应于TEST.DLL的静态库文件TEST.LIB,这也是在编译可执行文件时所不能或缺的。

以上,我们比较详细的讲了如何生成动态链接库,如何调用动态链接库。

如果是大型的动态链接库,将会设计到非常多的FUNCTION和SUBROUTINE,此外在某一个FUNCTION或SUBROUTINE中还会调用其它的FUNCTION和SUBROUTINE,这时的FUNCTION和SUBROUTINE就要稍微复杂一些。

再举个例子,例如SUBROUTINE的内容如下:

1.Subroutineadd1(a,b,c)

2.!

DEC$ATTRIBUTESDLLEXPORT:

:

ADD1

3.!

DEC$ATTRIBUTESALIAS:

’_ADD1’:

:

ADD1

4.!

DEC$ATTRIBUTESDLLIMPORT:

:

DIV

5.!

DEC$ATTRIBUTESALIAS:

’_DIV’:

:

DIV

6.REAL,INTENT(IN):

:

A,B

7.REAL,INTENT(OUT):

:

C

8.INTERFACE

9.FUNCTIONPLUS(AA,BB)

10.!

DEC$ATTRIBUTESDLLIMPORT:

:

PLUS

11.!

DEC$ATTRIBUTESALIAS:

’_PLUS’:

:

PLUS

12.REAL,INTENT(IN):

:

AA,BB

13.REALPLUS

14.ENDFUNCTIONPLUS

15.ENDINTERFACE

16.REALAA,BB,D,E

17.AA=1.0;BB=6.0

18.D=PLUS(AA,BB)

19.CALLDIV(D,E)

20.A=E

21.C=A+B

22.ENDSUBROUTINEADD1

在这个例子里面,在ADD1这个SUBROUTINE里面调用了一个名为DIV的SUBROUTINE,还调用了一个名为PLUS的函数。

注意,2到5行和8到14行的写法。

对于SUBROUTINE来讲,一般直接用4到5行这样引用就可以了;对于FUNCTION来讲,最好是写在一个接口里面,如8到14行,当然也可以写成4到5行的形式。

如果FUNCTION和SUBROUTINE里面有optional变量的话,则最后用INTERFACE写成一个完整的接口里面,这样就不会出现问题。

当然,你也可以将所有的接口都定义在一个module中,此时要用DLLIMPORT属性,然后用use调用也可以。

需要注意的是,对于CVF自带的内部函数,不需要加任何东西,直接调用就可以了。

对于IMSL中的库函数,同样只要用usenumerical_libraries来引用就可以了,也不用加!

DEC$ATTRIBUTES等这些属性。

至于其它语言如何调用FORTRAN编译的动态链接库,请参考相关的文献,在此不再详述。

七.动态链接库的发布

编译好动态链接库以后,就可以把他与可执行文件一起发布了,但很多时候,在自己的计算机上运行的很好的程序到别人的计算机上就运行不了了,出现缺某某dll的错误对话框。

这是因为,你所编译的dll是与系统内部的一些dll相关的,要运行你自己的dll,还需要其它的dll来支持,如果没有这些dll支持,就会出现上述错误。

解决的办法有一个,把这些关联的dll也一起发给用户。

那么,怎么才能知道还需要那些关联的dll呢。

其实CVF提供了一个工具,叫做dependencywalker,在开始菜单中的CVF的程序菜单中可以找到,用这个小工具打开你的dll文件,就会看到与之相关联的dll了。

当然,并不是所有的dll都需要与可执行文件一起复制发布,譬如说kernel32.dll就是系统自带的,不需要一同复制。

你可以在dependencywalker中右键需要查看的dll文件,在属性的版本等信息中可以发现此dll文件是否是系统文件,这样就可以很好的区分哪些是必须要复制的文件,哪些是不需要的,当然也可以看到这些dll文件所在的位置。

当然这个工具其实也就是C++语言中的depends.exe这个小工具。

八.静态库和动态库的条件编译

上面讲到了分别对静态库和动态库进行编译,但我们面对的事实是,我们只想管理一套源程序,而不是分别为静态库和动态库各自建立一套类似的源程序,只有一些“!

DEC$ATTRIBUTES…”的区别,这样会增加管理的难度和出错的几率。

解决这一问题的一个方法就是利用条件编译,这是利用了GeneralCompilerDire

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 幼儿教育 > 少儿英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1