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 aCppPtr
,CppRef
orCppValue
)@cxx m->foo(args...)
To embed C++ functions in Julia, there are two main approaches:
# Using @cxx (e.g.):
cxx""" void cppfunction(args){ . . .} """ => cppfunction(args)
# Using icxx (e.g.):
julia_function (args) icxx""" *code here* """ end
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() = mycppfunction()
Run the function.
julia_function()
Pass numeric arguments from Julia to C++
jnum = 10
cxx"""
void printme(int x) {
std::cout << x << std::endl;
}
"""
printme(jnum)
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;
}
"""
printme(pointer("John"))
Pass a Julia expression to C++
cxx"""
void testJuliaPrint() {
$:(println("\nHello whirled!")::Nothing);
}
"""
testJuliaPrint()
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
Nextjournal tries to pass values when it detects a pause for interactive input.
playing();
Using C++ enums
using Cxx
cxx"""
class Klassy {
public:
enum Foo { Bar, Baz };
static Foo exec(Foo x) { return x; }
};
"""
Access enum
Klassy::Bar
Pass enum as an argument
Klassy::exec( (Klassy::Baz))
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;
}
};"""
using Dates
hello_class = Hello()
tstamp = string(Dates.now())
hello_class -> hello_world(pointer(tstamp))
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
#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;
}
Compiling into shared library.
g++ -shared -fPIC ArrayMaker.cpp -o libArrayMaker.so
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")
Creating class object
# Creating class object
maker = ArrayMaker(5, 2.0)
arr = maker->fillArr()
unsafe_wrap(Array, arr, 5)
Setup
Install Cxx.
]up
]add Cxx
]precompile
]test Cxx