Calling C and Python
Prerequisites: Type stability
Julia can call C (and Fortran) libraries directly, with no wrapper code and no overhead beyond a normal C function call.
ccall and @ccall
n = ccall(:strlen, Csize_t, (Cstring,), "hello")
println(n)
m = @ccall strlen("hello, world"::Cstring)::Csize_t
println(m, " ", typeof(m))
println(@ccall abs(-42::Cint)::Cint)
exponent = Ref{Cint}(0)
mantissa = @ccall frexp(40.0::Cdouble, exponent::Ptr{Cint})::Cdouble
println(mantissa, " * 2^", exponent[])
5
12 UInt64
42
0.625 * 2^6
ccall(name, ReturnType, (ArgTypes...,), args...)or the more readable@ccall name(arg::Type, ...)::ReturnType.- C types have Julia names:
Cint,Cdouble,Csize_t,Cstring,Ptr{T}. - A
Refpasses a pointer to a value the C function can write to —frexpstores the exponent there.
Your own C library
// illustrative — mathlib.c, compiled with:
// gcc -shared -fPIC -O2 -o libmathlib.so mathlib.c (Linux; .dll on Windows, .dylib on macOS)
double dot(const double *a, const double *b, int n) {
double s = 0;
for (int i = 0; i < n; i++) s += a[i] * b[i];
return s;
}
# illustrative — needs the compiled library next to the script
const LIB = joinpath(@__DIR__, "libmathlib")
cdot(a::Vector{Float64}, b::Vector{Float64}) =
@ccall LIB.dot(a::Ptr{Cdouble}, b::Ptr{Cdouble}, length(a)::Cint)::Cdouble
println(cdot([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]))
32.0
Julia arrays of Float64 are laid out like C arrays, so they're passed
as pointers without copying. Packages ship compiled libraries as
JLL packages (built with BinaryBuilder.jl), so users don't need
a compiler. Learn more about C itself in the C course.
Python with PythonCall.jl
PythonCall.jl lets Julia use any Python package (and juliacall lets Python call Julia). It manages its own Python environment with CondaPkg.jl:
# illustrative — needs PythonCall and the numpy Python package
using PythonCall
np = pyimport("numpy")
a = np.array([1.0, 2.0, 3.0])
println(np.mean(a))
total = pyconvert(Float64, np.sum(a))
println(total + 1)
Python objects appear in Julia as Py values; pyconvert(T, x)
converts them to Julia types. (The older PyCall.jl package does the
same job with a different API.) This is handy for libraries that exist
only in Python — see the Python course. RCall.jl
does the same for R.