GNU Fortran 和 C 的互操作性

5

我有一个大型的混合C/Fortran代码库,目前在Windows上使用Intel工具进行编译。现在被要求将其迁移到GNU工具,在Linux上进行编译。我随意选择了版本4.8。

当从Fortran中调用C函数时,互操作性通常如下所示:

// C code:
void PRINTSTR(char *str, size_t len) {
    for(int ii = 0; ii < len; ii++) {
        putchar(str[ii]);
    }
    putchar('\n');
}

!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end

英特尔 Fortran 编译器总是生成大写符号,因此可以正常工作。但 GNU Fortran 编译器总是生成小写符号,因此会出现链接错误。
GNU Fortran 编译器曾经有一个名为“-fcase-upper”的选项,使其生成大写符号,但似乎这个选项对于每个人来说都过于可配置了,并已被删除(我不确定是何时)。
可以使用“ISO_C_BINDING”功能来强制编译器生成区分大小写的名称:
program test
interface
subroutine printstr(str) bind(C, name='PRINTSTR')
character :: str(*)
end subroutine
end interface

call printstr("Hello, world.")
end

这解决了链接错误,但它改变了字符串参数的处理方式;不再提供长度参数。所以要使用此方法,我不仅需要为每个当前采用这种方式的函数添加接口定义,还需要更改每个调用该函数的字符串处理方式,确保所有字符串都是以空字符结尾。
我可以通过将所有这样的函数转换为小写来解决问题,但是因为Intel编译器仍然生成大写符号,所以这将破坏现有的构建。
由于有大约2000个这样的函数,看起来这似乎是一项难以实现的工作。那么,我的问题是:如何在不改变函数调用语义和不使用Intel编译器破坏现有构建的情况下解决链接错误?

我担心你将面临一个相当大的问题,那就是Intel将长度传递为size_t,而GFortran使用int。在32位系统上这没问题,但在64位系统上传递多个字符串时会出现严重错误,而且链接器甚至无法捕获到这个错误。 - Tristan Brindle
我认为,纯粹是运气好,我逃脱了那个问题。这个Intel版本是32位的。 - Tom
我认为(可能)具有“-fcase-upper”选项的编译器是g95,而不是现在官方的GNU Fortran编译器GFortran。据我所知,g95仍在开发中,尽管速度比GFortran慢,但如果您的代码库纯粹是F77 / F95并且不使用尖端的F2003 / F2008功能,则值得研究一下? - Tristan Brindle
这些确实是从Fortran到C的~2000个不同函数接口吗?还是这些只是调用几个具有不同参数的函数?在后一种情况下,您可以编写一些包装器,为您附加C_NULL_CHAR - Stefan
仔细观察后,我(数千个)链接器问题中的许多与此无关。有244个不同的函数从Fortran接口到C,被调用410次。所以它不是2,000,但修复所有这些问题也不是一项微不足道的工作。 - Tom
1个回答

2
为解决链接器错误,您可以采取另一种方法。使用英特尔编译器选项 names 将外部名称转换为小写以匹配默认的 GNU Fortran 选项。并且也将 中的名称转换为小写:
void printstr(char *str, size_t len) {...}

个人建议使用-funderscoring和英特尔的/assume:underscore来区分旨在实现互操作性的函数。
// C code:
void printstr_(char *str, size_t len) {...}

!Fortran code:
program test
implicit none
call printstr("Hello, world.")
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接