Wrapping C++ libraries to Julia: part 1

{% include_relative wrapping.html %}

This is a short note how to get started of wrapping C++ libraries to Julia. Two approaches exists: the use of Cxx.jl or use of CxxWrap.jl. This first blog post contains a minimum working example, how to create a shared library and wrap it to Julia.

In [1]:
cd(tempdir())
pwd()
Out[1]:
"/tmp"

Normally it makes sense to define wrapper in a separate file, but like said, let's keep things as simple as possible first.

In [2]:
hello_content = """
#include <string>

std::string greet()
{
   return "hello, world";
}

// Wrapper start

#include "jlcxx/jlcxx.hpp"

JLCXX_MODULE define_julia_module(jlcxx::Module& mod)
{
  mod.method("greet", &greet);
}
"""

open("hello.cpp", "w") do fid write(fid, hello_content) end
Out[2]:
204

Header files for Julia and CxxWrap is needed to compile code to object file.

In [3]:
using CxxWrap
cxxwrap_include_path = abspath(dirname(pathof(CxxWrap)), "..", "deps", "usr", "include")
julia_include_path = abspath(Sys.BINDIR, Base.INCLUDEDIR, "julia")
cxxwrap_include_path, julia_include_path
Out[3]:
("/home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/include", "/opt/julia-1.2.0/include/julia")
In [4]:
run(`g++ -c -I$cxxwrap_include_path -I$julia_include_path -fPIC hello.cpp`)
Out[4]:
Process(`g++ -c -I/home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/include -I/opt/julia-1.2.0/include/julia -fPIC hello.cpp`, ProcessExited(0))

Then we can build the shared library:

In [5]:
cxxwrap_libfile = CxxWrap.libcxxwrap_julia
cxxwrap_libpath = dirname(cxxwrap_libfile)
julia_libpath = abspath(julia_include_path, "..", "..", "lib")
cxxwrap_libfile, cxxwrap_libpath, julia_libpath
Out[5]:
("/home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/lib/libcxxwrap_julia.so", "/home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/lib", "/opt/julia-1.2.0/lib")
In [6]:
run(`g++ hello.o -shared -o libhello.so -L/opt/julia/lib -Wl,-rpath,$cxxwrap_libpath: $cxxwrap_libfile -ljulia`)
Out[6]:
Process(`g++ hello.o -shared -o libhello.so -L/opt/julia/lib -Wl,-rpath,/home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/lib: /home/jukka/.julia/packages/CxxWrap/sarOk/deps/usr/lib/libcxxwrap_julia.so -ljulia`, ProcessExited(0))
In [7]:
;ls -l /tmp/libhello.so
-rwxrwxr-x 1 jukka jukka 82160 syys  26 16:03 /tmp/libhello.so

There it is! The last thing to do is to write a short Julia code which utilizes a shared library:

In [8]:
module CppHello
  using CxxWrap
  @wrapmodule(joinpath(".","libhello"))

  function __init__()
    @initcxx
  end
end
Out[8]:
Main.CppHello
In [9]:
CppHello.greet()
Out[9]:
"hello, world"

Of course, several things can be done more efficiently. For example, usually wrapper should be written to separate file and the whole process of compiling a shared library should be done using Makefile. We get into these improvements in further blog posts.