Calling C and Fortran Code

Though most code can be written in Julia, there are many high-quality, mature libraries for numerical computing already written in C and Fortran. To allow easy use of this existing code, Julia makes it simple and efficient to call C and Fortran functions. Julia has a “no boilerplate” philosophy: functions can be called directly from Julia without any “glue” code, code generation, or compilation — even from the interactive prompt. This is accomplished just by making an appropriate call with ccall syntax, which looks like an ordinary function call.

The code to be called must be available as a shared library. Most C and Fortran libraries ship compiled as shared libraries already, but if you are compiling the code yourself using GCC (or Clang), you will need to use the -shared and -fPIC options. The machine instructions generated by Julia’s JIT are the same as a native C call would be, so the resulting overhead is the same as calling a library function from C code. (Non-library function calls in both C and Julia can be inlined and thus may have even less overhead than calls to shared library functions. When both libraries and executables are generated by LLVM, it is possible to perform whole-program optimizations that can even optimize across this boundary, but Julia does not yet support that. In the future, however, it may do so, yielding even greater performance gains.)

Shared libraries and functions are referenced by a tuple of the form (:function,"library") or ("function","library") where function is the C-exported function name. library refers to the shared library name: shared libraries available in the (platform-specific) load path will be resolved by name, and if necessary a direct path may be specified.

A function name may be used alone in place of the tuple (just :function or "function"). In this case the name is resolved within the current process. This form can be used to call C library functions, functions in the Julia runtime, or functions in an application linked to Julia.

By default, Fortran compilers generate mangled names (for example, converting function names to lowercase or uppercase, often appending an underscore), and so to call a Fortran function via ccall you must pass the mangled identifier corresponding to the rule followed by your Fortran compiler. Also, when calling a Fortran function, all inputs must be passed by reference.

Finally, you can use ccall to actually generate a call to the library function. Arguments to ccall are as follows:

  1. (:function, “library”) pair (must be a constant, but see below).
  2. Return type (see below for mapping the declared C type to Julia)
    • This argument will be evaluated at compile-time.
  3. A tuple of input types. The input types must be written as a literal tuple, not a tuple-valued variable or expression.
    • This argument will be evaluated at compile-time.
  4. The following arguments, if any, are the actual argument values passed to the function.

As a complete but simple example, the following calls the clock function from the standard C library:

julia>t=ccall((:clock,"libc"),Int32,())2292761julia>t2292761julia>typeof(ans)Int32

clock takes no arguments and returns an Int32. One common gotcha is that a 1-tuple must be written with a trailing comma. For example, to call the getenv function to get a pointer to the value of an environment variable, one makes a call like this:

julia>path=ccall((:getenv,"libc"),Ptr{UInt8},(Ptr{UInt8},),"SHELL")Ptr{UInt8}@0x00007fff5fbffc45julia>bytestring(path)"/bin/bash"

Note that the argument type tuple must be written as (Ptr{UInt8},), rather than (Ptr{UInt8}). This is because (Ptr{UInt8}) is just the expression Ptr{UInt8} surrounded by parentheses, rather than a 1-tuple containing Ptr{UInt8}:

julia>(Ptr{UInt8})Ptr{UInt8}julia>(Ptr{UInt8},)(Ptr{UInt8},)

In practice, especially when providing reusable functionality, one generally wraps ccall uses in Julia functions that set up arguments and then check for errors in whatever manner the C or Fortran function indicates them, propagating to the Julia caller as exceptions. This is especially important since C and Fortran APIs are notoriously inconsistent about how they indicate error conditions. For example, the getenv C library function is wrapped in the following Julia function in env.jl:

function getenv(var::AbstractString)val=ccall((:getenv,"libc"),Ptr{UInt8},(Ptr{UInt8},),var)ifval==C_NULLerror("getenv: undefined variable: ",var)endbytestring(val)end

The C getenv function indicates an error by returning NULL, but other standard C functions indicate errors in various different ways, including by returning -1, 0, 1 and other special values. This wrapper throws an exception clearly indicating the problem if the caller tries to get a non-existent environment variable:

julia>getenv("SHELL")"/bin/bash"julia>getenv("FOOBAR")getenv:undefinedvariable:FOOBAR

Here is a slightly more complex example that discovers the local machine’s hostname:

function gethostname()hostname=Array(UInt8,128)ccall((:gethostname,"libc"),Int32,(Ptr{UInt8},Csize_t),hostname,sizeof(hostname))hostname[end]=0;# ensure null-terminationreturnbytestring(pointer(hostname))end

This example first allocates an array of bytes, then calls the C library function gethostname to fill the array in with the hostname, takes a pointer to the hostname buffer, and converts the pointer to a Julia string, assuming that it is a NUL-terminated C string. It is common for C libraries to use this pattern of requiring the caller to allocate memory to be passed to the callee and filled in. Allocation of memory from Julia like this is generally accomplished by creating an uninitialized array and passing a pointer to its data to the C function.

Creating C-Compatible Julia Function Pointers

It is possible to pass Julia functions to native c-functions that accept function pointer arguments. For example, to match c-prototypes of the form:

typedefreturntype(*functiontype)(argumenttype,...)

The function cfunction generates the c-compatible function pointer for a call to a Julia library function. Arguments to cfunction are as follows:

  1. A Julia Function
  2. Return type
  3. A tuple of input types

A classic example is the standard C library qsort function, declared as:

voidqsort(void*base,size_tnmemb,size_tsize,int(*compare)(constvoid*a,constvoid*b));

The base argument is a pointer to an array of length nmemb, with elements of size bytes each. compare is a callback function which takes pointers to two elements a and b and returns an integer less/greater than zero if a should appear before/after b (or zero if any order is permitted). Now, suppose that we have a 1d array A of values in Julia that we want to sort using the qsort function (rather than Julia’s built-in sort function). Before we worry about calling qsort and passing arguments, we need to write a comparison function that works for some arbitrary type T:

function mycompare{T}(a::T,b::T)returnconvert(Cint,a<b?-1:a>b?+1:0)::Cintend

Notice that we have to be careful about the return type: qsort expects a function returning a C int, so we must be sure to return Cint via a call to convert and a typeassert.

In order to pass this function to C, we obtain its address using the function cfunction:

constmycompare_c=cfunction(mycompare,Cint,(Ref{Cdouble},Ref{Cdouble}))

cfunction accepts three arguments: the Julia function (mycompare), the return type (Cint), and a tuple of the argument types, in this case to sort an array of Cdouble (Float64) elements.

The final call to qsort looks like this:

A=[1.3,-2.7,4.4,3.1]ccall(:qsort,Void,(Ptr{Cdouble},Csize_t,Csize_t,Ptr{Void}),A,length(A),sizeof(eltype(A)),mycompare_c)

After this executes, A is changed to the sorted array [-2.7,1.3,3.1,4.4]. Note that Julia knows how to convert an array into a Ptr{Cdouble}, how to compute the size of a type in bytes (identical to C’s sizeof operator), and so on. For fun, try inserting a println("mycompare($a,$b)") line into mycompare, which will allow you to see the comparisons that qsort is performing (and to verify that it is really calling the Julia function that you passed to it).

Mapping C Types to Julia

It is critical to exactly match the declared C type with its declaration in Julia. Inconsistencies can cause code that works correctly on one system to fail or produce indeterminate results on a different system.

Note that no C header files are used anywhere in the process of calling C functions: you are responsible for making sure that your Julia types and call signatures accurately reflect those in the C header file. (The Clang package can be used to auto-generate Julia code from a C header file.)

Auto-conversion:

Julia automatically inserts calls to the convert function to convert each argument to the specified type. For example, the following call:

ccall((:foo,"libfoo"),Void,(Int32,Float64),x,y)

will behave as if the following were written:

ccall((:foo,"libfoo"),Void,(Int32,Float64),Base.unsafe_convert(Int32,Base.cconvert(Int32,x)),Base.unsafe_convert(Float64,Base.cconvert(Float64,y)))

cconvert normally just calls convert, but can be defined to return an arbitrary new object more appropriate for passing to C. For example, this is used to convert an Array of objects (e.g. strings) to an array of pointers.

unsafe_convert handles conversion to Ptr types. It is considered unsafe because converting an object to a native pointer can hide the object from the garbage collector, causing it to be freed prematurely.

Type Correspondences:

First, a review of some relevant Julia type terminology:

Syntax / KeywordExampleDescription
typeASCIIString“Leaf Type” :: A group of related data that includes a type-tag, is managed by the Julia GC, and is defined by object-identity. The type parameters of a leaf type must be fully defined (no TypeVars are allowed) in order for the instance to be constructed.
abstractAny, AbstractArray{T,N}, Complex{T}“Super Type” :: A super-type (not a leaf-type) that cannot be instantiated, but can be used to describe a group of types.
{T}Vector{Int}

“Type Parameter” :: A specialization of a type (typically used for dispatch or storage optimization).

“TypeVar” :: The T in the type parameter declaration is referred to as a TypeVar (short for type variable).

bitstypeInt, Float64“Bits Type” :: A type with no fields, but a size. It is stored and defined by-value.
immutable

Pair{Int,Int}

Complex128 (isbits)

“Immutable” :: A type with all fields defined to be constant. It is defined by-value. And may be stored with a type-tag.

“Is-Bits” :: A bitstype, or an immutable type where all fields are other isbits types. It is defined by-value, and is stored without a type-tag.

type...;endnothing“Singleton” :: a Leaf Type or Immutable with no fields.
(...) or tuple(...)`(1,2,3)“Tuple” :: an immutable data-structure similar to an anonymous immutable type, or a constant array. Represented as either an array or a struct.
typealiasNot applicable hereType aliases, and other similar mechanisms of doing type indirection, are resolved to their base type (this includes assigning a type to another name, or getting the type out of a function call).

Bits Types:

There are several special types to be aware of, as no other type can be defined to behave the same:

Float32
Exactly corresponds to the float type in C (or REAL*4 in Fortran).
Float64
Exactly corresponds to the double type in C (or REAL*8 in Fortran).
Complex64
Exactly corresponds to the complexfloat type in C (or COMPLEX*8 in Fortran).
Complex128
Exactly corresponds to the complexdouble type in C (or COMPLEX*16 in Fortran).
Signed
Exactly corresponds to the signed type annotation in C (or any INTEGER type in Fortran). Any Julia type that is not a subtype of Signed is assumed to be unsigned.
Ref{T}
Behaves like a Ptr{T} that owns its memory.
Array{T,N}

When an array is passed to C as a Ptr{T} argument, it is not reinterpret-cast: Julia requires that the element type of the array matches T, and the address of the first element is passed.

Therefore, if an Array contains data in the wrong format, it will have to be explicitly converted using a call such as trunc(Int32,a).

To pass an array A as a pointer of a different type without converting the data beforehand (for example, to pass a Float64 array to a function that operates on uninterpreted bytes), you can declare the argument as Ptr{Void}.

If an array of eltype Ptr{T} is passed as a Ptr{Ptr{T}} argument, the Julia base library cconvert function will attempt to first make a null-terminated copy of the array with each element replaced by its cconvert version. This allows, for example, passing an argv pointer array of type Vector{ByteString} to an argument of type Ptr{Ptr{Cchar}}.

On all systems we currently support, basic C/C++ value types may be translated to Julia types as follows. Every C type also has a corresponding Julia type with the same name, prefixed by C. This can help for writing portable code (and remembering that an int in C is not the same as an Int in Julia).

System Independent:

C nameFortran nameStandard Julia AliasJulia Base Type

unsignedchar

bool (C++)

CHARACTERCucharUInt8
short

INTEGER*2

LOGICAL*2

CshortInt16
unsignedshort CushortUInt16

int

BOOL (C, typical)

INTEGER*4

LOGICAL*4

CintInt32
unsignedint CuintUInt32
longlong

INTEGER*8

LOGICAL*8

ClonglongInt64
unsignedlonglong CulonglongUInt64
intmax_t Cintmax_tInt64
uintmax_t Cuintmax_tUInt64
floatREAL*4iCfloatFloat32
doubleREAL*8CdoubleFloat64
complexfloatCOMPLEX*8Complex64Complex{Float32}
complexdoubleCOMPLEX*16Complex128Complex{Float64}
ptrdiff_t Cptrdiff_tInt
ssize_t Cssize_tInt
size_t Csize_tUInt
void  Void
void*  Ptr{Void}
T* (where T represents an appropriately defined type)  Ref{T}
char* (or char[], e.g. a string)CHARACTER*N Cstring if NUL-terminated, or Ptr{UInt8} if not
char** (or *char[])  Ptr{Ptr{UInt8}}
jl_value_t* (any Julia Type)  Any
jl_value_t** (a reference to a Julia Type)  Ref{Any}
va_arg  Not supported
... (variadic function specification)  T... (where T is one of the above types, variadic functions of different argument types are not supported)

The Cstring type is essentially a synonym for Ptr{UInt8}, except the conversion to Cstring throws an error if the Julia string contains any embedded NUL characters (which would cause the string to be silently truncated if the C routine treats NUL as the terminator). If you are passing a char* to a C routine that does not assume NUL termination (e.g. because you pass an explicit string length), or if you know for certain that your Julia string does not contain NUL and want to skip the check, you can use Ptr{UInt8} as the argument type.

System-dependent:

C nameStandard Julia AliasJulia Base Type
charCchar

Int8 (x86, x86_64)

UInt8 (powerpc, arm)

longClong

Int (UNIX)

Int32 (Windows)

unsignedlongCulong

UInt (UNIX)

UInt32 (Windows)

wchar_tCwchar_t

Int32 (UNIX)

UInt16 (Windows)

Note

When calling a Fortran function, all inputs must be passed by reference, so all type correspondences above should contain an additional Ptr{..} or Ref{..} wrapper around their type specification.

Warning

For string arguments (char*) the Julia type should be Cstring (if NUL- terminated data is expected) or either Ptr{Cchar} or Ptr{UInt8} otherwise (these two pointer types have the same effect), as described above, not ASCIIString. Similarly, for array arguments (T[] or T*), the Julia type should again be Ptr{T}, not Vector{T}.

Warning

Julia’s Char type is 32 bits, which is not the same as the wide character type (wchar_t or wint_t) on all platforms.

Note

For wchar_t* arguments, the Julia type should be Cwstring (if the C routine expects a NUL-terminated string) or Ptr{Cwchar_t} otherwise, and data can be converted to/from ordinary Julia strings by the wstring(s) function (equivalent to either utf16(s) or utf32(s) depending upon the width of Cwchar_t); this conversion will be called automatically for Cwstring arguments. Note also that ASCII, UTF-8, UTF-16, and UTF-32 string data in Julia is internally NUL-terminated, so it can be passed to C functions expecting NUL-terminated data without making a copy (but using the Cwstring type will cause an error to be thrown if the string itself contains NUL characters).

Note

C functions that take an argument of the type char** can be called by using a Ptr{Ptr{UInt8}} type within Julia. For example, C functions of the form:

intmain(intargc,char**argv);

can be called via the following Julia code:

argv=["a.out","arg1","arg2"]ccall(:main,Int32,(Int32,Ptr{Ptr{UInt8}}),length(argv),argv)

Note

A C function declared to return Void will return the value nothing in Julia.

Struct Type correspondences

Composite types, aka struct in C or TYPE in Fortran90 (or STRUCTURE / RECORD in some variants of F77), can be mirrored in Julia by creating a type or immutable definition with the same field layout.

When used recursively, isbits types are stored inline. All other types are stored as a pointer to the data. When mirroring a struct used by-value inside another struct in C, it is imperative that you do not attempt to manually copy the fields over, as this will not preserve the correct field alignment. Instead, declare an immutable isbits type and use that instead. Unnamed structs are not possible in the translation to Julia.

Packed structs and union declarations are not supported by Julia.

You can get a near approximation of a union if you know, a priori, the field that will have the greatest size (potentially including padding). When translating your fields to Julia, declare the Julia field to be only of that type.

Arrays of parameters must be expanded manually, currently (either inline, or in an immutable helper-type). For example:

inC:structB{intA[3];};b_a_2=B.A[2];inJulia:immutableB_AA_1::CintA_2::CintA_3::Cintendtype BA::B_Aendb_a_2=B.A.(2)

Arrays of unknown size are not supported.

In the future, some of these restrictions may be reduced or eliminated.

Memory Ownership:

malloc/free

Memory allocation and deallocation of such objects must be handled by calls to the appropriate cleanup routines in the libraries being used, just like in any C program. Do not try to free an object received from a C library with Libc.free in Julia, as this may result in the free function being called via the wrong libc library and cause Julia to crash. The reverse (passing an object allocated in Julia to be freed by an external library) is equally invalid.

Ptr{T} vs. Array{T} vs. Ref{T} vs. T

The choice of type-wrapper declaration strongly depends on who allocated the memory, and the declared type. In general, use T if the memory is intended to be allocated in (and managed by) Julia (with type-tag). Use Ptr{T} if the memory is expected to be populated by C (without type-tag). Use Ref{T} if you have an isbits type, but you want to turn it into a pointer to a struct in another struct definition.

Mapping C Functions to Julia

ccall/cfunction argument translation guide

For translating a c argument list to Julia:

  • T, where T is one of the primitive types: char, int, long, short, float, double, complex, enum or any of their typedef equivalents
    • T, where T is an equivalent Julia Bits Type (per the table above)
    • if T is an enum, the argument type should be equivalent to Cint or Cuint
    • argument value will be copied (passed by-value)
  • structT (including typedef to a struct)
    • T, where T is a Julia Leaf Type
    • argument value will be copied (passed by-value)
  • void*
    • depends on how this parameter is used, first translate this to the intended pointer type, then determine the Julia equivalent using the remaining rules in this list
    • this argument may be declared as Ptr{Void}, if it really is just an unknown pointer
  • jl_value_t*
    • Any
    • argument value must be a valid Julia object
    • currently unsupported by cfunction
  • jl_value_t**
    • Ref{Any}
    • argument value must be a valid Julia object (or C_NULL)
    • currently unsupported by cfunction
  • T*
    • Ref{T}, where T is the Julia type corresponding to T
    • argument value will be copied if it is an isbits type otherwise, the value must be a valid Julia object
  • (T*)(...) (e.g. a pointer to a function)
    • Ptr{Void} (you may need to use cfunction explicitly to create this pointer)
  • ... (e.g. a vararg)
    • T..., where T is the Julia type
  • va_arg
    • not supported

ccall/cfunction return type translation guide

For translating a c return type to Julia:

  • void
    • Void (this will return the singleton instance nothing::Void)
  • T, where T is one of the primitive types: char, int, long, short, float, double, complex, enum or any of their typedef equivalents
    • T, where T is an equivalent Julia Bits Type (per the table above)
    • if T is an enum, the argument type should be equivalent to Cint or Cuint
    • argument value will be copied (returned by-value)
  • structT (including typedef to a struct)
    • T, where T is a Julia Leaf Type
    • argument value will be copied (returned by-value)
  • void*
    • depends on how this parameter is used, first translate this to the intended pointer type, then determine the Julia equivalent using the remaining rules in this list
    • this argument may be declared as Ptr{Void}, if it really is just an unknown pointer
  • jl_value_t*
    • Any
    • argument value must be a valid Julia object
  • jl_value_t**
    • Ref{Any}
    • argument value must be a valid Julia object (or C_NULL)
  • T*
    • If the memory is already owned by Julia, or is an isbits type, and is known to be non-null:
      • Ref{T}, where T is the Julia type corresponding to T
      • a return type of Ref{Any} is invalid, it should either be Any (corresponding to jl_value_t*) or Ptr{Any} (corresponding to Ptr{Any})
      • currently partially unsupported by cfunction due to #2818
      • C MUST NOT modify the memory returned via Ref{T} if T is an isbits type
    • If the memory is owned by C:
      • Ptr{T}, where T is the Julia type corresponding to T
  • (T*)(...) (e.g. a pointer to a function)
    • Ptr{Void} (you may need to use cfunction explicitly to create this pointer)

Passing Pointers for Modifying Inputs

Because C doesn’t support multiple return values, often C functions will take pointers to data that the function will modify. To accomplish this within a ccall, you need to first encapsulate the value inside an Ref{T} of the appropriate type. When you pass this Ref object as an argument, julia will automatically pass a C pointer to the encapsulated data:

width=Ref{Cint}(0)range=Ref{Cfloat}(0)ccall(:foo,Void,(Ref{Cint},Ref{Cfloat}),width,range)

Upon return, the contents of width and range can be retrieved (if they were changed by foo) by width[] and range[]; that is, they act like zero-dimensional arrays.

Special Reference Syntax for ccall (deprecated):

The & syntax is deprecated, use the Ref{T} argument type instead.

A prefix & is used on an argument to ccall to indicate that a pointer to a scalar argument should be passed instead of the scalar value itself (required for all Fortran function arguments, as noted above). The following example computes a dot product using a BLAS function.

function compute_dot(DX::Vector{Float64},DY::Vector{Float64})assert(length(DX)==length(DY))n=length(DX)incx=incy=1product=ccall((:ddot_,"libLAPACK"),Float64,(Ptr{Int32},Ptr{Float64},Ptr{Int32},Ptr{Float64},Ptr{Int32}),&n,DX,&incx,DY,&incy)returnproductend

The meaning of prefix & is not quite the same as in C. In particular, any changes to the referenced variables will not be visible in Julia unless the type is mutable (declared via type). However, even for immutable types it will not cause any harm for called functions to attempt such modifications (that is, writing through the passed pointers). Moreover, & may be used with any expression, such as &0 or &f(x).

When a scalar value is passed with & as an argument of type Ptr{T}, the value will first be converted to type T.

Garbage Collection Safety

When passing data to a ccall, it is best to avoid using the pointer() function. Instead define a convert method and pass the variables directly to the ccall. ccall automatically arranges that all of its arguments will be preserved from garbage collection until the call returns. If a C API will store a reference to memory allocated by Julia, after the ccall returns, you must arrange that the object remains visible to the garbage collector. The suggested way to handle this is to make a global variable of type Array{Ref,1} to hold these values, until the C library notifies you that it is finished with them.

Whenever you have created a pointer to Julia data, you must ensure the original data exists until you are done with using the pointer. Many methods in Julia such as unsafe_load() and bytestring() make copies of data instead of taking ownership of the buffer, so that it is safe to free (or alter) the original data without affecting Julia. A notable exception is pointer_to_array() which, for performance reasons, shares (or can be told to take ownership of) the underlying buffer.

The garbage collector does not guarantee any order of finalization. That is, if a contained a reference to b and both a and b are due for garbage collection, there is no guarantee that b would be finalized after a. If proper finalization of a depends on b being valid, it must be handled in other ways.

Non-constant Function Specifications

A (name,library) function specification must be a constant expression. However, it is possible to use computed values as function names by staging through eval as follows:

@evalccall(($(string("a","b")),"lib"),...

This expression constructs a name using string, then substitutes this name into a new ccall expression, which is then evaluated. Keep in mind that eval only operates at the top level, so within this expression local variables will not be available (unless their values are substituted with $). For this reason, eval is typically only used to form top-level definitions, for example when wrapping libraries that contain many similar functions.

If your usage is more dynamic, use indirect calls as described in the next section.

Indirect Calls

The first argument to ccall can also be an expression evaluated at run time. In this case, the expression must evaluate to a Ptr, which will be used as the address of the native function to call. This behavior occurs when the first ccall argument contains references to non-constants, such as local variables, function arguments, or non-constant globals.

For example, you might lookup the function via dlsym, then cache it in a global variable for that session. For example:

macrodlsym(func,lib)z,zlocal=gensym(string(func)),gensym()eval(current_module(),:(global$z=C_NULL))z=esc(z)quotelet$zlocal::Ptr{Void}=$z::Ptr{Void}if$zlocal==C_NULL$zlocal=dlsym($(esc(lib))::Ptr{Void},$(esc(func)))global$z=$zlocalend$zlocalendendendmylibvar=dlopen("mylib")ccall(@dlsym("myfunc",mylibvar),Void,())

Calling Convention

The second argument to ccall can optionally be a calling convention specifier (immediately preceding return type). Without any specifier, the platform-default C calling convention is used. Other supported conventions are: stdcall, cdecl, fastcall, and thiscall. For example (from base/libc.jl) we see the same gethostname ccall as above, but with the correct signature for Windows:

hn=Array(UInt8,256)err=ccall(:gethostname,stdcall,Int32,(Ptr{UInt8},UInt32),hn,length(hn))

For more information, please see the LLVM Language Reference.

Accessing Global Variables

Global variables exported by native libraries can be accessed by name using the cglobal function. The arguments to cglobal are a symbol specification identical to that used by ccall, and a type describing the value stored in the variable:

julia>cglobal((:errno,:libc),Int32)Ptr{Int32}@0x00007f418d0816b8

The result is a pointer giving the address of the value. The value can be manipulated through this pointer using unsafe_load and unsafe_store.

Accessing Data through a Pointer

The following methods are described as “unsafe” because a bad pointer or type declaration can cause Julia to terminate abruptly (although, that’s quite alike with ccall).

Given a Ptr{T}, the contents of type T can generally be copied from the referenced memory into a Julia object using unsafe_load(ptr,[index]). The index argument is optional (default is 1), and follows the Julia-convention of 1-based indexing. This function is intentionally similar to the behavior of getindex() and setindex!() (e.g. [] access syntax).

The return value will be a new object initialized to contain a copy of the contents of the referenced memory. The referenced memory can safely be freed or released.

If T is Any, then the memory is assumed to contain a reference to a Julia object (a jl_value_t*), the result will be a reference to this object, and the object will not be copied. You must be careful in this case to ensure that the object was always visible to the garbage collector (pointers do not count, but the new reference does) to ensure the memory is not prematurely freed. Note that if the object was not originally allocated by Julia, the new object will never be finalized by Julia’s garbage collector. If the Ptr itself is actually a jl_value_t*, it can be converted back to a Julia object reference by unsafe_pointer_to_objref(ptr). (Julia values v can be converted to jl_value_t* pointers, as Ptr{Void}, by calling pointer_from_objref(v).)

The reverse operation (writing data to a Ptr{T}), can be performed using unsafe_store!(ptr,value,[index]). Currently, this is only supported for bitstypes or other pointer-free (isbits) immutable types.

Any operation that throws an error is probably currently unimplemented and should be posted as a bug so that it can be resolved.

If the pointer of interest is a plain-data array (bitstype or immutable), the function pointer_to_array(ptr,dims,[own]) may be more useful. The final parameter should be true if Julia should “take ownership” of the underlying buffer and call free(ptr) when the returned Array object is finalized. If the own parameter is omitted or false, the caller must ensure the buffer remains in existence until all access is complete.

Arithmetic on the Ptr type in Julia (e.g. using +) does not behave the same as C’s pointer arithmetic. Adding an integer to a Ptr in Julia always moves the pointer by some number of bytes, not elements. This way, the address values obtained from pointer arithmetic do not depend on the element types of pointers.

Thread-safety

Some C libraries execute their callbacks from a different thread, and since Julia isn’t thread-safe you’ll need to take some extra precautions. In particular, you’ll need to set up a two-layered system: the C callback should only schedule (via Julia’s event loop) the execution of your “real” callback. To do this, you pass a function of one argument (the AsyncWork object for which the event was triggered, which you’ll probably just ignore) to SingleAsyncWork:

cb=Base.SingleAsyncWork(data->my_real_callback(args))

The callback you pass to C should only execute a ccall to :uv_async_send, passing cb.handle as the argument.

More About Callbacks

For more details on how to pass callbacks to C libraries, see this blog post.

C++

Limited support for C++ is provided by the Cpp, Clang, and Cxx packages.

Handling Operating System Variation

When dealing with platform libraries, it is often necessary to provide special cases for various platforms. The variable OS_NAME can be used to write these special cases. Additionally, there are several macros intended to make this easier: @windows, @unix, @linux, and @osx. Note that linux and osx are mutually exclusive subsets of unix. Their usage takes the form of a ternary conditional operator, as demonstrated in the following examples.

Simple blocks:

ccall((@windows?:_fopen::fopen),...)

Complex blocks:

@linux?(beginsome_complicated_thing(a)end:beginsome_different_thing(a)end)

Chaining (parentheses optional, but recommended for readability):

@windows?:a:(@osx?:b::c)