Julia Cxx

This notebook creates a reusable environment with Julia's Cxx package installed in the setup section, and shows off basic usage of the package in the showcase.

Showcase

Adapted from the Cxx examples to show usage of the package on Nextjournal—redistributed under the MIT Expat License.

The Cxx package is Julia's Foreign Function Interface to C++. With it, you can include C++ functions and constructs in Julia code, use shared libraries, and pass data between the two languages.

The main interface provided by Cxx.jl is the @cxx macro. It supports two main usages:

  • Static function call @cxx mynamespace::func(args...)

  • Membercall (where m is a CppPtr, CppRef or CppValue) @cxx m->foo(args...)

To embed C++ functions in Julia, there are two main approaches:

# Using @cxx (e.g.): 
cxx""" void cppfunction(args){ . . .} """ => @cxx cppfunction(args)
# Using icxx (e.g.): 
julia_function (args) icxx""" *code here* """ end
Julia

Embedding a simple C++ function in Julia

# include headers
using Cxx
cxx""" #include<iostream> """  
# Declare the function
cxx"""  
  void mycppfunction() {   
    int z = 0;
    int y = 5;
    int x = 10;
    z = x*y + 2;
    std::cout << "The number is " << z << std::endl;
  }
"""
# Convert C++ to Julia function
julia_function() = @cxx mycppfunction()
5.8s
Cxx Showcase (Julia)
Julia 1.2 Cxx
julia_function (generic function with 1 method)

Run the function.

julia_function()
1.2s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Pass numeric arguments from Julia to C++

jnum = 10
cxx"""
     void printme(int x) {
       std::cout << x << std::endl;
     }
"""
0.5s
Cxx Showcase (Julia)
Julia 1.2 Cxx
true
@cxx printme(jnum)
0.8s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Pass strings from Julia to C++

cxx"""
  void printme(const char *name) {
    // const char* => std::string
    std::string sname = name;
    // print it out
    std::cout << sname << std::endl;
  }
"""
0.2s
Cxx Showcase (Julia)
Julia 1.2 Cxx
true
@cxx printme(pointer("John"))
0.4s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Pass a Julia expression to C++

cxx"""
  void testJuliaPrint() {
    $:(println("\nHello whirled!")::Nothing);
  }
"""
1.8s
Cxx Showcase (Julia)
Julia 1.2 Cxx
true
@cxx testJuliaPrint()
0.6s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Embedding C++ code inside a Julia function

using Cxx
cxx""" #include <iostream> """  
function playing()
    for i = 1:5
        icxx"""
            int tellme;
            std::cout<< "Please enter a number: " << std::endl;
            std::cin >> tellme;
            std::cout<< "\nYour number is "<< tellme << "\n" <<std::endl;
        """
    end
end
1.9s
Cxx Showcase (Julia)
Julia 1.2 Cxx
playing (generic function with 1 method)

Nextjournal tries to pass values when it detects a pause for interactive input.

playing();
0.7s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Using C++ enums

using Cxx
cxx"""
  class Klassy {
    public:
      enum Foo { Bar, Baz };
      static Foo exec(Foo x) { return x; }
  };
"""
0.2s
Cxx Showcase (Julia)
Julia 1.2 Cxx
true

Access enum

@cxx Klassy::Bar
0.8s
Cxx Showcase (Julia)
Julia 1.2 Cxx
CppEnum{Symbol("Klassy::Foo"),UInt32}(0x00000000)

Pass enum as an argument

@cxx Klassy::exec(@cxx(Klassy::Baz))
0.4s
Cxx Showcase (Julia)
Julia 1.2 Cxx
CppEnum{Symbol("Klassy::Foo"),UInt32}(0x00000001)

C++ Hello World class

using Cxx
cxx"""#include <iostream>
  class Hello
    {
      public:
        void hello_world(const char *now){
          std::string snow = now;
          std::cout << "Hello World! Now is " << snow << std::endl;
        }
    };"""
0.2s
Cxx Showcase (Julia)
Julia 1.2 Cxx
true
using Dates
hello_class = @cxxnew Hello()
tstamp = string(Dates.now())
@cxx hello_class -> hello_world(pointer(tstamp))
1.1s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Using C++ with shared libraries

The two code listings below are named, and mounted to the runtime as files.

#ifndef ARRAYMAKER_H
#define ARRAYMAKER_H
class ArrayMaker
{
    private:
        int iNumber;
        float fNumber;
        float* fArr;
    public:
        ArrayMaker(int, float);
        float* fillArr();
};
#endif
ArrayMaker.h
C++
#include "ArrayMaker.h"
#include <iostream>
using namespace std;
ArrayMaker::ArrayMaker(int iNum, float fNum) {
    cout << "Got arguments: " << iNum << ", and " << fNum << endl;
    iNumber = iNum;
    fNumber = fNum;
    fArr = new float[iNumber];
}
float* ArrayMaker::fillArr() {
    cout << "Filling the array" << endl;
    for (int i=0; i < iNumber; i++) {
        fArr[i] = fNumber;
        fNumber *= 2;
    }
    return fArr;
}
ArrayMaker.cpp
C++

Compiling into shared library.

g++ -shared -fPIC ArrayMaker.cpp -o libArrayMaker.so
1.1s
Cxx Showcase (Bash in Julia)
Julia 1.2 Cxx

Importing shared library and header file.

using Cxx, Libdl
const path_to_lib = pwd()
addHeaderDir(path_to_lib, kind=C_System)
Libdl.dlopen(path_to_lib * "/libArrayMaker.so", Libdl.RTLD_GLOBAL)
cxxinclude("ArrayMaker.h")
0.5s
Cxx Showcase (Julia)
Julia 1.2 Cxx

Creating class object

# Creating class object
maker = @cxxnew ArrayMaker(5, 2.0)
0.7s
Cxx Showcase (Julia)
Julia 1.2 Cxx
(class ArrayMaker *) @0x0000000006a0cbc0
arr = @cxx maker->fillArr()
0.5s
Cxx Showcase (Julia)
Julia 1.2 Cxx
Ptr{Float32} @0x0000000006e9a860
unsafe_wrap(Array, arr, 5)
1.4s
Cxx Showcase (Julia)
Julia 1.2 Cxx
5-element Array{Float32,1}: 2.0 4.0 8.0 16.0 32.0

Setup

Install Cxx.

]up
153.5s
Julia 1.2 Cxx (Julia)
]add Cxx
37.2s
Julia 1.2 Cxx (Julia)
]precompile
222.1s
Julia 1.2 Cxx (Julia)
]test Cxx
31.0s
Julia 1.2 Cxx (Julia)
Runtimes (2)