6

I am looking for a minimal example of the FFI between these two languages, a very simple hello world of a Go program calling a Fortran library.

I want to emphasize I am not looking for external resources, recommendations, or a tutorial, only a minimal code snippet in golang, and the corresponding format in Fortran.

There are plenty of examples on this site of:

A Go -> Fortran example would be in line with these and useful for other developers.

Edit to address duplication claim

This question has an answer and the one linked to as this being a duplicate of does not. Closing and redirecting this question as a duplicate that is likely to be closed with -5 votes would not be useful to stackoverflow users, though both present a reasonable question.

Mittenchops
  • 18,633
  • 33
  • 128
  • 246
  • Possible duplicate of [Where are resources and examples of calling fortran from go?](https://stackoverflow.com/questions/53345803/where-are-resources-and-examples-of-calling-fortran-from-go) – talonmies Nov 18 '18 at 11:16
  • 1
    Doesn't help to link this to that as a dupe. This was answered (very well) and that was closed as being off-topic for stackoverflow. – Mittenchops Nov 18 '18 at 12:19

1 Answers1

8

cgo (https://golang.org/cmd/cgo/) seems to provide a functionality for calling C. So I've tried using it for calling Fortran (with go-1.11 + gfortran-8.2 on OSX10.11), which seems to be working for this simple program...

main.go:

package main

// #cgo LDFLAGS: mylib.o -L/usr/local/Cellar/gcc/8.2.0/lib/gcc/8 -lgfortran
// void hello();
// int  fort_mult( int );
// void array_test1 ( double*, int* );
// void array_test2_( double*, int* );
import "C"
import "fmt"

func main() {
    // print a message
    C.hello()

    // pass a value
    fmt.Println( "val = ", C.fort_mult( 10 ) )

    k := C.int( 777 )
    fmt.Println( "val = ", C.fort_mult( k ) )

    // pass an array
    a := []C.double {1, 2, 3, 4, 5.5555}
    n := C.int( len(a) )

    C.array_test1( &a[0], &n )  // pass addresses
    fmt.Println( a )

    C.array_test2_( &a[0], &n )  // no use of iso_c_binding
    fmt.Println( a )
}

mylib.f90:

subroutine hello() bind(C)
    print *, "Hello from Fortran"
end subroutine

function mult( x ) result( y ) bind(C,name="fort_mult")  ! can use a different name
    use iso_c_binding, only: c_int
    integer(c_int), value :: x
    integer(c_int) :: y

    y = x * 10
end function

subroutine array_test1( arr, n ) bind(C)   ! use iso_c_binding
    use iso_c_binding, only: c_int, c_double
    integer(c_int) :: n
    real(c_double) :: arr( n )

    arr(:) = arr(:) * 100.0d0
end subroutine

subroutine array_test2( arr, n ) ! no use of iso_c_binding (e.g. for legacy codes)
    integer :: n
    double precision :: arr( n )   ! or real(8) etc

    arr(:) = arr(:) * 2.0d0
end subroutine

Compile:

gfortran -c mylib.f90
go build main.go
./main

Result:

 Hello from Fortran
val =  100
val =  7770
[100 200 300 400 555.5500000000001]
[200 400 600 800 1111.1000000000001]
roygvib
  • 7,218
  • 2
  • 19
  • 36
  • 3
    My usual answer is: "If you can call C from language , you can call Fortran." (This doesn't extend to C++.) Fortran has extensive C interoperability features. The biggest hurdle, especially with non-compiled languages, is finding the mechanism to bind to compiled code. Once you have that, the rest is straightforward (you MUST stick to the C interoperability features, or else you can create headaches.) – Steve Lionel Nov 18 '18 at 15:38
  • That’s great and news to me: I expected something special would be necessary owing to array indexing column transposition or something. – Mittenchops Nov 18 '18 at 16:56
  • 3
    You certainly need to take array ordering into account, but that has no effect on doing the call. – Steve Lionel Nov 18 '18 at 21:12
  • @Steve Lionel, in this case, by “you MUST stick to the C interoperability features” you mean the “use iso_c_binding” example rather than the example without? – Mittenchops Nov 18 '18 at 23:14
  • 4
    No - it is a common misconception that using ISO_C_BINDING makes things interoperable. The key in Fortran is the language-binding-attribute BIND(C). When this is specified on a procedure, variable or type declaration, it imposes rules and behaviors compatible with a "companion C processor". On a procedure, for example, it means no hidden arguments, and the ability to pass by value. On a type it means no padding that a C compiler wouldn't do. ISO_C_BINDING is a help, to be sure, but on its own it does nothing. – Steve Lionel Nov 19 '18 at 00:08
  • Got it, thank you. Found this, looks helpful: https://stackoverflow.com/tags/fortran-iso-c-binding/info – Mittenchops Nov 19 '18 at 01:58