Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Minimal example of calling a fortran library from go

Tags:

go

fortran

ffi

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:

  • Calling C from fortran (ifort, gfortran)
  • calling C# from Fortran
  • Read C++ 'Hello World' from Fortran
  • Call Go functions from C
  • Calling C from golang
  • Calling Haskell FFI Function Ptrs from C
  • Calling python from fortran
  • Calling Haskell from Rust
  • How to call R functions from Fortran?

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.

like image 201
Mittenchops Avatar asked Nov 18 '18 02:11

Mittenchops


1 Answers

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]
like image 171
roygvib Avatar answered Nov 05 '22 15:11

roygvib