Calling C and Fortran

While Julia can rightfully claim to obviate the need to write some C or Fortran code, it is possible that you will need to interact with the existing C or Fortran shared libraries. Functions in such a library can be called directly by Julia, with no glue code, boilerplate code, or compilation needed. Because Julia's LLVM compiler generates native code, calling a C function from Julia has exactly the same overhead as calling the same function from C code itself. However, first, we need to know a few more things:

  • For calling out to C, we need to work with pointer types; a native pointer Ptr{T} is nothing more than the memory address for a variable of type T. You can use Cstring if the value is null-terminated.
  • At this lower level, the term primitive is also used. primitive is a concrete type whose data consists of bits, such as Int8, UInt8, Int32, Float64, Bool, and Char.
  • To pass a string to C, it is converted to a contiguous byte array representation with the function unsafe_string(); given Ptr to a C string, it returns a Julia string.

Here is how to call a C function in a shared library (calling Fortran is done similarly). Suppose we want to know the value of an environment variable in our system, say, the language; we can obtain this by calling the C function getenv from the shared library libc:

# code in Chapter 9callc.jl: 
lang = ccall( (:getenv, "libc"), Cstring, (Cstring,), "LANG")

This returns a Cstring. To see its string contents, execute unsafe_string(lang), which returns en_US.

In general, ccall takes the following arguments:

  • A (:function, "library") tuple, where the name of the C function (here, getenv) is used as a symbol, and the library name (here, libc) as a string
  • The return type (here, Cstring), which can also be any primitive, or Ptr
  • A Cstring as input arguments: note the tuple notation (Cstring,)
  • The actual arguments, if there are any (here, "LANG")

It is generally advisable to test for the existence of a library before doing the call. This can be tested like this: find_library(["libc"]), which returns "libc" when the library is found, or " " when it cannot find the library.

When calling a Fortran function, all inputs must be passed by reference. Arguments to C functions are, in general, automatically converted, and the returned values in C types are also converted to Julia types. Arrays of Booleans are handled differently in C and Julia and cannot be passed directly, so they must be manually converted. The same applies for some system-dependent types.

The ccall function will also automatically ensure that all of its arguments will be preserved from garbage collection until the call returns. C types are mapped to Julia types. For example, short is mapped to Int16, and double to Float64.

A complete table of these mappings, as well as a lot more intricate details, can be found in the Julia docs at http://docs.julialang.org/en/latest/manual/calling-c-and-fortran-code/. The other way around is also possible, by calling Julia functions from C code (or embedding Julia in C); refer to http://docs.julialang.org/en/latest/manual/embedding/. Julia and C can also share array data without copying.

If you have the existing C code, you must compile it as a shared library to call it from Julia. With GCC, you can do this using the -shared -fPIC command-line arguments. Support for C++ is more limited and is provided by the Cpp and Clang packages.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.159.223