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

Native C FFI in the same manner as D #5853

Closed
bstrie opened this issue Apr 12, 2013 · 15 comments
Closed

Native C FFI in the same manner as D #5853

bstrie opened this issue Apr 12, 2013 · 15 comments
Labels
A-FFI Area: Foreign function interface (FFI) E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. P-low Low priority

Comments

@bstrie
Copy link
Contributor

bstrie commented Apr 12, 2013

@sanxiyn and @jdm have expressed interest in doing this, possibly in the 0.8 cycle.

http://www.reddit.com/r/rust/comments/1c3clf/c_ffi/c9codm1

@bstrie
Copy link
Contributor Author

bstrie commented Apr 12, 2013

Here's a resource describing the level to which D can interface with C :

http://dlang.org/cpp_interface.html

@asb
Copy link

asb commented Apr 19, 2013

It's worth taking a look at what the Julia community have been working on with C support via Clang.jl JuliaInterop/Clang.jl#20

@emberian
Copy link
Member

emberian commented Jul 7, 2013

Still very relevant

@graydon
Copy link
Contributor

graydon commented Jul 11, 2013

just a bug, removing milestone/nomination.

@metajack
Copy link
Contributor

metajack commented Sep 5, 2013

Visiting for triage. Nothing to add.

@klutzy
Copy link
Contributor

klutzy commented Sep 23, 2013

Taking examples from D FFI doc,

int foo(int i, int j, int k);

can be expressed in Rust as

extern "C  " {
    fn foo(i: c_int, j: c_int, k: c_int) -> c_int;
}

This is straightforward; I've locally tuned rustc with tiny proof-of-concept mangler and it worked successfully.

However, if C code is in some namespace e.g.

namespace A {
    namespace B {
        int foo(int i, int j, int k);
    }
}

then we need to specify namespace in Rust since mangled function name contains it (at least on linux). One way to achieve that is:

#[namespace = "A::B"]
extern "C  " {
    fn foo(i: c_int, j: c_int, k: c_int) -> c_int;
}

I didn't tried to implement it, but it is still not hard; the only stuff I have to do is name mangling.

Classes and methods are more challenging: we need discussion on syntax. Again from D example,

class D {
public:
   virtual int bar(int i, int j, int k);
}
D *getD();

How this can be expressed in Rust? I've initially thought:

extern "C  " {
    trait D {
        fn bar(i: c_int, j: c_int, k: c_int) -> c_int;
    }
}

but D* getD(); becomes tricky since we don't have raw pointer to traits. Maybe we can treat extern C trait as structs as well, but it may be unintuitive for users.

@pnkfelix
Copy link
Member

  1. Could this be a motivation for adding D* (where D is a trait) to our grammar, even if its only to support a detail of the FFI? (In particular, I imagine you would not be able to do D* as D& etc...)
    Ugh, even just writing it down makes me say "no that seems bad."
  2. We don't have to shoehorn Rust's syntax into something matching C semantics, because we have macros, right?
    (Obviously the macros will need to then expand into something, and so its important to specify what that something is, in terms of what the interface to the end user is. E.g. as @klutzy points out, we still need to figure out what class D maps to. And of course we don't have macro-expansion in all the relevant contexts, such as type-expressions, so you'd still want the macro to generate bindings for sane identifiers that can be used elsewhere directly. But I think we can separate the two concerns here...)
  3. Ignoring the question of macros and continuing with @klutzy's idea of leveraging attributes, we could map each C class to two distinct bindings in Rust: one for its data layout (--> struct), and one for its vtable (--> trait).

For example:

class S {
  int x;
  virtual void foo();
  void bar();
}
class T : public S {
  int y;
  void baz();
}
void process(S* arg);
S* getS();

could be expressed as:

extern "C  " {
  #[class = "S"]
  struct Simpl { x: int, }

  #[class = "S"]
  trait Stable {
    fn foo(*self),
  }
  impl Simpl { fn bar(*self); }
  impl Stable for Simpl { fn foo(*self); }

  #[class = "T"]
  struct Timpl { super_: Simpl, y: int, }
  impl Stable for Timpl { fn foo(*self); }
  impl Timpl { fn baz(*self); }

  fn process<S:Stable>(arg: *S);
  fn getS() -> *Simpl;
}

(one could imagine rearranging the above a bit, pulling the struct items out of the extern block, and moving their #[class=..] attributes down instead to the impl Simpl and impl Timpl items. Not sure if that helps or hurts. Anyway I imagine the trait item needs to stay in the extern block, since a C vtable need not be compatible with a Rust trait vtable.)

@klutzy
Copy link
Contributor

klutzy commented Sep 26, 2013

On extern "C " I wrote above: I forgot the Windows situation! We also have to specify calling convention on Win32 since mangling uses callconv info. See also mangling scheme by @lifthrasiir.

Maybe extern "C " is wrongly placed since "C " is not a calling convention as we used. So how to declare C -mangled stdcall function? #[cxx] extern "stdcall"? extern "C " "stdcall"?

@flaper87
Copy link
Contributor

visiting for triage. Nothing to add here.

@klutzy
Copy link
Contributor

klutzy commented May 28, 2014

I started to think we don't need language-level support for C FFI. For name mangling we can just use #[link_name = "_Z5func2v"]. For virtual methods, we can define
virtual method table as struct.
What we really need is tool for generating C ffi, like rust-bindgen. For COM, we need code generator for MIDL.

@nathansobo
Copy link

I would love to use Rust to write V8 extensions, and a direct C interface could make that a good experience.

@emberian
Copy link
Member

Nominating for P-high. I imagine this is going to be pretty important for driving adoption.

@jacobsantos
Copy link

I would jump balls in if this had native C support. Although, it might be difficult kissing Golang goodbye for some things. I am disappointed in Golang's C support however. Not much to be done given how concurrency is handled between the languages.

@pnkfelix
Copy link
Member

pnkfelix commented Jul 3, 2014

Assigning P-low, not 1.0 milestone.

@pnkfelix pnkfelix added P-low and removed I-nominated labels Jul 3, 2014
@steveklabnik
Copy link
Member

I'm pulling a massive triage effort to get us ready for 1.0. As part of this, I'm moving stuff that's wishlist-like to the RFCs repo, as that's where major new things should get discussed/prioritized.

This issue has been moved to the RFCs repo: rust-lang/rfcs#602

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. P-low Low priority
Projects
None yet
Development

No branches or pull requests