Search code examples
node.jsccrtnode.js-addon

Trying to make my C addon uses the same C runtime with the C runtime that NodeJS uses but got stuck


If you guys have to know what I am actually doing, then this is it: https://github.com/Meigyoku-Thmn/CSBinary (A port of BinaryReader and BinaryWriter from .NET Core).

The thing is, my library doesn't have File Buffering (please, again from my other post, this has nothing to do with the Buffer class in NodeJS), and I want to take advantage of the I/O system of the C runtime, instead of having to write a BufferedFile class (think of the BufferedStream class in .NET).

In C language, if you open/create a file (fopen) and get a FILE* instance, then it's doing file buffering behind the scene, you can even set the file buffer size (again, nothing to do with the Buffer class) by using the setvbuf function.

And I think if I have a file descriptor in hand (created by fs module), I could use the fdopen function to wrap it/associate it in a FILE* instance, and get the built-in C runtime's file buffering for free.

Unfortunately, NodeJS seems to be built using static link. So my addon uses separate C runtime from the one that NodeJS uses. File descriptor created from NodeJS cannot be used directly in my addon, and libuv doesn't have anything similar to fdopen.

According to this section in NodeJS docs, there is a case that node-gyp will "download the full source tarball" and let me "have complete access to the full set of Node.js dependencies". That may be the way, but aside from specifying the nodedir flag (which requires me to manually prepare "a local Node.js source image"), the docs is pretty vague.

So is this the dead end, anybody has experience about this, please help me.


Solution

  • Eventually, I found a way to do this:

    int nodejs_fd = gotFromJs();
    // on POSIX-system, fd is process-wide, so I don't have to do anything
    int fd = nodejs_fd;
    // but on Windows, fd is just simulated on top of OS-Handle
    // so it's bound to a specific C runtime, and my addon use a separate C runtime.
    // therefore, I cannot just pass it to fdopen (EBADF)
    // but I can still get the OS-handle
    #ifdef _WIN32
    HANDLE fh = (HANDLE)uv_get_osfhandle(nodejs_fd);
    // so I can just open my own fd that points to it, side-by-side with the fd of NodeJS
    fd = _open_osfhandle((intptr_t)fh, _O_RDONLY);
    #endif
    // and problem solved
    FILE* file = fdopen(fd, "rb");