diff --git a/doc/src/manual/calling-c-and-fortran-code.md b/doc/src/manual/calling-c-and-fortran-code.md index a73f746f8ceaa..a1612e2b3e734 100644 --- a/doc/src/manual/calling-c-and-fortran-code.md +++ b/doc/src/manual/calling-c-and-fortran-code.md @@ -11,16 +11,12 @@ The code to be called must be available as a shared library. Most C and Fortran 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.) +as calling a library function from C code. [^1] 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. +or `("function", "library")` where `function` is the C-exported function name, and `library` refers +to the shared library name. Shared libraries available in the (platform-specific) load path will +be resolved by name. The full path to the library may also 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 @@ -37,30 +33,33 @@ arrays and other mutable objects which are normally heap-allocated, but also to scalar values such as integers and floats which are normally stack-allocated and commonly passed in registers when using C or Julia calling conventions. -Finally, you can use [`ccall`](@ref) to actually generate a call to the library function. Arguments -to [`ccall`](@ref) are as follows: +Finally, you can use [`ccall`](@ref) to actually generate a call to the library function. The arguments +to [`ccall`](@ref) are: -1. A `(:function, "library")` pair, which must be written as a literal constant, +1. A `(:function, "library")` pair, OR - a `:function` name symbol or `"function"` name string, which is resolved in the - current process, + a `:function` name symbol or `"function"` name string, OR a function pointer (for example, from `dlsym`). -2. Return type (see below for mapping the declared C type to Julia) +2. The function's return type - * This argument will be evaluated at compile-time, when the containing method is defined. +3. A tuple of input types, corresponding to the function signature -3. A tuple of input types. The input types must be written as a literal tuple, not a tuple-valued - variable or expression. +4. The actual argument values to be passed to the function, if any; each is a separate parameter. - * This argument will be evaluated at compile-time, when the containing method is defined. +!!! note + The `(:function, "library")` pair, return type, and input types must be literal constants + (i.e., they can't be variables, but see [Non-constant Function Specifications](@ref) below). + + The remaining parameters are evaluated at compile time, when the containing method is defined. -4. The following arguments, if any, are the actual argument values passed to the function. +!!! note + See below for how to [map C types to Julia types](@ref mapping-c-types-to-julia). As a complete but simple example, the following calls the `clock` function from the standard C library: @@ -164,18 +163,20 @@ typedef returntype (*functiontype)(argumenttype, ...) ``` The macro [`@cfunction`](@ref) generates the C-compatible function pointer for a call to a -Julia function. Arguments to [`@cfunction`](@ref) are as follows: +Julia function. The arguments to [`@cfunction`](@ref) are: -1. A Julia Function -2. Return type -3. A literal tuple of input types +1. A Julia function +2. The function's return type +3. A tuple of input types, corresponding to the function signature -Like ccall, all of these arguments will be evaluated at compile-time, when the containing method is defined. +!!! note + As with `ccall`, the return type and tuple of input types must be literal constants. -Currently, only the platform-default C calling convention is supported. This means that -`@cfunction`-generated pointers cannot be used in calls where WINAPI expects `stdcall` -function on 32-bit windows, but can be used on WIN64 (where `stdcall` is unified with the -C calling convention). +!!! note + Currently, only the platform-default C calling convention is supported. This means that + `@cfunction`-generated pointers cannot be used in calls where WINAPI expects `stdcall` + function on 32-bit windows, but can be used on WIN64 (where `stdcall` is unified with the + C calling convention). A classic example is the standard C library `qsort` function, declared as: @@ -187,10 +188,11 @@ void qsort(void *base, size_t nmemb, size_t size, 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 +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 objects (which define `<`): +calling `qsort` and passing arguments, we need to write a comparison function: ```jldoctest mycompare julia> function mycompare(a, b)::Cint @@ -199,8 +201,8 @@ julia> function mycompare(a, b)::Cint mycompare (generic function with 1 method) ``` -Notice that we have to be careful about the return type: `qsort` expects a function returning -a C `int`, so we annotate the return type of the function to be sure it returns a `Cint`. +``qsort`` expects a comparison function that return a C ``int``, so we annotate the return type +to be ``Cint``. In order to pass this function to C, we obtain its address using the macro `@cfunction`: @@ -234,12 +236,14 @@ julia> A ``` As can be seen, `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). +[takes care of converting the array to a `Ptr{Cdouble}`](@ref automatic-type-conversion)), computing +the size of the element type in bytes, 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 +## [Mapping C Types to Julia](@id 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 @@ -247,10 +251,9 @@ 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](https://github.com/ihnorton/Clang.jl) can be used to auto-generate -Julia code from a C header file.) +file.[^2] -### Auto-conversion: +### [Automatic Type Conversion](@id automatic-type-conversion) Julia automatically inserts calls to the [`Base.cconvert`](@ref) function to convert each argument to the specified type. For example, the following call: @@ -276,9 +279,9 @@ For example, this is used to convert an `Array` of objects (e.g. strings) to an converting an object to a native pointer can hide the object from the garbage collector, causing it to be freed prematurely. -### Type Correspondences: +### Type Correspondences -First, a review of some relevant Julia type terminology: +First, let's review some relevant Julia type terminology: | Syntax / Keyword | Example | Description | |:----------------------------- |:------------------------------------------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | @@ -347,7 +350,7 @@ This can help for writing portable code (and remembering that an `int` in C is n an `Int` in Julia). -**System Independent:** +**System Independent Types** | C name | Fortran name | Standard Julia Alias | Julia Base Type | |:------------------------------------------------------- |:------------------------ |:-------------------- |:-------------------------------------------------------------------------------------------------------------- | @@ -388,7 +391,7 @@ to skip the check, you can use `Ptr{UInt8}` as the argument type. `Cstring` can the [`ccall`](@ref) return type, but in that case it obviously does not introduce any extra checks and is only meant to improve readability of the call. -**System-dependent:** +**System Dependent Types** | C name | Standard Julia Alias | Julia Base Type | |:--------------- |:-------------------- |:-------------------------------------------- | @@ -418,11 +421,11 @@ checks and is only meant to improve readability of the call. (`void`) but do return, use `Cvoid` instead. !!! note - For `wchar_t*` arguments, the Julia type should be [`Cwstring`](@ref) (if the C routine expects a NUL-terminated - string) or `Ptr{Cwchar_t}` otherwise. Note also that UTF-8 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). + For `wchar_t*` arguments, the Julia type should be [`Cwstring`](@ref) (if the C routine expects a + NUL-terminated string) or `Ptr{Cwchar_t}` otherwise. Note also that UTF-8 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}}` @@ -471,7 +474,7 @@ checks and is only meant to improve readability of the call. !!! note A C function declared to return `Cvoid` will return the value `nothing` in Julia. -### Struct Type correspondences +### 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 `struct` definition with the same @@ -485,29 +488,32 @@ 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 +You can get an 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 can be expressed with `NTuple`: +Arrays of parameters can be expressed with `NTuple`. For example, the struct in C notation written as -in C: ```c struct B { int A[3]; }; + b_a_2 = B.A[2]; ``` -in Julia: + +can be written in Julia as + ```julia struct B A::NTuple{3, Cint} end + b_a_2 = B.A[3] # note the difference in indexing (1-based in Julia, 0-based in C) ``` -Arrays of unknown size (C99-compliant variable length structs specified by `[]` or `[0]`) are not directly supported. -Often the best way to deal with these is to deal with the byte offsets directly. +Arrays of unknown size (C99-compliant variable length structs specified by `[]` or `[0]`) are not directly +supported. Often the best way to deal with these is to deal with the byte offsets directly. For example, if a C library declared a proper string type and returned a pointer to it: ```c @@ -602,7 +608,7 @@ In Julia code wrapping calls to external C routines, ordinary (non-pointer) data to be of type `T` inside the [`ccall`](@ref), as they are passed by value. For C code accepting pointers, [`Ref{T}`](@ref) should generally be used for the types of input arguments, allowing the use of pointers to memory managed by either Julia or C through the implicit call to [`Base.cconvert`](@ref). - In contrast, pointers returned by the C function called should be declared to be of output type +In contrast, pointers returned by the C function called should be declared to be of output type [`Ptr{T}`](@ref), reflecting that the memory pointed to is managed by C only. Pointers contained in C structs should be represented as fields of type `Ptr{T}` within the corresponding Julia struct types designed to mimic the internal structure of corresponding C structs. @@ -692,8 +698,8 @@ For translating a C return type to Julia: * 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 `jl_value_t**`) + * a return type of `Ref{Any}` is invalid, it should either be `Any` (corresponding to + `jl_value_t*`) or `Ptr{Any}` (corresponding to `jl_value_t**`) * C **MUST NOT** modify the memory returned via `Ref{T}` if `T` is an `isbits` type * If the memory is owned by C: @@ -718,39 +724,9 @@ ccall(:foo, Cvoid, (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. +## C Wrapper Examples -A prefix `&` is used on an argument to [`ccall`](@ref) 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. - -```julia -function compute_dot(DX::Vector{Float64}, DY::Vector{Float64}) - @assert length(DX) == length(DY) - n = length(DX) - incx = incy = 1 - product = ccall((:ddot_, "libLAPACK"), - Float64, - (Ref{Int32}, Ptr{Float64}, Ref{Int32}, Ptr{Float64}, Ref{Int32}), - n, DX, incx, DY, incy) - return product -end -``` - -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 `mutable struct`). However, -even for immutable structs 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`. - -## Some Examples of C Wrappers - -Here is a simple example of a C wrapper that returns a `Ptr` type: +Let's start with a simple example of a C wrapper that returns a `Ptr` type: ```julia mutable struct gsl_permutation @@ -778,12 +754,12 @@ function `gsl_permutation_alloc`. As user code never has to look inside the `gsl struct, the corresponding Julia wrapper simply needs a new type declaration, `gsl_permutation`, that has no internal fields and whose sole purpose is to be placed in the type parameter of a `Ptr` type. The return type of the [`ccall`](@ref) is declared as `Ptr{gsl_permutation}`, since -the memory allocated and pointed to by `output_ptr` is controlled by C (and not Julia). +the memory allocated and pointed to by `output_ptr` is controlled by C. The input `n` is passed by value, and so the function's input signature is simply declared as `(Csize_t,)` without any `Ref` or `Ptr` necessary. (If the wrapper was calling a Fortran function instead, the corresponding function input -signature should instead be `(Ref{Csize_t},)`, since Fortran variables are +signature would instead be `(Ref{Csize_t},)`, since Fortran variables are passed by pointers.) Furthermore, `n` can be any type that is convertible to a `Csize_t` integer; the [`ccall`](@ref) implicitly calls [`Base.cconvert(Csize_t, n)`](@ref). @@ -806,11 +782,12 @@ end Here, the input `p` is declared to be of type `Ref{gsl_permutation}`, meaning that the memory that `p` points to may be managed by Julia or by C. A pointer to memory allocated by C should be of type `Ptr{gsl_permutation}`, but it is convertible using [`Base.cconvert`](@ref) and therefore -can be used in the same (covariant) context of the input argument to a [`ccall`](@ref). A pointer -to memory allocated by Julia must be of type `Ref{gsl_permutation}`, to ensure that the memory -address pointed to is valid and that Julia's garbage collector manages the chunk of memory pointed -to correctly. Therefore, the `Ref{gsl_permutation}` declaration allows pointers managed by C or -Julia to be used. + +Now if you look closely enough at this example, you may notice that it is incorrect, given our explanation +above of preferred declaration types. Do you see it? The function we are calling is going to free the +memory. This type of operation cannot be given a Julia object (it will crash or cause memory corruption). +Therefore, it may be preferable to declare the `p` type as `Ptr{gsl_permutation }`, to make it harder for the +user to mistakenly pass another sort of object there than one obtained via `gsl_permutation_alloc`. If the C wrapper never expects the user to pass pointers to memory managed by Julia, then using `p::Ptr{gsl_permutation}` for the method signature of the wrapper and similarly in the [`ccall`](@ref) @@ -841,19 +818,33 @@ end ``` The C function wrapped returns an integer error code; the results of the actual evaluation of -the Bessel J function populate the Julia array `result_array`. This variable can only be used -with corresponding input type declaration `Ref{Cdouble}`, since its memory is allocated and managed -by Julia, not C. The implicit call to [`Base.cconvert(Ref{Cdouble}, result_array)`](@ref) unpacks +the Bessel J function populate the Julia array `result_array`. This variable is declared as a +`Ref{Cdouble}`, since its memory is allocated and managed by Julia. The implicit call to +[`Base.cconvert(Ref{Cdouble}, result_array)`](@ref) unpacks the Julia pointer to a Julia array data structure into a form understandable by C. -Note that for this code to work correctly, `result_array` must be declared to be of type `Ref{Cdouble}` -and not `Ptr{Cdouble}`. The memory is managed by Julia and the `Ref` signature alerts Julia's -garbage collector to keep managing the memory for `result_array` while the [`ccall`](@ref) executes. -If `Ptr{Cdouble}` were used instead, the [`ccall`](@ref) may still work, but Julia's garbage -collector would not be aware that the memory declared for `result_array` is being used by the -external C function. As a result, the code may produce a memory leak if `result_array` never gets -freed by the garbage collector, or if the garbage collector prematurely frees `result_array`, -the C function may end up throwing an invalid memory access exception. +## Fortran Wrapper Example + +The following example utilizes ccall to call a function in a common Fortran library (libBLAS) to +computes a dot product. Notice that the argument mapping is a bit different here than above, as +we need to map from Julia to Fortran. On every argument type, we specify `Ref` or `Ptr`. This +mangling convention may be specific to your fortran compiler and operating system, and is likely +undocumented. However, wrapping each in a `Ref` (or `Ptr`, where equivalent) is a frequent +requirement of Fortran compiler implementations: + +```julia +function compute_dot(DX::Vector{Float64}, DY::Vector{Float64}) + @assert length(DX) == length(DY) + n = length(DX) + incx = incy = 1 + product = ccall((:ddot_, "libLAPACK"), + Float64, + (Ref{Int32}, Ptr{Float64}, Ref{Int32}, Ptr{Float64}, Ref{Int32}), + n, DX, incx, DY, incy) + return product +end +``` + ## Garbage Collection Safety @@ -868,8 +859,9 @@ 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`](@ref) and [`String`](@ref) 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 [`unsafe_wrap`](@ref) -which, for performance reasons, shares (or can be told to take ownership of) the underlying buffer. +safe to free (or alter) the original data without affecting Julia. A notable exception is +[`unsafe_wrap`](@ref) 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 @@ -892,8 +884,8 @@ with `$`). For this reason, `eval` is typically only used to form top-level defi when wrapping libraries that contain many similar functions. A similar example can be constructed for [`@cfunction`](@ref). -However, doing this will also be very slow and leak memory, so you should usually avoid this and instead keep reading. -The next section discusses how to use indirect calls to efficiently accomplish a similar effect. +However, doing this will also be very slow and leak memory, so you should usually avoid this and instead keep +reading. The next section discusses how to use indirect calls to efficiently accomplish a similar effect. ## Indirect Calls @@ -962,8 +954,8 @@ and load in the new changes. One can either restart Julia or use the ```julia lib = Libdl.dlopen("./my_lib.so") # Open the library explicitly. sym = Libdl.dlsym(lib, :my_fcn) # Get a symbol for the function to call. -ccall(sym, ...) # Use the pointer `sym` instead of the (symbol, library) tuple (remaining arguments are the same). -Libdl.dlclose(lib) # Close the library explicitly. +ccall(sym, ...) # Use the pointer `sym` instead of the (symbol, library) tuple (remaining arguments are the +same). Libdl.dlclose(lib) # Close the library explicitly. ``` Note that when using `ccall` with the tuple input @@ -974,8 +966,8 @@ and it may not be explicitly closed. The second argument to [`ccall`](@ref) 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` (no-op on 64-bit Windows). For example (from -`base/libc.jl`) we see the same `gethostname`[`ccall`](@ref) as above, but with the correct +Other supported conventions are: `stdcall`, `cdecl`, `fastcall`, and `thiscall` (no-op on 64-bit Windows). +For example (from `base/libc.jl`) we see the same `gethostname`[`ccall`](@ref) as above, but with the correct signature for Windows: ```julia @@ -1036,12 +1028,14 @@ back to a Julia object reference by [`unsafe_pointer_to_objref(ptr)`](@ref). (Ju can be converted to `jl_value_t*` pointers, as `Ptr{Cvoid}`, by calling [`pointer_from_objref(v)`](@ref).) The reverse operation (writing data to a `Ptr{T}`), can be performed using [`unsafe_store!(ptr, value, [index])`](@ref). -Currently, this is only supported for primitive types or other pointer-free (`isbits`) immutable struct types. +Currently, this is only supported for primitive types or other pointer-free (`isbits`) immutable struct +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 (primitive type or immutable struct), the function [`unsafe_wrap(Array, ptr,dims, own = false)`](@ref) +If the pointer of interest is a plain-data array (primitive type or immutable struct), the function +[`unsafe_wrap(Array, ptr,dims, own = false)`](@ref) 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 @@ -1079,3 +1073,12 @@ For more details on how to pass callbacks to C libraries, see this [blog post](h For direct C++ interfacing, see the [Cxx](https://github.com/Keno/Cxx.jl) package. For tools to create C++ bindings, see the [CxxWrap](https://github.com/JuliaInterop/CxxWrap.jl) package. + + + +[^1]: 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. + The point above is that the cost of actually doing foreign function call is about the same as doing a call in either native language. + +[^2]: The [Clang package](https://github.com/ihnorton/Clang.jl) can be used to auto-generate Julia code + from a C header file.