Skip to content

Calling C code from JavaScript involving Structs #3083

Closed

Description

@Planeshifter

First let me say, this is an amazing project!

Now my question:
I am in the process of transpiling a C library to JS which should then be used as a node.js module. While I managed to export functions accepting or returning standard types such as floats or doubles, the documentation is not clear on how to properly convert functions accepting or returning custom C structs (the Embind and WebIDL facilities seem to be tailored only at C++ code).

Consider the following artificial example:

#include <math.h>

struct Vector3d{
  double x;
  double y;
  double z;
};

double length(struct Vector3d vec){
  double vec_sum = vec.x*vec.x + vec.y*vec.y + vec.z*vec.z;
  return sqrt(vec_sum);
}

struct Vector3d createVec(double x, double y, double z){
  struct Vector3d ret;
  ret.x = x;
  ret.y = y;
  ret.z = z;
  return ret;
}

Ideally, I would like to end up with a constructor function than can create 3d vectors and a length function to calculate their length. This seems to be a quite common task when porting C code, but browsing the Internet I couldn't find a proper explanation of how to proceed? I would greatly appreciate if someone could tell me whether and if so how one can convert such C code to JavaScript. I found a discussion on the Google group (Link) suggesting that it is possible, but was not able to reproduce the necessary steps, so a worked example would be of much help.

Best,
Philipp

Activity

  1. kripken commented on Dec 16, 2014

    @kripken
    Member

    In WebIDL, you can use [Value] to allow passing and returning structs by value,

    http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/WebIDL-Binder.html#pointers-references-value-types-ref-and-value

    For efficiency, though, it is much better for your APIs to hand off pointers to objects.

  2. Planeshifter commented on Dec 17, 2014

    @Planeshifter
    Author

    Thank you for your quick response. By now, I managed to convert above example using Embind as follows:

    #include <math.h>
    #include <emscripten/bind.h>
    
    using namespace emscripten;
    
    struct Vector3d{
      double x;
      double y;
      double z;
    };
    
    double length(struct Vector3d vec){
      double vec_sum = vec.x*vec.x + vec.y*vec.y + vec.z*vec.z;
      return sqrt(vec_sum);
    }
    
    struct Vector3d createVec(double x, double y, double z){
      struct Vector3d ret;
      ret.x = x;
      ret.y = y;
      ret.z = z;
      return ret;
    }
    
    EMSCRIPTEN_BINDINGS(my_module) {
        value_object<Vector3d>("Vector3d")
            .field("x", &Vector3d::x)
            .field("y", &Vector3d::y)
            .field("z", &Vector3d::z);
        function("createVec",&createVec);
        function("length", &length);
    }
    

    That works just as expected. When trying WebIDL, I was not able to export a function which is not a method belonging to a class. It seems that you always have to define an interface, at least in the examples I came across. Is that correct?

  3. kripken commented on Dec 17, 2014

    @kripken
    Member

    Yes, WebIDL currently exports only classes and structs, I don't think
    anyone has added global functions to it.

    • Alon

    On Tue, Dec 16, 2014 at 11:03 PM, Philipp Burckhardt <
    notifications@github.com> wrote:

    Thank you for your quick response. By now, I managed to convert above
    example using Embind as follows:

    #include <math.h>
    #include <emscripten/bind.h>

    using namespace emscripten;

    struct Vector3d{
    double x;
    double y;
    double z;
    };

    double length(struct Vector3d vec){
    double vec_sum = vec.x_vec.x + vec.y_vec.y + vec.z*vec.z;
    return sqrt(vec_sum);
    }

    struct Vector3d createVec(double x, double y, double z){
    struct Vector3d ret;
    ret.x = x;
    ret.y = y;
    ret.z = z;
    return ret;
    }

    EMSCRIPTEN_BINDINGS(my_module) {
    value_object("Vector3d")
    .field("x", &Vector3d::x)
    .field("y", &Vector3d::y)
    .field("z", &Vector3d::z);
    function("createVec",&createVec);
    function("length", &length);
    }

    That works just as expected. When trying WebIDL, I was not able to export
    a function which is not a method belonging to a class. It seems that you
    always have to define an interface (which will be converted to a JS
    constructor function), at least in the examples I came across.

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

  4. Planeshifter commented on Dec 20, 2014

    @Planeshifter
    Author

    Thanks for the clarification!
    Best,
    Philipp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions