Is ISO_Fortran_binding.h compatible for different Fortran ABIs?

Using Fortran2008/C intercompatibility via bind(c) does allow Fortran libraries to export APIs with the same ABI compatibility as available in C. Now with the ISO_Fortran_binding.h we get another possibility to define Fortran compatible C-APIs, while in principle useful. The question is whether it also guarantees ABI compatibility.

Looking into the ISO_Fortran_binding.h defined by different compilers shows discrepancies, like for the CFI_dim_t, GCC defines

typedef struct CFI_dim_t
  {
    CFI_index_t lower_bound;
    CFI_index_t extent;
    CFI_index_t sm;
  }
CFI_dim_t;

While in Intel Fortran you find

typedef struct CFI_dim_t_
{
    CFI_index_t     extent;
    CFI_index_t     sm;
    CFI_index_t     lower_bound;
} CFI_dim_t;

And LLVM flang is compatible with GCC here

/* 18.5.2 per-dimension information */
typedef struct CFI_dim_t {
  CFI_index_t lower_bound;
  CFI_index_t extent; /* == -1 for assumed size */
  CFI_index_t sm; /* memory stride in bytes */
} CFI_dim_t;

Nag’s declaration is compatible with Intel

typedef struct {
  CFI_index_t extent,sm,lower_bound;
} CFI_dim_t;

With this in mind, can we actually define portable Fortran/C ABIs using ISO_Fortran_binding.h?

6 Likes

To quote from Sec. 21.5.5 in MRC: “For each dimension, the structure members are, in any order:” (bold typesetting by me). And also about the C-descriptor itself in Sec. 12.5.1: “The exact contents of the structure are processor dependent, though some members are fully standardized.”

So, it won’t work with ABI compatibility when using different Fortran compilers. But if you wish to look at the bright side of it, it is absolutely consistent with, how it currently works (or to be more precises, how it currently does not work) between Fortran components compiled with different Fortran compilers. Why should the C/Fortran interface be easier to handle than the Fortran/Fortran interface. :wink:

3 Likes

Too bad, at least for me this makes the ISO_Fortran_binding.h look like a step back when interfacing to C. For module files Fortran compilers usually choke on modules produced by other vendors, yet a C compiler will happily compile against any ISO_Fortran_binding.h found somewhere in the include path and maybe horribly fail at runtime. There are a few macros around which could help detect this on the C side, however those won’t be available on the Fortran side.

4 Likes

Given that Fortran object files are not compatible across different Fortran compilers, in that they each have their own conventions for language library calls, internal use descriptors and more, there isn’t anything to be gained by making the C interoperability ABI cross-compatible. The CFI routines have the ability to check that a C descriptor was created in a compatible fashion (ifort does), but this is not required.

I took a long look at trying to come up with a way of finessing this but gave it up as unworkable. I recognize that it would be great to be able to supply precompiled Fortran modules and libraries that work with any Fortran compiler, but it’s not going to happen.

4 Likes

If I understand this correctly, any C library which attempts to provide a “native” Fortran interface using the CFI routines, should be compiled with the companion C processor of the Fortran compiler in use?

At the Intel Development Reference I’ve found:

For Intel® Fortran, the supported C companion is the Intel® C++ Compiler or the Microsoft* Visual C++* Compiler on Windows*, and the Intel® C++ Compiler or gcc* on Linux* and macOS*

This would seem to imply that Intel Fortran programs could also work with C libraries compiled with gcc? In this case, which header file should gcc target?
.

1 Like

The C compiler can generate the correct ABI if the corresponding ISO_Fortran_binding.h is used. In case Intel Fortran is correctly setup the include directory of the Intel compilers should be in the CPATH environment variable and therefore prefer the ISO_Fortran_binding.h of Intel Fortran over the GFortran one.

However, you have to be careful about your environment and include paths, if the build of the Fortran and C side are separated, an incorrect ABI could be generated if the wrong header is picked up. It helps to detect some compiler specific extensions from the ISO_Fortran_header.h in your build system to ensure the Fortran and C side actually match.

2 Likes

Checking the latest GCC version, the CFI_dim_t descriptor is still compatible with 11.1, which I’m using on my machine at the moment.

Still holding back with the yearly compiler update on my machine. From what I heard about GCC 12 and the new Intel oneAPI release I’m really looking forward to upgrade, unfortunately my laptop is not powerful enough to actually compile GCC or flang, making it hard to use experimental versions more frequently :cry: (I really have to consider this when buying a new one next time).

1 Like

What matters is that the C library is built using the ISO_Fortran_binding.h of the Fortran compiler to be used when building the whole application. The compatibility issue is entirely on the Fortran side. It’s not just the C descriptor layout, but what is behind the CFI_xxx function definitions in the .h - these can be macros and will end up being references to routines in the appropriate Fortran compiler’s run-time library.

If it were just the C descriptor, that could be finessed. But I was unable to think of a way to work around the function references.

1 Like

Naive question: Couldn’t the standard require, that all CFI_xxx functions are indeed functions (no macros) with a standardized C-interoperable API. And additionally, that the C descriptors must have one additional pointer field (at a defined position in the struct), which can point to any additional data a given compiler implementation may require beyond the information stored in the standardized fields. The data it points to could be processor dependent, of course, but on the C-side, it would be still ABI compatible. (Unless I have overseen something…)

5 Likes

@aradi, yes, it could have been done that way, but wasn’t. Sadly, this issue never came up in the years that the feature was developed and reviewed. There was added a “version” component to the descriptor that at least allowed an implementation to say, “that’s not mine!”

Going forward, would it be possible to amend the ISO_Fortran_binding.h specification in the standard or is this a too fundamental breaking change? Would there be a realistic chance to consider ABI compatibility in the CFI_* interface in a future revision of the standard?

I opened a thread at the incubator repository for this purpose (see fortran_proposals#247), in case we want to move the discussion there.

3 Likes

@awvwgk thanks for opening up the issue at the proposals repository and for pushing this. If it turns out it is not possible (or feasible) to do, then let’s document this why, at the issue.

My understanding of this is that the CFI_* interface is not typically the interface the compilers use internally, at least that was my understanding of GFortran. Is that correct? If so, then it means it is in some sense a “wrapper”, the compiler has to specifically generate this interface. Just like for a bind(c) procedure, the compiler must generate a specific ABI interface, but without bind(c) it is my understanding that the compiler is free to represent the procedure any way it likes.

How big of a performance hit is to convert the array descriptor to the CFI_* interface?

Presumably the idea is that if performance matters, one should stay in Fortran. And the bind(c) interface is to be used to wrap the functionality to other languages (such as Python, Julia, …) in which case a slight overhead is not a big deal.

1 Like

There are three things that would be needed to allow distribution of C code libraries that can work with any Fortran compiler.

First is to define a new layout for a C descriptor that completely specified the layout and ordering. This would somehow have to be distinguishable from the F2018 (TS29113) format. There is a version field, but that is implementation dependent.

Second is to specify a new module with each CFI routine having a known C prototype.

Third is that compilers would need the ability to generate and recognize both the old and new descriptor formats. Some compilers might use the standard’s C descriptor internally, some might not (ifort does not).

Given all this, the question is: “Does the benefit make it worth the pain?” Without this change, you have to rebuild the C library from source - something already very common. I expect it would be a hard sell.

4 Likes

One place where you might need to pay attention to this issue is if you are calling exported Chapel functions from Fortran, see “Using Your Library in Fortran” in Exporting Chapel as a Library.

For my purposes, ISO_Fortran_binding.h is major step forward. I’ve been attempting to wrap a C library in a Fortran interface that can accept any type, kind, and rank. I started of with Fortran procedure interfaces that have assumed-rank, unlimited polymorphic arguments. That necessitated procedure definitions that handle the proverbial combinatorial explosion of types, kinds, and ranks with select type and select rank blocks. Just yesterday, a collaborator suggested that I switch from unlimited-polymorphic/assumed-rank arguments to assumed-type/assumed-rank arguments, which then enables me to write very simple C wrappers for the C library and the C wrappers can get all of the type/kind/rank information from the C descriptor. With this strategy, I was able to shrink one file from over 400 lines to under 40 lines and I expect/hope to achieve similar savings throughout my code. I’m feeling very pleased with CFI_cdesc_t right now! :slight_smile:

6 Likes

I agree with Steve’s point above and share the view that reconciling Fortran ABIs is impossible. However, I don’t think the situation is as bad as some suggest. CFI standardizes a bidirectional protocol with C, which means that one can use a C bridge between two Fortran compilers.

In short, Fortran can call C libraries that happen to be implemented in Fortran but are compiled by a different compiler, as long as one has a C bridge that contains O(num_fortran_compilers^2) worth of CFI glue. It is tedious to implement, but only needs to be done once. The application needs Fortran interfaces for the C library it’s calling too, but libraries can provide these.

I wrote about this a bit on my blog:

5 Likes