2015-02-06 12 views
6

Chcę wywoływać funkcje z mojej biblioteki Fortran od Julii. W tym przypadku mam funkcję eye, która pobiera liczbę całkowitą i zwraca dwuwymiarową tablicę liczb całkowitych.Wywołanie funkcji Fortran z Julii, zwrócenie tablicy: nieznana funkcja, segfault?

Moduł Fortran jest kompilowany do wspólnej biblioteki przy użyciu

$ gfortran -shared -fPIC -o matrix_routines.so matrix_routines.f90 

a potem ja próbuje wywołać ją z interaktywnym Julia tłumacza takiego (nazwa uzyskanych od nm):

julia> n=5 
5 

julia> ccall((:__matrix_routines_MOD_eye, "/path/to/library/matrix_routines.so"), Array{Int64,2} , (Ptr{Int64},), &n) 

To jednak natychmiast powoduje, że Julia rzuca na mnie uraz:

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 

Czy wywołanie funkcji jest nieprawidłowe? Jaka jest prawidłowa nazwa funkcji? (Wydaje się, że to nie jest tylko eye, ponieważ to też nie działa.)

Jako dodatkowe pytanie: czy Julia robi coś z orientacją pamięci wynikowych tablic? Fortran i Julia są głównymi kolumnami, ale zastanawiam się, czy ze względu na ccall() Julia może pomyśleć, że powinna je przenieść?

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 
+2

Opcjonalne argumenty wymagają jawnego interfejsu w Fortran. Powinieneś wiedzieć, co robisz przed zabawą z ogniem. Najlepiej byłoby użyć interopera Fortran 2003 z C (i prawdopodobnie modułem iso_c_binding). Tylko Fortran 2008 (lub 15?) Pozwala opcjonalnie argumentować na interoperacyjne procedury C. –

+0

Dowolne użyteczne wyjście z 'gfortran -Wall -fcheck = all ...'? – rickhg12hs

+1

@VladimirF: Dziękuję za wskazanie tego. Do tej pory "używałem modułu w moim programie Fortran", który oczywiście ma jawny interfejs poprzez plik '.mod'. Zauważ, że usunąłem argument "opcjonalny", ale nadal powoduje to błąd segfault. Sugerujesz, że muszę użyć 'iso_c_binding'? @ rickhg12hs: Nie, nic w ogóle. Brak ostrzeżeń. – mSSM

Odpowiedz

1

Jest kilka problemów z twoim podejściem. Zwrócenie tablicy bezpośrednio do julia jest problematyczne, ponieważ tablice Fortran nie są interoperacyjne z C, chyba że spełnione są określone warunki. Po dokonaniu tablica interoperacyjne (dodaj bind(C) do procedury i dać tablicę typu C) kompilator (gfortran) będzie narzekać:

Error: Return type of BIND(C) function 'um' at (1) cannot be an array 

Aby obejść ten problem, że możemy wrócić tablicy przez manekina argumentu. Będziesz chciał uczynić to argumentem intent(inout) i skonstruować tablicę w julia, aby uniknąć problemów związanych z pamięcią/zasięgiem podczas tworzenia tablicy w Fortranie.

Po drugie, opcjonalny argument jest problematyczny i przegląda dokumentację Julii. Nie jestem pewien, czy jest ona obsługiwana. Zauważ, że nawet Fortran nie może wywołać Fortran z opcjonalnymi argumentami bez jawnego interfejsu, a ponieważ Julia nie wchodzi w interakcję z plikiem .mod i wydaje się, że spodziewa się sposobu działania C, prawdopodobnie to nie zadziała (i Fortran 2008 15.3.7 Wydaje się, że p2.6 nie jest obsługiwane). Istnieją jednak obejścia - można utworzyć wiele procedur Fortran ze zmienną liczbą argumentów, a następnie wywołać procedurę z opcjonalnymi argumentami z nich.

pierwsze, rozważyć ten moduł Fortran, która rozpoczęła się swoim przykładzie, ale jest uproszczona do tylko to, co jest konieczne do wykazania współdziałanie:

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 

pamiętać, że został przeniesiony um do bycia inout manekin argumentem a ponieważ nie zwracamy wartości, zmieniliśmy procedurę na podprogram. Usunąłem także opcjonalny argument. Użyłem również typów C interop i przypisałem nazwę C do procedury. Możesz skompilować to tak jak w swoim pytaniu.

W Julia można teraz wykonać następujące czynności:

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 

pamiętać, że możemy wywołać funkcję jak tylko :eye ponieważ użyliśmy współdziałanie bind(C,name="eye") C w naszym Fortran.

I wreszcie, jeśli zmieniamy pętlę uwagi w moim Fortran przykład być um(i,j) = i*10+j, widzimy, że żadna transpozycja dzieje się w tablicy:

julia> um 
3x3 Array{Int32,2}: 
11 12 13 
21 22 23 
31 32 33 

Szczególnym powodem Twój segfault może mieć było wiele rzeczy - niedopasowane typy danych, problemy z typem zwracania, problemy z opcjonalnym argumentem lub niedopasowanie w rzeczywistym wywołaniu i zmienne przekazane.

+0

Potrzebuję użyć "./matrix_routines.so" dla Julia, aby znaleźć bibliotekę, a następnie pojawia się komunikat o błędzie zaczynający się od "BŁĄD: MethodError:' convert' nie ma metody pasującej do konwersji ". –

Powiązane problemy