如何在不复制源代码或创建库的情况下重用Fortran模块

时间:2013-05-03 05:39:53

标签: module linker fortran intel-fortran photran

我无法理解是否/如何在多个Fortran项目之间共享代码而不构建库或复制源代码。

我在Linux系统上使用Eclipse / Photran和Intel编译器(ifort),但我相信我对模块的概念问题比使用特定工具更大。

这是一个简单的例子:在〜/ workspace / cow中,我有一个包含cow.f90(PROGRAM)的源目录(src)和m_graze.f90和m_moo.f90中的两个模块m_graze和m_moo。该项目正确构建和链接以创建可执行文件“cow”。可执行文件和模块(m_graze.mod和m_moo.mod)存储在〜/ workspace / cow / Debug中,目标文件存储在〜/ workspace / cow / Debug / src

稍后,我创建〜/ workplace / sheep并将src / sheep.f90作为程序,将src / m_baa.f90作为模块m_baa。我想'只使用m_graze:在sheep.f90中反刍'来访问ruminate()子程序。我可以复制m_graze.f90但这可能导致代码不同步,并且没有考虑m_graze可能具有的任何依赖性。出于这些原因,我宁愿将m_graze留在牛项目中,并编译并链接sheep.f90。

如果我尝试编译绵羊项目,我会收到如下错误:

error #7002: Error in opening the compiled module file.  Check INCLUDE paths.   [M_GRAZE]

在羊的属性:项目参考下,我可以选择牛项目。在Properties:Fortran Build:Settings:Intel Compiler:Preprocessor我可以将〜/ workspace / cow / Debug(模块文件的位置)添加到include目录列表中,这样编译器现在可以找到cow模块并编译sheep.f90。然而,链接器死了像:

Building target: sheep
Invoking: Intel(R) Fortran Linker
ifort -L/home/me/workspace/cow/Debug -o "sheep"  ./src/sheep.o
./src/sheep.o: In function `sheep':
/home/me/workspace/sheep/src/sheep.f90:11: undefined reference to `m_graze_mp_ruminate_'

这通常可以通过向链接器设置添加库和库路径来解决,除了没有适当的库链接(这是Fortran,而不是C)。

牛项目完全能够将cow.f90,m_graze.f90和m_moo.f90编译并链接到一个可执行文件中。虽然羊项目可以编译sheep.f90和m_baa.f90并且可以找到模块m_graze.mod,但是它似乎无法找到m_graze的符号,即使系统上存在所有必需的信息也是如此

配置ifort的链接器部分以找到缺失的部分并将它们组合在一起似乎是一件容易的配置问题,但我不知道需要在Photran UI中输入哪些魔术字才能实现这一点

我承认在C和C构建过程中完全缺乏兴趣和能力,我宁愿避免创建库(.a或.so)的转移,除非这是使这项工作的唯一方法。

最终,我正在寻找一个纯粹的Fortran解决方案来解决这个问题,因此我可以保留源代码的单个副本,而不必手动维护一堆自定义Makefile。

那可以这样做吗?

道歉,如果已经在某处记录过; Google只向我展示了简单的构建示例,如何创建模块以及如何与现有库链接。似乎没有(m)代码重用的任何示例与不涉及复制源代码的模块。


修改

正如受访者所指出的那样,.mod文件是必要的,但还不够;在链接阶段必须指定目标代码(以m_graze.o的形式)或staticshared库。 .mod文件描述了目标代码/库的接口,但这两者都是构建最终可执行文件所必需的。

对于这样一个过于简单的玩具问题,这足以回答提出的问题。

在一个具有更复杂依赖关系的大型项目中(在我的情况下,F90的80 + KLOC链接到MKL版本的LAPACK95),IDE或工具链可能缺少足够的自动或用户界面工具来共享单个规范集源文件是一个可行的策略。选择似乎是冒着重复的源文件不同步的风险,放弃了IDE的许多好处(即避免手动创建make / CMake / SCons文件),或者很可能两者兼而有之。虽然修订控制系统和良好的代码组织可以提供帮助,但很明显,鉴于Eclipse的当前状态,在项目之间共享单个规范的源文件集并不容易。

2 个答案:

答案 0 :(得分:4)

我怀疑您已经知道的一些背景:通常(包括ifort)编译Fortran模块的源代码会产生两个输出 - 一个“mod”文件,其中包含模块定义的Fortran实体的描述< em>编译器需要在它看到模块的USE语句时,以及实现模块定义的过程和变量存储等的链接器的目标代码时查找。

您的第一个错误(您解决的错误)是因为编译器无法找到mod文件。

第二个错误是因为没有告诉链接器实现源模块中包含模块的东西的目标代码。我无论如何都不是Eclipse用户,但是指定这种方式的蛮力方式只是添加目标文件(xxxxx/Debug/m_graze.o)作为附加链接器选项(Fortran Build&gt; Settings,Intel Fortran Linker&gt; ; 命令行)。 (其他工具链的链接阶段具有明确的“附加目标文件”属性 - 可能有更好的方法为英特尔链做到这一点。)

对于更多涉及的示例,您通常会从共享代码中创建一个库。这不是特定于C的,唯一的Fortran方面是目标代码的库存档需要与Fortran编译器生成的mod文件一起提供。

答案 1 :(得分:1)

是的,必须提供目标代码。例如,当您在Debian(apt-get install libnetcdf-dev)中安装libnetcdf-dev时,会包含一个/usr/include/netcdf.mod文件。

您现在可以在Fortran代码中使用所有netcdf例程。如,

program main
use netcdf
...
end 

但您将链接到netcdf共享(或静态)库,即

gfortran -I/usr/include/ main.f90 -lnetcdff

但是,正如用户MSB提到的那样,mod文件只能由分发版附带的gfortran使用(apt-get install gfortran)。如果你想使用任何其他编译器(甚至是你自己安装的不同版本),那么你必须使用那个特定的编译器自己构建netcdf。

因此创建库并不是一个糟糕的解决方案。