Simplest way to wrap virtual c++ class

ccall
cxx

#1

Hi,

I would like to wrap a C++ library that works with virtual methods. If I understand well, the problem boils down to calling the class Base for the reduced library below (so we have a simple working example) from Julia. Note that I made a new class B so I can provide a function history_f h from Julia.

Ultimately, history_f h will be the right hand side of a differential equation. Hence, it is likely to be called many times.

I would appreciate if you can provide any advice about wthethger to use Cxx.jl or CxxWrap.jl to do this. What will be the simplest / most efficient?

Thank you for your help,

Best regards

#include <iostream>

typedef double (*history_f) (double); 
double fex(double x){return -1.;};

class Base
{
    virtual double history(double) = 0;
    public:
    void solve(){
        for (int i=0;i<3;i++){
            std::cout<<history((double) i)<<" \n";
            }
    }
}    ;

class A:public Base
{
    double history(double x){return x;}   
};

class B:public Base
{
    public:
    B(history_f h){f=h;}
    double history(double x){return f(x);}

    history_f f;    
};




int main()
{
    A a;
    a.solve();
    std::cout<<"ok\n";
    B b(fex);
    b.solve();
    std::cout<<"ok\n";
}

#2

For a small number of methods – on the order of, say, under a few 10s of signatures – the simplest way is almost always to create an extern C { ... } wrapper, which can be done with no knowledge of or dependency on julia.h.

As far as Cxx and CxxWrap:

  • Cxx operates at LLVM IR level and can potentially do aggressive cross-language inlining, which could give some performance edge for very hot code.
  • the advantage of both (in somewhat different ways) is they have a lot of logic built-in already for working with, e.g., Julia arrays. This can save time if your interfaces are complicated.

The disadvantage of Cxx is complex build and distribution issues; CxxWrap allows localization of complexity to the developer side because binding shared libraries can be precompiled (as can the dependent Julia wrappers, which is helpful for end-user experience).


#3

Since this is an interesting example, I added it to the CxxWrap inheritance example

This can be used from Julia like this, assuming the module is called VirtualSolver:

a = VirtualSolver.A()
VirtualSolver.solve(a)

b = VirtualSolver.B(safe_cfunction(x -> 2x, Float64, (Float64,)))
VirtualSolver.solve(b)

#4

Wow thank you for your help! Trying your wrapper, I did

clang++ -shared -std=c++11 -undefined dynamic_lookup -I /Users/rveltz/.julia/v0.6/CxxWrap/deps/src/jlcxx/include -I /Applications/Julia-0.6.app/Contents/Resources/julia/include/julia/ -L/Users/rveltz/.julia/v0.6/CxxWrap/deps/usr/lib/ -L/Applications/Julia-0.6.app/Contents/Resources/julia/lib/ -L/Applications/Julia-0.6.app/Contents/Resources/julia/lib/julia/  -o libVirtualSolver.dylib wrap2.cpp

and then

using CxxWrap
wrap_modules(joinpath(pwd(),"libVirtualSolver"))

and I got

ERROR: could not load library "/Users/rveltz/work/prog_gd/julia/DDEArndt.jl/libVirtualSolver"
dlopen(/Users/rveltz/work/prog_gd/julia/DDEArndt.jl/libVirtualSolver.dylib, 9): Symbol not found: _jl_tls_states
  Referenced from: /Users/rveltz/work/prog_gd/julia/DDEArndt.jl/libVirtualSolver.dylib
  Expected in: flat namespace
 in /Users/rveltz/work/prog_gd/julia/DDEArndt.jl/libVirtualSolver.dylib
Stacktrace:
 [1] dlopen(::String, ::UInt32) at ./libdl.jl:97
 [2] load_modules at /Users/rveltz/.julia/v0.6/CxxWrap/src/CxxWrap.jl:139 [inlined]
 [3] wrap_modules at /Users/rveltz/.julia/v0.6/CxxWrap/src/CxxWrap.jl:359 [inlined] (repeats 2 times)

Can you give me one push please?


#5

I think you need to add -DJULIA_ENABLE_THREADING to the compile flags.


#6

What DDE solver are you wrapping?


#7

I will give a try to this one. I used it in the past and it was very good.