【问题标题】:How to reuse Fortran modules without copying source or creating libraries如何在不复制源代码或创建库的情况下重用 Fortran 模块
【发布时间】:2013-05-03 05:39:52
【问题描述】:

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

我在 linux 系统上使用带有英特尔编译器 (ifort) 的 Eclipse/Photran,但我相信与特定工具相比,模块的概念问题更大。

这是一个简单的例子:在 ~/workspace/cow 我有一个源目录 (src),其中包含 cow.f90(程序)和两个模块 m_graze 和 m_moo,分别位于 m_graze.f90 和 m_moo.f90 中。该项目正确构建和链接以创建可执行的“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。我想在sheep.f90 中“仅使用m_graze:反刍”来访问rumate() 子例程。我可以只复制 m_graze.f90 但这可能导致代码不同步并且没有考虑 m_graze 可能具有的任何依赖项。由于这些原因,我宁愿将 m_graze 留在牛项目中并针对它编译和链接sheep.f90。

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

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

在属性:羊的项目引用下,我可以选择牛项目。在 Properties:Fortran Build:Settings:Intel Compiler:Preprocessor 下,我可以将 ~/workspace/cow/Debug(模块文件的位置)添加到包含目录列表中,因此编译器现在可以找到 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 项目完全能够将cow.f90、m_graze.f90 和m_moo.f90 编译并链接到一个可执行文件中。然而,虽然sheep 项目可以编译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 链接到 LAPACK95 的 MKL 版本),IDE 或工具链可能缺乏足够的自动或用户界面设施来共享单个规范集源文件是一种可行的策略。选择似乎是冒着重复源文件不同步的风险,放弃 IDE 的许多好处(即避免手动创建 make/CMake/SCons 文件),或者很可能两者兼而有之。虽然修订控制系统和良好的代码组织可以提供帮助,但很明显,鉴于 Eclipse 的当前状态,在项目之间共享单个规范的源文件集绝非易事。

【问题讨论】:

  • 你在哪里链接m_graze.o
  • 这似乎是关键。我没有明确地与 m_graze.o 链接,而且 Photran 和链接器似乎都没有办法让这变得容易,特别是如果 m_graze 有很多依赖项。不确定是否有办法告诉链接器“在此处查找 *.o 文件并根据您的需要进行链接”,或者您是否必须明确列出每个依赖项。如果是后者,就显得非常乏味了。
  • 我无法帮助您处理 Photran 项目,但我可以推荐您使用 SCons 而不是 make。它对 Fortran 的支持非常好,而且比make 更容易调整。它会自动进行依赖分析。
  • 我不确定问题是什么。您需要在链接阶段明确提供目标文件。如果目标文件太多,请将它们放入库中(.a.so)。这部分与 C 无关。库只是目标文件的容器。这是我通常为我的 Fortran 程序 + make 所做的。 SCons也不错。

标签: module linker fortran intel-fortran photran


【解决方案1】:

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

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

第二个错误是因为链接器没有被告知目标代码实现了模块源文件中的内容。我无论如何都不是 Eclipse 用户,而是一种蛮力的指定方式,即添加目标文件 (xxxxx/Debug/m_graze.o) 作为附加链接器选项(Fortran Build > Settings,在 Intel Fortran Linker > Command Line 下) . (其他工具链在其链接阶段具有明确的“附加对象文件”属性 - 对于英特尔链,可能有更好的方法。)

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

【讨论】:

  • 对,所以类比.mod文件充当C头文件,描述中间代码(目标文件和库)的调用接口。
  • 与 C 头文件更好的类比是包含该模块的 Fortran 源代码。编译器从中生成 .mod 文件并使用它来“完成工作”,例如检查调用和实际过程之间的参数一致性。 .mod 文件是特定于编译器的,甚至可以随编译器版本而改变……与创建它们的源代码不同。 .mod 文件超出了语言标准。
  • 谢谢;这解释了 .mod 文件缺乏一般文档。在尝试解决这个问题的过程中,我学到了很多东西,但对于可靠的软件开发来说,这些都不是好兆头。似乎没有什么好的方法可以避免在 Eclipse(或任何 IDE)中复制源文件。:/
  • 我不了解 IDE 方面。我在几个项目之间使用 Fortran 模块,并且不复制源代码文件。我只是让几个编译命令使用同一个文件。几个项目使用的C头文件怎么办?
  • 无需复制源代码,甚至无需编译步骤。您只需提供对包含 mod 文件的目录的引用和对目标文件的引用。如果您有多个目标文件,那么将它们捆绑在一个库中可以简化此操作。 mod 文件在某种程度上等同于 C 中的预编译头文件。
【解决方案2】:

是的,必须提供目标代码。例如,当您在 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 文件只能由发行版 (apt-get install gfortran) 附带的 gfortran 使用。如果您想使用任何其他编译器(甚至是您自己安装的不同版本),那么您必须使用该特定编译器自己构建 netcdf。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2014-10-21
    相关资源
    最近更新 更多