4

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

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

这是一个简单的示例:在 ~/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。

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

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 的形式)或静态共享库。.mod 文件描述了目标代码/库的接口,但两者都是构建最终可执行文件所必需的。

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

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

4

2 回答 2

4

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

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

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

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

于 2013-05-03T21:04:26.287 回答
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 文件只能由发行版 ( apt-get install gfortran) 附带的 gfortran 使用。如果您想使用任何其他编译器(甚至是您自己安装的不同版本),那么您必须使用该特定编译器自己构建 netcdf。

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

于 2013-05-04T12:18:26.133 回答