Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing Julia datatypes to C++ #22

Open
wbhart opened this issue Nov 7, 2014 · 29 comments
Open

Passing Julia datatypes to C++ #22

wbhart opened this issue Nov 7, 2014 · 29 comments

Comments

@wbhart
Copy link

wbhart commented Nov 7, 2014

We have done the following using Cxx

using Cxx

cxx"""class Bill {
         public:
            int64_t a;
            int64_t b;
       };"""

 type Bill
          a::Int
          b::Int
       end

s = Bill(1, 2)

cxx"""#include <stdio.h>"""

cxx"""void myfn(Bill * m) { printf("%ld, %ld", m->a, m->b);}"""

Now we are looking for a way to pass s into the function myfn. Can you give an example of how to do this using Cxx?

@maxruby
Copy link
Contributor

maxruby commented Nov 7, 2014

I know this works, but I also would like to know how to pass entire Julia types to C++ ...

    using Cxx

    cxx"""
        #include <iostream>
    """

    type Bill
      a::Int64
      b::Int64
    end

   s = Bill(1,2)

    cxx"""
    class Bill {
             public:
                int64_t a = $(s.a);
                int64_t b = $(s.b);
           };

    void myfn(Bill m) {
        std::cout << "The bill is: " << m.a << "," << m.b << std::endl;
    };
    """

    bill = @cxxnew Bill()
    @cxx myfn(bill)

@Keno
Copy link
Collaborator

Keno commented Nov 7, 2014

I don't currently have any support to pass julia types to C++. This could be supported probably, but there's some issues with respect to semantics. Somehow we need to annotate that the julia type Bill is the same as the C++ class Bill. What is possible right now of course, is just passing around the C++ types as if they were julia types. Admittedly, it's not as nice as native julia objects, because you can't just type bill.a, but I'm planning to do that once we can overload getfield. In short, I'll have to think about it.

@wbhart
Copy link
Author

wbhart commented Nov 7, 2014

It should be possible to do this in theory, since the & operator does this in ccall, and it works just fine. However, that seems to be baked into the compiler and is not defined in a Julia library as far as I can tell. One real hack is to add a function to bootstrap.cpp

extern "C" {
void * to_ptr(void * a) { return a; }
}

All it does is return whatever pointer it is passed. But the important thing is it should be ccall'able. Thus on the Julia side you have:

function toPtr{T}(a::T)
   ccall(:to_ptr, Ptr{Void}, (Ptr{T},), &a)
end

aa = pcpp"Bill"(toPtr(s))
@cxx myfn(aa)

Unfortunately, it seems that ccall can't currently call functions declared extern "C" by cxx, otherwise you could do this without having to bake this into bootstrap.cpp. And the above will be much slower if it actually has to call out to an external library too.

@Keno
Copy link
Collaborator

Keno commented Nov 7, 2014

If you're willing to do the cast manually, I can probably implement this fairly easily.

@wbhart
Copy link
Author

wbhart commented Nov 7, 2014

I don't think that would be a problem for our application. The speed is going to be an issue though. I'm just really tempted to use pointer_from_objref and manually increment the pointer to skip the gc header that julia adds to its datatypes.

@rhl-
Copy link

rhl- commented Nov 7, 2014

Off topic, but, I am on a phone and can't easily open a new thread.

How do you set include and link paths?

Also, is there a way to make a Cxx shell within Julia, where you can just
type the c++ and it wraps around the appropriate calls? This would be a
"killer app"
On Nov 7, 2014 1:35 PM, "wbhart" notifications@github.com wrote:

I don't think that would be a problem for our application. The speed is
going to be an issue though.


Reply to this email directly or view it on GitHub
#22 (comment).

@Keno
Copy link
Collaborator

Keno commented Nov 7, 2014

That almost works, except for the GC rooting issue. I'm imagining something like

@cxx myfn(jpcpp"Bill"(s))

which takes care of the gc rooting of s properly but otherwise is basically just that.

@Keno
Copy link
Collaborator

Keno commented Nov 7, 2014

@rhl- For include paths, see https://github.com/Keno/Cxx.jl/blob/master/test/llvmincludes.jl. For link paths, just dlopen the appropriate shared library and it'll be able to find the symbols. There's no Cxx shell, but that shouldn't be too hard.

@wbhart
Copy link
Author

wbhart commented Nov 7, 2014

@Keno yes that is exactly what we need. I cannot for the life of me work out how julia implements its own & operator, otherwise I'd implement it myself even.

I actually really can't understand why pointer_from_objref doesn't handle gc rooting itself. That doesn't make sense to me.

@wbhart
Copy link
Author

wbhart commented Nov 7, 2014

I wonder if it could be done with llvm_call. It looks to me like llvm_call might already convert julia types to pointers for its arguments in much the same way as & operates for ccall. It should just be a matter of returning that pointer.

@Keno
Copy link
Collaborator

Keno commented Nov 7, 2014

Yes, that's correct. It's just a matter of threading it through the Cxx macro processing frontend. I'll get to it soon (today).

@wbhart
Copy link
Author

wbhart commented Nov 7, 2014

OK, I think I'll let you work on it. It looks like %jl_value_t* are passed into functions, but llvmcall complains that this is an undefined type. I can't find any examples anywhere that actually use llvmcall for anything other than bitstypes or tuples of such.

@maxruby
Copy link
Contributor

maxruby commented Nov 8, 2014

Is it possible to simply add the jl_type to the list of types in bootstrap.cpp?
I also can not find examples for passing anything other than bitstypes.

@malex984
Copy link

malex984 commented Nov 8, 2014

i would try to use the embedded Julia api from julia.h... at least in some form...
do you avoid it by going deeper to llvm level and using some implementational details on julia internals?

please forgive my ignorance about Julia.

@maxruby
Copy link
Contributor

maxruby commented Nov 8, 2014

Embedding Julia code in C with julia.h and then using extern C to call it in C++ seems reasonable,
but if I understood correctly, the problem is handling the GC for julia types?

@malex984
Copy link

malex984 commented Nov 8, 2014

Well, looking at https://github.com/JuliaLang/julia/blob/master/examples/embedding.c it seems to me that one can use JL_GC_* for that. Did i get that wrong?

@malex984
Copy link

by the way, i learned that one can embed Python inside Julia.
does anybody know whether it is possible to access julia objects from Python running embedded inside Julia runtime???

@malex984
Copy link

according to http://julia.readthedocs.org/en/latest/manual/embedding/ one has to do a lot of boxing and unboxing somewhat similarly to C#... after looking at Cxx sources it seems me that that Cxx does not do embedding like that but rather something like transparent (to Julia) runtime extension... but again i have seen VERY few Julia's own internal types or calls...

@Keno could you please clarify how do you achieve that? or am i totally wrong in my guesses?

@Keno
Copy link
Collaborator

Keno commented Nov 10, 2014

Cxx.jl is built on top of llvmcall. It basically never has to deal with implementation details of julia (in a few places it does and that'll have to change if the julia ABI changes). In particular llvmcall takes care of GC rooting.

@wbhart I have the jpcpp thing done, but there's a few changes in Julia and LLVM needed that I need to get in first.

@maxruby
Copy link
Contributor

maxruby commented Nov 10, 2014

@Keno I have put together a package to integrate OpenCV in Julia using Cxx which I intend to upload soon. The C++ interface is working great in Julia. However, the challenge now is to pass Julia objects (images and arrays) to C++. Do you think jpcpp will be able to take care of passing Julia multidimensional arrays or other abstract Julia types? I think I understand the llvmcall idea and how this is being implemented in Cxx. However, it is much less clear how you tweak the low level interface to pass the Julia types. Can you explain how you go about doing this? Sorry for my ignorance.

@Keno
Copy link
Collaborator

Keno commented Nov 10, 2014

I'd have to look at a more specific use case to be able to answer that (there may be multiple approaches).

@maxruby
Copy link
Contributor

maxruby commented Nov 10, 2014

Here is a very plain case:

# Say that we have an image opened with `Images.jl`
julia> img = imread()
   RGB4 Image with:
   data: 512x512 Array{RGB4{UfixedBase{Uint8,8}},2}
      properties:
      imagedescription: <suppressed>
      spatialorder:  x y
      pixelspacing:  1 1

# Convert to an array
julia> imA = convert(Array, img)
512x512 Array{RGB4{UfixedBase{Uint8,8}},2}:

=> pass imA array to C++ ?
=> convert to a suitable representation to process in OpenCV (obviously this is case by case)
=> pass C++ Mat array back to Julia for analysis?

@Keno
Copy link
Collaborator

Keno commented Nov 10, 2014

Well, I guess the question is whether you want to write the conversion in julia or C++ code. In either case, it might be simplest to expose a julia object to C++ as a templated value, e.g.:

some_random_julia_function(a::MyType) = ...
cxx"""
void foo(jl<$(MyType)> a)
{
  $:(some_random_julia_function)(a)
}
"""

@wbhart
Copy link
Author

wbhart commented Nov 10, 2014

@Keno that's great news. Looking forward to giving it a try.

@maxruby
Copy link
Contributor

maxruby commented Nov 10, 2014

@Keno Thanks. I see what you mean, and it sounds very reasonable. However, this looks much like passing a Julia expression , e.g., $:(println("some word")). I was thinking more about the possibility of displaying a Julia image type (jl_image) with an OpenCV C++ function, e.g., cv::imshow(jl_image) after doing some image filtering or thresholding. I understand that this comes down to a case-by-case conversion of the jl_image type to the C++ equivalent.

@Keno
Copy link
Collaborator

Keno commented Nov 11, 2014

Hmm, yeah, I'll have to think abut how to best describe the conversions.

@maxruby
Copy link
Contributor

maxruby commented Nov 11, 2014

This package is great and I really appreciate your contribution. In case you are interested, I have put together a README.md file that could be used to help others get started with Cxx.jl. Let me know if this is of any interest - otherwise, I will include it in my package.

@Keno
Copy link
Collaborator

Keno commented Nov 11, 2014

Sure. Probably best to submit it as a pull request against this repo's README.md.

@jhasse
Copy link

jhasse commented Apr 17, 2015

Just for convenience: #23

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants