Automated Fortran--C++ Bindings for Large-Scale Scientific Applications
Seth R. Johnson, Andrey Prokopenko, Katherine J. Evans

TL;DR
This paper presents an automated tool that generates native Fortran 2003 interfaces for C and C++ libraries, simplifying integration in large-scale scientific applications with minimal performance overhead.
Contribution
The introduced tool automatically creates Fortran bindings for C/C++ libraries, supporting complex C++ features like templates and exceptions, which was previously challenging.
Findings
The tool successfully generates Fortran interfaces for complex C++ features.
Timing measurements show minimal performance impact.
Examples demonstrate broad utility and scope of the tool.
Abstract
Although many active scientific codes use modern Fortran, most contemporary scientific software "libraries" are implemented in C and C++. Providing their numerical, algorithmic, or data management features to Fortran codes requires writing and maintaining substantial amounts of glue code. This article introduces a tool that automatically generates native Fortran 2003 interfaces to C and C++ libraries. The tool supports C++ features that have no direct Fortran analog, such as templated functions and exceptions. A set of simple examples demonstrate the utility and scope of the tool, and timing measurements with a mock numerical library illustrate the minimal performance impact of the generated wrapper code.
| Feature | Status |
|---|---|
| Data type conversion | ✓ |
| Fundamental types | ✓ |
| C strings | ✓ |
| Pointers and references | ✓ |
| Function pointers, member function pointers | ✓ |
| POD structs | ✓ |
| Arrays | ✶ |
| Shared pointers | ✓ |
| std::string | ✓ |
| std::vector | ✓ |
| thrust::device_ptr | ✓ |
| Other standard library containers | ✶ |
| Functions | ✓ |
| Default arguments | ✓ |
| Overloading | ✶ |
| Operator overloading | ✗ |
| Templates | ✓ |
| Classes | ✓ |
| Member data | ✓ |
| Inheritance | ✶ |
| Multiple inheritance | ✗ |
| Constants | ✓ |
| Enumerations | ✓ |
| Compile-time constants | ✓ |
| Exceptions | ✓ |
| Time (s) for | ||||
|---|---|---|---|---|
| Implementation | ||||
| Native Fortran quicksort | 0.0011 | 0.0104 | 0.1132 | 1.3058 |
| Wrapped C++ std::sort | 0.0008 | 0.0074 | 0.0877 | 1.0189 |
| Interface | Standard | LTO | LTO (null pointer check) | ||
|---|---|---|---|---|---|
| Library only | All | Library only | All | ||
| Matrix (coarse) | 0.095 | 0.095 | 0.076 | 0.095 | 0.077 |
| Row (intermediate) | 0.184 | 0.162 | 0.067 | 0.158 | 0.163 |
| Element (fine) | 0.684 | 0.505 | 0.215 | 0.531 | 0.325 |
Peer Reviews
No public reviews on file for this paper yet. If you reviewed it on a platform where reviews are public (OpenReview, ICLR, NeurIPS, ICML), you can paste yours below so the community can read it here.
Videos
No videos yet. Explain this paper in a talk, walkthrough, or lecture? Add one.
Automated Fortran–C++ Bindings
for Large-Scale Scientific Applications
Seth R. Johnson, Andrey Prokopenko, and Katherine J. Evans This manuscript has been authored by UT–Battelle, LLC, under Contract No. DE-AC05-00OR22725 with the U.S. Department of Energy. The United States Government retains and the publisher, by accepting the article for publication, acknowledges that the United States Government retains a non-exclusive, paid-up, irrevocable, world-wide license to publish or reproduce the published form of this manuscript, or allow others to do so, for United States Government purposes.
Abstract
Although many active scientific codes use modern Fortran, most contemporary scientific software libraries are implemented in C and C++. Providing their numerical, algorithmic, or data management features to Fortran codes requires writing and maintaining substantial amounts of glue code.
This article introduces a tool that automatically generates native Fortran 2003 interfaces to C and C++ libraries. The tool supports C++ features that have no direct Fortran analog, such as templated functions and exceptions. A set of simple examples demonstrate the utility and scope of the tool, and timing measurements with a mock numerical library illustrate the minimal performance impact of the generated wrapper code.
Index Terms:
Software Interoperability, Scientific Codes, Software Reusability, Fortran, C++, SWIG
I Introduction
Fortran has a long history in scientific programming and is still in common use today [1] in application codes for climate science [2], weather forecasting [3], chemical looping reactors [4], plasma physics, and other fields. As a domain-specific language for scientific computing, Fortran enables modernization and improvement of application codes by the publication of new standards specifications that define new features and intrinsic functions. Unfortunately, these specifications take years to become available to Fortran users: as of 2018, only six of eleven surveyed compilers fully implement even half of Fortran 2008’s new features [5]. Another approach to language extensibility is the distribution of libraries, which can be developed and deployed much more rapidly than compilers. However, most contemporary compiled-language scientific and computing libraries are written in C and C++, and their capabilities are either unavailable to Fortran users or exposed through fragile C interface code. Providing Fortran application developers with robust bindings to high-performance C++ libraries will substantially and rapidly enrich their toolset.
As available computing power increases, more scientific codes are improving their simulations’ fidelity by incorporating additional physics. Often multiphysics codes rely on disparate pieces of scientific software written in multiple programming languages. Increasingly complex simulations require improved multi-language interoperability. Furthermore, the drive to exascale scientific computing motivates the replacement of custom numerical solvers in Fortran application code with modern solvers, particularly those with support for distributed-memory parallelism and device/host architectures.
The increasing necessity for robust, low-maintenance Fortran bindings—for multi-language application developers and scientific library authors—demands a new tool for coupling Fortran applications to existing C and C++ code. This article introduces such a tool, implemented as a new extension to the Simplified Wrapper and Interface Generator (SWIG) tool [6]. A set of simple examples demonstrate the utility and scope of SWIG-Fortran, and timing measurements with a mock numerical library illustrate the minimal performance impact of the generated wrapper code.
II Background
For decades, Fortran application developers and domain scientists have required capabilities that can only be implemented in a systems programming language such as C. The MPI specification, which declares both C and Fortran interfaces, provides a clear example: the MPICH implementation was written in C and to this day uses a custom tool to automate the generation of a Fortran interface and the underlying C binding routines [7].
Over the years, many attempts have been made to build a generic tool to generate Fortran bindings to existing C C++ code. Early efforts explored manual generation of encapsulated proxy Fortran interfaces to C++ classes using Fortran 95 [8]. Some C scientific libraries such as Silo, HDF5, and PETSc include custom tools to generate Fortran from their own header files. Most of these tools use non-portable means to bind the languages with the help of configuration scripts, because they were initially developed before widespread support for the Fortran 2003 standard [9], which added features for standardized interoperability with ISO C code.
Some newer software projects, such as the first iteration of a Fortran interface [10] to the Trilinos [11] numerical library that motivated this work, use Fortran 2003 features but are limited to manually generated C interfaces to C++ code, with hand-written Fortran shadow interfaces layered on those interfaces. The Babel tool [12] can automatically generate data structures and glue code for numerous languages (including C++ and Fortran 2003) from a custom interface description language, but it is suited for data interoperability in a polyglot application rather than for exposing existing C and C++ interfaces to Fortran.
Any practical code generation tool must be able to parse and interact with advanced language features, such as C++ templates which are critical to today’s parallel scientific libraries. The advent of GPU accelerators further complicates inter-language translation by the data sharing imposed by its device/host dichotomy. The maturity and flexibility of SWIG allows us to address these and other emergent concerns in a generic tool for generating high-performance, modern Fortran interfaces from existing C and C++ library header files with minimal effort from the C++ library developers and no effort on the downstream Fortran application developers.
III Methodology
The core functionality of SWIG is to parse library header files and generate C-linkage wrapper interfaces to each function. It composes these interfaces out of small code snippets called “typemaps,” responsible for converting a type in C++ to a different representation of that type in a target language. The new Fortran target language comprises a library of these typemaps and a C++ “language module” compiled into the SWIG executable.
SWIG generates wrappers only for code specified in an interface file, which can direct SWIG to process specified C and C++ header files. The interface file also informs SWIG of additional type conversions and code transformations to be made to the modules, procedures, or classes to be wrapped. Each invocation of SWIG-Fortran with an interface file creates two source files: a C++ file with C-linkage wrapper code that calls the C++ libraries, and a Fortran module file that calls the C-linkage wrapper code (Fig. 1).
These generated source files must be compiled and linked together against the C++ library being wrapped, and the resulting Fortran module can be directly used by downstream user code. The generated files can be included in a C++ library distribution without requiring library users or application developers to install or even have any knowledge of SWIG.
As SWIG processes an interface file (or a header file referenced by that file), it encounters C and C++ declarations that may generate several pieces of code. Functions, classes, enumerations, and other declarations generate user-facing Fortran equivalents and the private wrappers that transform data to pass it between the Fortran user and the C++ library. These type-mapping transformations are enabled by the Fortran 2003 standard, which mandates a set of interoperable data types between ISO C and Fortran, defined in the ISO_C_BINDING intrinsic module.
III-A Type conversions
SWIG-Fortran can pass all ISO C compatible data types between C++ and Fortran without copying or transforming the data. Additional typemaps included with the SWIG library provide transformations between C++ types and Fortran types that are analogous but not directly compatible. These advanced type transformation routines shield Fortran application users from the complexities of inter-language translation.
Consider the character string, which for decades has complicated C/Fortran binding due to its different representation by the two languages. The size of a C string is determined by counting the number of characters until a null terminator \0 is encountered, but Fortran string sizes are fixed at allocation. The Fortran ISO C binding rules prohibit Fortran strings from being directly passed to C; instead, SWIG-Fortran injects code to convert a string to a zero-terminated array of characters, which can interact with C. A small C-bound struct containing the array’s length and the address of its initial element is passed to the C++ wrapper code, which then can instantiate a std::string or pass a char* pointer to the C/C++ library. Returning a string from C++ similarly passes a pointer and length through the C wrapper layer. The Fortran wrapper code creates an allocatable character array of the correct size, copies in the data from the character array, and frees the C pointer if necessary. Thus, C/C++ library routines that accept or return strings can be called using native types familiar to the Fortran user without any knowledge of null terminators.
Another notable scalar type conversion defined by SWIG-Fortran is boolean value translation. In C and C++, the bool type is defined to be true if nonzero and false if zero, whereas Fortran logical values are defined to be true if the least significant bit is 1 and false otherwise. The automated wrapper generation frees developers from having to understand that the value 2 may be true in C but false in Fortran.
Finally, the SWIG typemap system also allows multiple C++ function arguments to be converted to a single argument in the target language. This allows a multi-argument C++ function
to generate a Fortran function that accepts a native Fortran array:
by creating temporary arguments using the intrinsic Fortran SIZE and C_LOC functions.
Advanced typemaps can be constructed to perform other transformations on the input to facilitate the translation of C++ APIs into forms familiar to Fortran application developers. For example, the wrappers may increment input parameters by 1 so that library users can continue using the idiomatic 1-offset indexing of Fortran rather than counting from 0 as in C++.
III-B Functions
Functions in C/C++ are procedures in Fortran. A function in C/C++ with a void return value will translate to a subroutine in Fortran, and a function returning anything else will yield a Fortran function.
Each function processed by SWIG-Fortran generates a single C-linkage shim function in the C++ file. This thin wrapper converts the function’s arguments from Fortran- and C-compatible datatypes to the function’s actual C++ argument types, calls the function, and converts the result back to a Fortran-compatible datatype. The wrapper function also implements other optional features such as exception handling and input validation.
In the corresponding .f90 module file, SWIG-Fortran generates a private, bind(C)-qualified declaration of the C wrapper in an INTERFACE block. This interface is called by a public Fortran shim procedure that translates native Fortran datatypes to and from the C interface datatypes. Figure 2 demonstrates the control flow for a Fortran user calling a C++ library function through the SWIG-generated module and wrapper code.
If a function is overloaded, SWIG-Fortran generates a unique, private Fortran shim procedure for each overload. These procedures are then combined under a separate module procedure that is given a public interface with the original function’s name. For example, an overloaded free function myfunc in C++ will generate two private procedures and add an interface to the module specification:
Since Fortran does not allow a module procedure or generic interface to contain both functions (which return an object) and subroutines (which return nothing), SWIG-Fortran detects, ignores, and warns about such incompatible overloaded C++ functions, e.g.,
Templated functions are supported, but since the wrapper code is generated without any knowledge of the downstream Fortran user’s code, each template instantiation must be explicitly specified in the SWIG interface file:
The two instantiated subroutines can be called from user Fortran code on integers and single-precision floating-point values, but since the example does not instantiate on bool, the user’s Fortran code cannot call do_it with a logical argument. Note that the chosen names for template instantiations (do_it_int and do_it_real) have no bearing on the way they are being called from a Fortran code, which is through the original do_it name.
The restriction of SWIG-time instantiation may be particularly limiting for library functions that accept generic functors, including the C++11 lambda functions that are crucial to programming models such as Kokkos and RAJA. However, SWIG’s support for function pointer conversion does enable some flexibility for user codes. Instantiating a function template using a function pointer as the predicate operator allows the function to be used with arbitrary functions with a fixed type signature:
This instantiated compare function can be used in Fortran with an arbitrary comparator that accepts integer arguments:
if the user has defined a function such as
This limited capability for inversion of control (i.e., C++ library code calling Fortran application code) will be extended and documented in future work.
III-C Automated class generation
Like the thin wrappers generated for procedures, SWIG also creates thin proxy wrappers for C++ classes. Here, each Fortran derived type mirrors a C++ class, contains type-bound procedures that mirror C++ member functions, and stores a pointer to the C++ class with memory management flags. Its assignment and memory management semantics mimic that of an allocatable Fortran pointer. SWIG supports single inheritance by generating a derived type with the EXTENDS attribute, so functions accepting a class(Base) argument will also accept a class(Derived).
Proxy types are instantiated via a module interface function that shares the name of the derived type, giving construction the same syntax as in other high-level languages and in other modern Fortran idioms [13]. Instances are nullified (and deallocated if owned) by calling the release procedure.
The same proxy type can be used as an interface to a C++ class pointer, const reference, or value; and it must be able to correctly transfer ownership during assignment or when being returned from a wrapped C++ function. To support this variety of similar but distinct use cases in a single instance of a Fortran type, the proxy type stores a bit field of flags alongside the pointer to the C++ object. One bit denotes ownership, another marks the instance as a C++ rvalue, and the third bit is set if the instance is const. The rvalue bit is set only when returning a value from a function. A custom Fortran assignment(=) generic function transfers ownership when this bit is set.
The following block of code demonstrates the assignment semantics; it neither leaks nor double-deletes memory.
In line 2, a new temporary Foo object is created and returned with the rvalue and own flags. The assignment operation in line 2 transfers ownership from that temporary object and assigns it to the owner instance, replacing the initial value of a null C pointer, and clearing the rvalue flag. Line 3 creates another object, but when the SWIG-generated assignment operator is called, it first deletes the original Foo object before capturing the new one. Without the special assignment operator, memory would be leaked. The next assignment (line 4) copies the underlying C pointer but not the memory flag, so that alias is a non-owning pointer to the same object as owner. Line 5 clears the pointer but does not call any destructor because it did not own the memory. The final line actually destroys the underlying object because its ownership flag is set.
This methodology is an alternative to implementing the Fortran proxy type as a shared pointer that relies on the Fortran FINAL feature [13]. This feature is intentionally avoided because it is not implemented (or buggy) in some recent compilers, sixteen years after the specification of Fortran 2003 [5].
III-D Exception handling
Since Fortran has no exception handling, any uncaught C++ exception from a wrapped library call will immediately terminate the program. With SWIG’s %exception feature, C++ exceptions can be caught and handled by the Fortran code by setting and clearing an integer flag. For example, assuming that one wants to use a conservative square root function careful_sqrt that throws an exception when a given number is non-positive, the Fortran code could look like this:
where ierr is a nonzero error code, and get_serr() returns a string containing the exception message. This approach allows Fortran code to gracefully recover from exception-safe C++ code. For example, if a C++ numeric solver throws an error if it fails to converge, the Fortran application would be able to detect the failure, print a message, and write the unconverged solution.
III-E HPC-oriented features
The SWIG Fortran target language is able to wrap CUDA kernels using the Thrust C++ interface and use the resulting code with Fortran OpenACC kernels. The implementation is designed to avoid the performance penalty of copying between the host and device inside the wrapper layer: the underlying device data pointer is seamlessly handed off between C++/CUDA and Fortran.
Here is an example SWIG module that wraps the thrust::sort function to enable sorting on-device data using a highly optimized kernel:
The corresponding test code simply calls the SWIG-generated sort function:
Note that the ACC data copy occurs before the native Fortran ACC kernel and after the SWIG-wrapped Thrust kernel, demonstrating that the interoperability of the Fortran and C++ data requires no data movement.
SWIG also supports automatic conversion of MPI communicator handles between the Fortran mpi module and MPI’s C API by generating wrapper code that calls MPI_Comm_f2c. The SWIG interface code
will generate a wrapper function that can be called from Fortran using the standard mpi module and its communicator handles:
III-F Direct C binding
A special %fortranbindc directive in SWIG-Fortran will bypass wrapper function generation and instead build direct bind(C) public function interfaces in the Fortran module for C-linkage functions. A similar macro, %fortranbindc_type, will generate bind(C) derived types in Fortran from C-compatible structs, with no wrapper code. Another directive %fortranconst will generate parameter-qualified Fortran constants from #define macros, and SWIG will further generate Fortran C-bound enumerations from C enum types.
III-G Language features
The SWIG Fortran module maps many other C++ capabilities to Fortran. Table I lists features supported by SWIG and their implementation status in the Fortran module. SWIG currently has only limited support for C++11 features, so these are omitted from the table.
IV Applications
This section contains two examples of the capabilities outlined in the previous section and a discussion of their performance: (i) wrapping a standard C++ library sort function, and (ii) accessing a sparse matrix-vector multiplication computational kernel through a generated interface with performance discussion.
IV-A Sorting
Sorting arrays is a common operation in problem setup and data mapping routines, and the C++ standard library provides generic algorithms for efficient sorting in its <algorithm> header. In contrast, Fortran application developers must choose a sorting algorithm and implement it by hand for each data type, an approach with many shortcomings. Application developers must understand that a naive sorting algorithm that works well for desktop-sized problems may not be performant for exascale-sized problems. Manually implementing a robust version of a sorting algorithm is also notoriously error-prone. Finally, having to instantiate the implemented algorithm for each data type increases development and maintenance cost.
Using an externally supplied, efficient, and well-tested algorithm is clearly a better approach. The following self-contained SWIG interface wraps the C++-supplied sort implementation into a generic Fortran subroutine that operates on either integer or real Fortran arrays:
The first line declares the name of the resulting Fortran module. Lines 2–4 insert the standard library include into the generated C++ wrapper code, and the following %inline block both inserts the code into the wrapper and declares it to SWIG. Lines 11–14 inform SWIG that a special predefined typemap (which treats two C++ pointer/size arguments as a single Fortran array pointer argument; see §III-A) should be applied to the function signature of the declared sort function. The final two lines direct SWIG to instantiate the sort function for both integer and double-precision types.
Fortran application developers need not understand or even see any of the above code; they merely link against the compiled SWIG-generated files and use the wrapped function as follows:
A developer might wonder whether using C++ instead of Fortran for a numeric algorithm will slow their code, so Table II compares the performance of two Fortran codes that sort an array of random real numbers. The first code implements a standard Fortran quicksort numerical recipe [14], and the second calls the SWIG-wrapped C++ function. Both experiments were compiled using GCC 7.3.0 and run on a Intel Xeon E5-2620 v4 workstation, and the timings were averaged across 40 runs to remove variability.
The external C++ sort actually outperforms the native Fortran implementation, likely due to its algorithmic implementation: the standard C++ std::sort function uses introsort, which has the algorithmic strengths of both heapsort and quicksort [15], but is more lengthy to describe and implement. Yet with SWIG-Fortran, “implementing” the advanced algorithm is far easier still.
IV-B Sparse matrix multiplication
The sparse matrix–vector multiplication (SpMV) algorithm is a well-known computational kernel commonly used in linear algebra. Sparse matrices, which have relatively few nonzero elements, are typically stored and operated upon as memory-efficient formats such as compressed row storage (CRS) [16]. In CRS format, a matrix with nonzero entries and rows is stored in three arrays. The first two, vals and col_inds, each have elements: the values and column indices, respectively, of each nonzero matrix entry. A third length- array, row_ptrs, comprises the offset of the first nonzero entry in each row of the matrix.
With CRS, the sparse matrix-vector multiplication algorithm consists of two nested loops:
For the SWIG-wrapped SpMV algorithm, the data associated with the matrix is stored in a C++ class and accessed through a Fortran interface. To analyze the performance, three interfaces with different access granularity are considered. The coarsest provides access to the full matrix, i.e. three arrays containing the sparse structure. The intermediate-granularity interface returns a single row of nonzero entries for each call, and the finest interface provides functions to access individual elements in the matrix. The three granularities require different numbers of calls to the SWIG interface: the matrix-granularity interface calls C++ only three times total, the row-level interface calls C++ twice per matrix row, and the finest calls it twice per nonzero matrix entry.
This example uses a simple 2D Laplacian matrix corresponding to a discretization of the Poisson equation on a 2D Cartesian grid. Such a matrix has 5 diagonals with gaps between diagonals and a main diagonal on , , [math], , and . The “Standard” column of Table III presents the SpMV execution timings results for .
As expected, the computational work increases with the number of calls to the wrapper, resulting in a factor of seven slowdown to go from the coarsest to the finest granularity. Since the compiler is unable to inline the C++ wrapper function into the Fortran application code, the optimizer must make unnecessarily conservative approximations that hurt performance. One workaround is to use link-time optimization (LTO) [17], which compiles user code into an intermediate representation (IR) rather than assembly code. The IR from multiple translation units, even from different languages, can be inlined and optimized together during the link stage.
In the case of a C++ library bundled with a SWIG-generated Fortran interface, LTO would be applied during the library’s installation to the original C++ code, the flattened C++ wrapper file, and the Fortran module file. However, if SWIG-generated code is part of an application, the Fortran user code could additionally be built with LTO as well. The “LTO” column of Table III compares the performance of the SpMV test code for these two hypothetical situations against the “standard” case of no LTO. Enabling LTO as a library improves performance modestly for the finest-grained case, but as part of an entire application toolchain it results in dramatic (3) performance improvements for the fine-grain interfaces.
Note that the benefits of LTO depend on the complexity of the generated wrapper code. Adding an assertion to check for null pointers reduced LTO-provided performance by a factor of 1.5–2, shown in the last column of Table III. Thus, the wrapper interface writer, who has a degree of control over the generated code, should consider the tradeoff between stability and performance.
V Conclusion
This article introduces a new, full-featured approach to generating modern Fortran interfaces to C++ code, allowing C++ library developers to easily expose their work’s functionality to Fortran application developers, and potentially improving the coupling between the two different languages in the same application. By leveraging the SWIG automation tool, it supports many C++ features critical to contemporary scientific software libraries, including inheritance, templates, and exceptions. Future work will demonstrate SWIG’s utility in exposing the Trilinos and SUNDIALS numerical libraries to pre-exascale Fortran application codes.
The developed software, examples, and performance code presented here are available under open-source licenses at https://github.com/swig-fortran.
Acknowledgments
This research was supported by the Exascale Computing Project (17-SC-20-SC), a joint project of the U.S. Department of Energy’s Office of Science and National Nuclear Security Administration, responsible for delivering a capable exascale ecosystem, including software, applications, and hardware technology, to support the nation’s exascale computing imperative.
This research used resources of the Oak Ridge Leadership Computing Facility at the Oak Ridge National Laboratory, which is supported by the Office of Science of the U.S. Department of Energy under Contract No. DE-AC05-00OR22725.
The reference list from the paper itself. Each links out to its DOI / PubMed record.
- 1[1] V. K. Decyk, C. D. Norton, and H. J. Gardner, “Why Fortran?” Computing in Science & Engineering , vol. 9, no. 4, pp. 68–71, 2007.
- 2[2] C. Golaz et al. , “The DOE E 3SM coupled model v 1: Overview and evaluation at standard resolution,” J. Adv. Mod. Earth Sys. , in revision.
- 3[3] K. D. Williams, C. M. Harris et al. , “The Met Office Global Coupled model 2.0 (GC 2) configuration,” Geosci. Model. Dev. , vol. 88, pp. 1509–1524, 2015.
- 4[4] T. Li, W. A. Rogers, M. Syamlal, J.-F. Dietiker, J. Musser, M. Shahnam, and S. Rabha, “The NETL M Fi X suite of multiphase flow models: a brief review and recent applications of M Fi X-TFM to fossil energy technologies,” Chemical Engineering Science , vol. 169, pp. 259–272, 2017.
- 5[5] I. D. Chivers and J. Sleightholme, “Compiler support for the Fortran 2003, 2008, TS 29113, and 2018 standards revision 24,” SIGPLAN Fortran Forum , vol. 37, no. 2, pp. 19–41, Aug. 2018. [Online]. Available: http://doi.acm.org/10.1145/3266145.3266148
- 6[6] D. M. Beazley, “Automated scientific software scripting with SWIG,” Future Generation Computer Systems , vol. 19, no. 5, pp. 599–609, 2003.
- 7[7] W. Gropp, E. Lusk, N. Doss, and A. Skjellum, “A high-performance, portable implementation of the MPI message passing interface standard,” Parallel Computing , vol. 22, no. 6, pp. 789–828, Sep. 1996. [Online]. Available: http://linkinghub.elsevier.com/retrieve/pii/0167819196000245
- 8[8] M. G. Gray, R. M. Roberts, and T. M. Evans, “Shadow-object interface between Fortran 95 and C++,” Computing in Science & Engineering , vol. 1, no. 2, pp. 63–70, Apr. 1999. [Online]. Available: http://ieeexplore.ieee.org/document/753048/
