example for ccall use and fortran

1,160 views
Skip to first unread message

Andre Bieler

unread,
Nov 14, 2014, 4:08:50 PM11/14/14
to julia...@googlegroups.com
tried calling a simple fortran function from julia but did not succeed:
this is the fortran code:

!fileName = simplemodule.f95
module simpleModule

contains
function foo(x)
  integer
:: foo, x
  foo
= x * 2
end function foo


end module simplemodule


which is then compiled with:

gfortran simplemodule.f95 -o simplemodule.so -shared -fPIC

and finally the julia call is:


ccall
((:foo, "/fullPathTo/simpleMod.so"), Int32, (Int32,), 3)


which then leads to the following error:

ERROR: ccall: could not find function foo in library /fullPathTo/simpleMod.so
 in anonymous at no file



when compiling with:

gfortran -c simplemodule.f95 -o simplemodule.so -shared -fPIC

i get a different error:

ERROR: error compiling anonymous: could not load module /fullPathTo/simplemodule.so: /fullPathTo/simplemodule.so:
only ET_DYN and ET_EXEC can be loaded



Can anyone tell me what I am missing?
I do realize I would not need to call fortran to multiply a variable by 2, but its a starting point..


Thanks!
Andre

Mike Nolta

unread,
Nov 14, 2014, 4:20:53 PM11/14/14
to julia...@googlegroups.com
On Fri, Nov 14, 2014 at 4:08 PM, Andre Bieler <andre.b...@gmail.com> wrote:
> tried calling a simple fortran function from julia but did not succeed:
> this is the fortran code:
>
> !fileName = simplemodule.f95
> module simpleModule
>
> contains
> function foo(x)
> integer :: foo, x
> foo = x * 2
> end function foo
>
>
> end module simplemodule
>
>
> which is then compiled with:
>
> gfortran simplemodule.f95 -o simplemodule.so -shared -fPIC
>
> and finally the julia call is:
>
>
> ccall((:foo, "/fullPathTo/simpleMod.so"), Int32, (Int32,), 3)
>

You have to mangle the function name because of the module, so
something like this might work:

a = Int32[3]
ccall(("__simplemodule_MOD_foo","./simplemodule.so"),Int32,(Ptr{Int32},),a)

-Mike

Luthaf

unread,
Nov 14, 2014, 4:22:44 PM11/14/14
to julia...@googlegroups.com
The first way to compile is the good one, but gfortran is slightly changing the names of the function. You can see it by running the `nm` command :
```
$ nm simplemodule.so
0000000000000f98 T ___simplemodule_MOD_foo
```

So you have to call `__simplemodule_MOD_foo`  from Julia side (yes, with one underscore less. I don't know why ...)

```
julia> ccall((:__simplemodule_MOD_foo, "simplemodule.so"), Int32, (Int32,), 3)
```

This will also lead to a segfault, as Fortran except values to be passed by reference, and not by value. So the final call is

```
julia>ccall((:__simplemodule_MOD_foo, "simplemodule.so"), Int32, (Ptr{Int32},), &3)
   6
```

Regards,
Guillaume

Andre Bieler a écrit :

Mauro

unread,
Nov 14, 2014, 4:39:01 PM11/14/14
to julia...@googlegroups.com
Maybe this can help too:
http://maurow.bitbucket.org/notes/calling_fortran_from_misc.html

By using bind(c) or iso_c_binding name mangling is turned off.
>> *gfortran simplemodule.f95 -o simplemodule.so -shared -fPIC*
>>
>> and finally the julia call is:
>>
>> ||
>>
>> ccall((:foo,"/fullPathTo/simpleMod.so"),Int32,(Int32,),3)
>>
>>
>> which then leads to the following error:
>>
>> ERROR: ccall: could not find function foo in library
>> /fullPathTo/simpleMod.so
>> in anonymous at no file
>>
>>
>>
>> when compiling with:
>>
>> gfortran -c simplemodule.f95 -o simplemodule.so -shared -fPIC
>>
>> i get a different error:
>>
>> *ERROR: error compiling anonymous: could not load module
>> /fullPathTo/simplemodule.so: /fullPathTo/simplemodule.so:*
>> *only ET_DYN and ET_EXEC can be loaded*

Andre Bieler

unread,
Nov 14, 2014, 4:42:59 PM11/14/14
to julia...@googlegroups.com, lut...@luthaf.fr
Thanks guys that worked!! 

Daniel Høegh

unread,
Nov 15, 2014, 9:38:47 AM11/15/14
to julia...@googlegroups.com
I had a problem about this some time ago and I abandoned it because I could not get it working and then this discussion actually helped solving the problem today.
I have opened an issue on it on Github see https://github.com/JuliaLang/julia/issues/9022

Andre Bieler

unread,
May 30, 2015, 3:10:39 PM5/30/15
to julia...@googlegroups.com
Ok so I have a few simple examples working for ccalling fortran functions and subroutines from Julia.
Maybe someone will find this useful examples when first looking into calling fortran from julia.

compile the following fortran module with

gfortran simplemodule.f95 -o simplemodule.so -shared -fPIC


```
!fileName = simplemodule.f95
module simpleModule

implicit none

contains
function foo(x)
  integer :: foo, x
  foo = x * 2
end function foo

subroutine bar(x, a, b)
  integer, intent(in) :: x
  integer, intent(out) :: a, b
  
  a = x + 3
  b = x * 3
end subroutine bar

subroutine keg(x, a, b)
  real*8, intent(in) :: x
  real*8, intent(out) :: a, b
  
  a = x + 3.0
  b = x * 3.0
end subroutine keg

subroutine ruf(x, y)
  real*8, dimension(3), intent(in) :: x
  real*8, dimension(3), intent(out) :: y
  integer :: i
  
  DO i = 1, 3
    y(i) = 2*x(i)
  END DO
end subroutine ruf

end module simplemodule
```

then you can use the following julia script to call the functions from the shared library.

```
x1 = 7
a1 = [0]
b1 = [0]

r1 = ccall((:__simplemodule_MOD_foo, "/home/abieler/testPrograms/fortranShardLib/simplemodule.so"), Int64, 
            (Ptr{Int64},), &x1)

println(r1)
println()

ccall((:__simplemodule_MOD_bar, "/home/abieler/testPrograms/fortranShardLib/simplemodule.so"), Void, 
      (Ptr{Int64}, Ptr{Int64}, Ptr{Int64}), &x1, a1, b1)
      
println(a1[1])
println(b1[1])
println()

x2 = 7.0
a2 = Cdouble[1.0]
b2 = Cdouble[1.0]

ccall((:__simplemodule_MOD_keg, "/home/abieler/testPrograms/fortranShardLib/simplemodule.so"), Void, 
      (Ptr{Float64}, Ptr{Float64}, Ptr{Float64}), &x2, a2, b2)
      
println(a2[1])
println(b2[1])
println()

x3 = [1.0, 2.0, 3.0]
y3 = [0.0, 0.0, 0.0]
ccall((:__simplemodule_MOD_ruf, "/home/abieler/testPrograms/fortranShardLib/simplemodule.so"), Void, 
      (Ptr{Float64}, Ptr{Float64}), x3, y3)
      
println(y3)
```

Message has been deleted

Jiahao Chen

unread,
May 30, 2015, 9:52:03 PM5/30/15
to julia...@googlegroups.com
It would be great if you could clean up your example and add it to the documentation.

Thanks,

Jiahao Chen
Research Scientist
MIT CSAIL

On Sun, May 31, 2015 at 3:17 AM, Andre Bieler <andre.b...@gmail.com> wrote:
Ok so I have a few simple examples working for ccalling fortran functions and subroutines from Julia.
Maybe someone will find this useful examples when first looking into calling fortran from julia.

compile the following fortran mod
```
!fileName = simplemodule.f95
module simpleModule

implicit none

contains
function foo(x)
  integer :: foo, x
  foo = x * 2
end function foo

```

Eduardo Lenz

unread,
May 31, 2015, 8:53:15 PM5/31/15
to julia...@googlegroups.com

Hi
I am using the dsplp subroutine  (Linear Programming) from LINPACK. It is also in FORTRAN and I made a simple interface to use it in Julia. Although the data format used internally by the dsplp subroutine is diferent, I made the following function in julia to emulate the linpro package from Scilab (without the equality constraint, but it can be changed).

The julia function is

<script src="https://gist.github.com/anonymous/9e4bcda40a5e66f9f104.js"></script>

and the fortran subroutine is

<script src="https://gist.github.com/CodeLenz/223f3efe4b9e386059e2.js"></script>

To generate the .so, I use this fortran subroutine and some of the fortran functions from LINPACK;

The usage is simple like this

function Linpro_Test()

# Min 2x[1] + 3x[2]
# S.T
#         -x[1] - x[2] <= -1.0
#
#       0<= x[1] <= 5
#       0<= x[2] <= 5
#
# Solution x = [1,0]

  n = 2
  m = 1
  p = [2.0, 3.0]
  C = [-1.0 -1.0]
  b = [-1.0]
  ci = [0.0 , 0.0]
  cs = [5.0 , 5.0]

  x,lagr,info = Linpro_Slatec(n,m,p,C,b,ci,cs)

  println("\n Result ",x)
  println("\n Lagr      ",lagr)
  println("\n Info      ",info)

end

Andre Bieler

unread,
Jun 1, 2015, 3:11:01 PM6/1/15
to julia...@googlegroups.com
ok I ll look into how to put a more polished version of this
into the docs.

Steven G. Johnson

unread,
Jun 7, 2015, 2:56:42 AM6/7/15
to julia...@googlegroups.com
I'm skeptical that calling Fortran subroutines inside modules like this is portable; the mangling is compiler-dependent, no?

(Even calling Fortran subroutines outside modules is compiler-dependent, but thankfully most compilers these days use lowercase+underscore.  Calling Fortran functions (not subroutines) and passing strings are also things that are hard to do portably, or at least that used to be the case.)

With Fortran 2003, the portable thing to do is to use iso_c_binding to declare a C-compatible interface to your Fortran subroutines.

Tony Kelman

unread,
Jun 7, 2015, 8:14:54 AM6/7/15
to julia...@googlegroups.com
While a great many things in Fortran are compiler-dependent, practically speaking well over 90% of the usage in the Julia ecosystem is going to be with gfortran. The only reason anything in base Julia might work at all with ifort on OSX or Linux is due to ifort having gone out of their way to try to be at least mostly gfortran compatible by default on those platforms.

Edmondo Giovannozzi

unread,
Jun 8, 2015, 7:28:49 AM6/8/15
to julia...@googlegroups.com
Pay attention as "real*8" is not standard Fortran but just a quite common extension accepted by most compilers. :-)

Byung Lee

unread,
Aug 5, 2015, 6:01:04 PM8/5/15
to julia-users
Hi,

When I tried the following Fortran routine (abc.f), it worked using the following shared file and ccall.
But when I tried after changing  DOUBLE PRECISION with REAL, it did not work. How should it be fixed.

This is what I saw on the Internet and worked:
 
abc.f file I saw on the Internet

       SUBROUTINE MULTIPLY(A,B,C)
        DOUBLE PRECISION A,B,C
        C = A*B
        RETURN
        END

gfortran abc.f -o abc.so -shared -fPIC

a = 2.0
b = 4.2
n = Float64[1.0]
 
  ccall((:multiply_, "abc.so"), Void, (Ptr{Float64},Ptr{Float64},Ptr{Float64}),&a,&b, n)

julia> n
1-element Array{Float64,1}:
 8.4

Again ccall worked with DOUBLE PRECISION.

When I used REAL like the following:
      SUBROUTINE MULTIPLY(A,B,C)
        DOUBLE PRECISION A,B,C
        C = A*B
        RETURN
        END

and used the same procedure like

gfortran abc.f -o abc.so -shared -fPIC

a = 2.0
b = 4.2
julia> n = Array(Float64)
0-dimensional Array{Float64,0}:
0.0

julia> ccall((:multiply_, "abc.so"), Void,  (Ptr{Float64},Ptr{Float64},Ptr{Float64}), &a,  &b, n)

julia> n
0-dimensional Array{Float64,0}:
1.061e-314

The default value of 0.0 changed to 1.061e-314, which is not the correct answer.

When I assigned a specific number to n:
julia> n = Float64[1.0]
1-element Array{Float64,1}:
 1.0

julia> ccall((:multiply_, "abc.so"), Void,  (Ptr{Float64},Ptr{Float64},Ptr{Float64}), &a,  &b, n)

Then the array element value was not changed.
julia> n
1-element Array{Float64,1}:
 1.0

I am wondering why it does not work with REAL variables.
I tried Logical, Int, and Character variables, along with Double Precision.
All worked, except for REAL.

Thanks,

Byung Lee

unread,
Aug 5, 2015, 6:01:05 PM8/5/15
to julia-users
julia> ccall((:multiply_, "/fullPathTo/abc.so"), Void,  (Ptr{Float64},Ptr{Float64},Ptr{Float64}), &a,  &b, n)


julia> n
0-dimensional Array{Float64,0}:
1.061e-314

The default value of 0.0 changed to 1.061e-314, which is not the correct answer.

When I assigned a specific number to n:
julia> n = Float64[1.0]
1-element Array{Float64,1}:
 1.0

julia> ccall((:multiply_, "/fullPathTo/abc.so"), Void,  (Ptr{Float64},Ptr{Float64},Ptr{Float64}), &a,  &b, n)


Then the array element value was not changed.
julia> n
1-element Array{Float64,1}:
 1.0

I am wondering why it does not work with REAL variables.
I tried Logical, Int, and Character variables, along with Double Precision.
All worked, except for REAL.

Thanks,

Byung Lee

Byung Lee

unread,
Aug 6, 2015, 9:13:58 AM8/6/15
to julia-users
Hi,

I got an answer. You need to use Cfloat for REAL instead of Cdouble for DOUBLE PRECISION.

Byung Lee

unread,
Aug 6, 2015, 9:30:43 AM8/6/15
to julia-users
Not only Cfloat, but also Float32 worked, like Cfloat[1.2] OR Float32[1.1].

Patrick O'Leary

unread,
Aug 6, 2015, 10:21:43 AM8/6/15
to julia-users
Cfloat is just an alias for Float32, to make it easier to match up type signatures in ccalls. The same is true for the other C-prefixed types. Which to prefer in a ccall is a matter of style.
Reply all
Reply to author
Forward
0 new messages