Julia calling C: A minimal example

This blog is a “Hello World” example of Julia calling C.

We start of by at bit of C code we want to call from Julia. We write the following in calc_mean.c

double mean(double a, double b) {
  return (a+b) / 2;
}

To build the library, we need to create a Makefile

CC=gcc 
 
CFLAGS=-c -Wall -fPIC
 
SOURCES=calc_mean.c 
OBJECTS=$(SOURCES:.c=.o)
 
.c.o:
    $(CC) $(CFLAGS) $< -o $@ 
 
lib: $(OBJECTS)
    $(CC) -shared -fPIC -o libmean.so $(OBJECTS)
 
clean:
    rm *.o *.so

The option fPIC and -shared are essential for Julia to be able to resolve the function in our library. Now we are almost ready to build our library. From the bash terminal we invoke:

make lib

This will generate a libmean.so file.

In Julia we call the function in our c library by

x=ccall((:mean,"libmean"),Float64,(Float64,Float64),2.0,5.0)
println(x)
3.5

For this to work,

  • Julia must be running either on the same path where libmean.so resides,
  • the path to libmean.so is in LD_LIBRARY_PATH, or
  • the path to the library is pushed to Libdl.DL_LOAD_PATH via

push!(Libdl.DL_LOAD_PATH,"path_to_libmean.so")

P.S. Thanks to Christopher Rackauckas for tips on Julia highlighting.

7 thoughts on “Julia calling C: A minimal example

  1. Hi Perfectionatic’s

    I’m studying julia and I liked the site. An error occurred while running “make”:

    Makefile:9: *** missing separator. Stop.

    How to solve?

  2. Pingback: Julia calling C: A more minimal example | Perfectionatic's blog

  3. Hello,
    thank you for your post si very helpfull. I’ve already created the library and i’m g¡having this error.
    julia> x=ccall((:mean,”libmean”),Float64,(Float64,Float64),2.0,5.0)
    ERROR: error compiling anonymous: could not load library “libmean”
    I think it’s a problem with the thing that you mentioned at the end but i did
    push!(Libdl.DL_LOAD_PATH,”path_to_libmean.so”) and it still doesnt work. I think i’m doing a stupid thing but i dont know what:
    Could you please help me?

    Thank you very much

    Sara

  4. Hello Sara,

    Just to be sure ”path_to_libmean.so” in the example command is just a string pointing to where your libmean.so lives. For example on a Linux systems, this would look something like “/home/sara/juliacode/meanlib/”. So the basic steps are:
    1. Make sure that “libmean.so” was actually created
    2. Find its full path
    3. Use that path in push!(Libdl.DL_LOAD_PATH,”path_to_libmean.so”)

    Hope this helps.

  5. Am using macOs High Sierra. Tried your example, including push!(Libdl.DL_LOAD_PATH,”path_to_libmean”).
    Got. ERROR: error compiling anonymous: could not load library “libmean” dlopen(libbar.dylib, 1): image not found. Relinked as: “gcc -shared -fPIC -dynamiclib -o libmean.dylib calc_mean.o”. After using “ccall((:mean,”libmean”),Float64,(Float64,Float64),2.0,5.0)”; got result: ERROR: ccall: could not find function mean in library libmean . It seems that the library was found but not the function. Is it possible for Julia to call user defined c functions on a macintosh? Though, I was able to call libc functions from Julia on a Macintosh.

    my regards,
    Ihor Jakowec

  6. I found an answer to my own question. The following works on macOs High Sierra (Darwin).
    Instead of creating a library with the “.so” extension, create a dynamically linked library with
    the “.dylib” extension. The c and the Julia code, posted by perfectionatic, does not need any
    modification. However, the makefile with the following modifications, will work with Darwin:

    CC=gcc

    CFLAGS=-c -Wall -fPIC

    SOURCES=calc_mean.c
    OBJECTS=$(SOURCES:.c=.o)

    .c.o:
    $(CC) $(CFLAGS) $< -o $@ lib: $(OBJECTS) $(CC) -shared -fPIC -dynamiclib -o libmean.so $(OBJECTS) clean: rm *.o *.dylib I found this blog really useful. my regards, Ihor Jakowec

Leave a Reply