Open wbhart opened 10 years ago
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)
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.
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.
If you're willing to do the cast manually, I can probably implement this fairly easily.
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.
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 https://github.com/Keno/Cxx.jl/issues/22#issuecomment-62217462.
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.
@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.
@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.
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.
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).
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.
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.
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.
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?
Well, looking at https://github.com/JuliaLang/julia/blob/master/examples/embedding.c it seems to me that one can use JLGC* for that. Did i get that wrong?
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???
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?
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.
@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.
I'd have to look at a more specific use case to be able to answer that (there may be multiple approaches).
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?
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)
}
"""
@Keno that's great news. Looking forward to giving it a try.
@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.
Hmm, yeah, I'll have to think abut how to best describe the conversions.
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.
Sure. Probably best to submit it as a pull request against this repo's README.md.
Just for convenience: #23
We have done the following using Cxx
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?