I want to call functions in my Fortran library from Julia. In this case, I have a function eye that takes an Integer, and returns a two-dimensional array of integers.
The Fortran module is compiled into a shared library using
$ gfortran -shared -fPIC -o matrix_routines.so matrix_routines.f90
And thereafter I am attempting to call it from the interactive Julia interpreter like that (name obtained from nm):
julia> n=5
5
julia> ccall( (:__matrix_routines_MOD_eye, "/path/to/library/matrix_routines.so"), Array{Int64,2} , (Ptr{Int64},), &n )
This, however, immediately results in Julia throwing a segfault at me:
signal (11): Segmentation fault
__matrix_routines_MOD_eye at /path/to/library/matrix_routines.so (unknown line)
anonymous at no file:0
unknown function (ip: -1137818532)
jl_f_top_eval at /usr/bin/../lib/julia/libjulia.so (unknown line)
eval_user_input at REPL.jl:53
jlcall_eval_user_input_19998 at  (unknown line)
jl_apply_generic at /usr/bin/../lib/julia/libjulia.so (unknown line)
anonymous at task.jl:95
jl_handle_stack_switch at /usr/bin/../lib/julia/libjulia.so (unknown line)
julia_trampoline at /usr/bin/../lib/julia/libjulia.so (unknown line)
unknown function (ip: 4199613)
__libc_start_main at /usr/bin/../lib/libc.so.6 (unknown line)
unknown function (ip: 4199667)
unknown function (ip: 0)
zsh: segmentation fault (core dumped)  julia
Am I calling the function the wrong way? What is the correct name of the function? (It doesn't appear to be just eye, as that doesn't work either.)
As an additional question: does Julia do anything with the memory-orientation of the resulting arrays? Fortran and Julia are both column-major, but I wonder if due to ccall() Julia might think it should tranpose them?
module matrix_routines
    implicit none
    private
    public :: eye
    contains
        pure function eye(n,offset) result(um) !{{{
            integer, intent(in) :: n
            integer, intent(in), optional :: offset
            integer, dimension(n,n) :: um
            integer :: i, l, u, os
            um = 0
            l = 1
            u = n
            os = 0
            if (present(offset)) then
                os = offset
            end if
            if (abs(os) < n) then
                if (os > 0) then
                    u = n - os
                else if (os < 0) then
                    l = 1 - os
                end if
                do i=l, u
                    um(i, i+os) = 1
                end do
            end if
        end function eye !}}}
end module matrix_routines
                There a couple issues with your approach.  Returning an array directly to julia is problematic because Fortran arrays are not interoperable with C unless specific conditions are met.  When you make the array interoperable (add bind(C) to your procedure and give the array a C type) the compiler (gfortran) will complain:
Error: Return type of BIND(C) function 'um' at (1) cannot be an array
To get around this we can return the array through a dummy argument.  You'll want to make this an intent(inout) argument and construct the array in julia to avoid any memory/scope issues with creating the array in Fortran.
Secondly, the optional argument is problematic and skimming the Julia docs I'm not sure it is even supported.  Note that not even Fortran can call Fortran with optional arguments without an explicit interface and as Julia doesn't interact with the .mod file and seems to expect the C way of doing things, it probably won't work (and Fortran 2008 15.3.7 p2.6 seems to say it isn't supported).  There are workarounds though -- you can create multiple Fortran procedures with varying numbers of arguments and then call the procedure with optional arguments from them.  
First, consider this Fortran module, which started with your example but is pared down to just what is necessary to demonstrate the interop:
module matrix_routines
  implicit none
  private
  public :: eye
contains
  pure subroutine eye(n,um) bind(C,name="eye") !{{{
    use, intrinsic :: iso_c_binding, only: c_int
    implicit none
    integer(c_int), intent(in) :: n
    integer(c_int), intent(inout), dimension(n,n) :: um
    integer :: i, j
    do j=1,n
       do i=1,n
          um(i,j) = i+j
       end do
    end do
  end subroutine eye !}}}
end module matrix_routines
Note that I've moved um to being an inout dummy argument and since we're not returning a value changed the procedure to a subroutine.  I have also removed the optional argument.  I have also used C interop types and bound a C name to the procedure. You can compile this as in your question.
In Julia you can now do the following:
julia> n = 2
2
julia> um = zeros(Int32, n, n)
2x2 Array{Int32,2}:
 0  0
 0  0
julia> ccall((:eye, "matrix_routines.so"), Void, (Ptr{Int32}, Ptr{Array{Int32,2}}), &n, um)
julia> um
2x2 Array{Int32,2}:
 2  3
 3  4
julia> n = 4
4
julia> um = zeros(Int32, n, n)
4x4 Array{Int32,2}:
 0  0  0  0
 0  0  0  0
 0  0  0  0
 0  0  0  0
julia> ccall((:eye, "matrix_routines.so"), Void, (Ptr{Int32}, Ptr{Array{Int32,2}}), &n, um)
julia> um
4x4 Array{Int32,2}:
 2  3  4  5
 3  4  5  6
 4  5  6  7
 5  6  7  8
Note that we can call the function as just :eye since we used the bind(C,name="eye") C interop in our Fortran.  
And lastly, if we change the do loop in my Fortran example to be um(i,j) = i*10+j, we can see that no transposition happens in the array:
julia> um
3x3 Array{Int32,2}:
 11  12  13
 21  22  23
 31  32  33
The particular reason for your segfault could have been a number of things -- mismatched data types, issues with the return type, issues with the optional argument or mismatch in the actual call and variables passed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With