Можно ли написать родное расширение Node.js в Go, в отличие от С++?

Это все, что касается моего вопроса, на самом деле, но я думаю, что это было интересно ответить.

Ответы

Ответ 1

С добавлением поддержки разделяемых библиотек в go это возможно сейчас.

file: calculator.go

// package name: calculator
package main

import "C"

//export Sum
func Sum(x, y float64) float64 {
    return x + y
}

func main() {
}

файл: node -calculator.cc

#include "calculator.h"
#include <node.h>

namespace calc {

  using v8::FunctionCallbackInfo;
  using v8::Isolate;
  using v8::Local;
  using v8::Object;
  using v8::String;
  using v8::Value;
  using v8::Number;
  using v8::Exception;

  void add(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate();

    // Check the number of arguments passed.
    if (args.Length() < 2) {
      // Throw an Error that is passed back to JavaScript
      isolate->ThrowException(Exception::TypeError(
          String::NewFromUtf8(isolate, "Wrong number of arguments")));
      return;
    }

    // Check the argument types
    if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
      isolate->ThrowException(Exception::TypeError(
          String::NewFromUtf8(isolate, "Wrong arguments")));
      return;
    }

    // Perform the operation
    Local<Number> num = Number::New(isolate, Sum(args[0]->NumberValue(), args[1]->NumberValue()));

    // Set the return value (using the passed in
    // FunctionCallbackInfo<Value>&)
    args.GetReturnValue().Set(num);
  }

  void init(Local<Object> exports) {
    NODE_SET_METHOD(exports, "add", add);
  }

  NODE_MODULE(calculator, init)
}

file: test.cc

const calculator = require('./build/Release/node-calculator');
console.log('4+5=', calculator.add(4, 5));

file: binding.gyp

{
  "targets": [
    {
      "target_name": "node-calculator",
      "sources": [
        "node-calculator.cc"
      ],
      "libraries": [
        "../calculator.a"
      ],
    },
  ],
}

Сложение:

go build -buildmode c-archive -o calculator.a calculator.go
node-gyp configure
node-gyp build

Вывод:

#> node test.js 
4+5= 9

Ответ 2

Нативный модуль для node.js должен глубоко взаимодействовать с процессом V8, который содержит много концепций v8, таких как gc, javascript context,...

И я не думаю, что V8 предоставил совместимые и стабильные API-интерфейсы для взаимодействия с другим языком. Вот почему node.js собственный аддон должен быть построен с С++ и всегда импортирует заголовки V8 С++.


Но вы можете использовать GO для записи родных аддонов node.js путем переноса GO-кода на С++:

file: module.go

package main

func Add(a, b int) int {
    return a + b
}

file: module.c

#include <node.h>
#include <v8.h>

using namespace v8;

extern int go_add(int, int) __asm__ ("example.main.Add");

void init(Handle<Object> exports) {
    // call go_add
}

NODE_MODULE(module, init)

Подробнее о том, как вызвать функцию GO из C/С++:

Функции вызова Go с C


Edit:

См. комментарии @jdi и ссылку: https://groups.google.com/forum/#!msg/golang-nuts/FzPbOwbTlPs/dAJVWQHx6m4J

Цитата: Это может быть выполнимо для простых вещей, таких как add (которые не генерируют мусор или не требуют времени выполнения), но он пока не поддерживается (хотя) компилятором, насколько я знаю. Часть работы выполняется для linux (см. Golang.org/issue/256), но есть ряд открытых вопросов (что происходит при загрузке двух общих объектов и т.д.).

Ответ 3

Просто, чтобы отправить это сообщение вместо ответа...

Я просмотрел список рассылки golang-nuts относительно поддержки написания расширений в Go для других языков. Источник ответа можно найти здесь.

Это может быть выполнимо для простых вещей, таких как add (которые не генерируют мусор или требуется время выполнения), но он не поддерживается (пока) насколько я знаю. Часть работы выполняется для Linux (см. golang.org/issue/256), но есть ряд открытых вопросов (что происходит при загрузке двух общих объектов? и т.д.)

Так что, по-видимому, нет смысла писать расширение в Go, тем не менее, поскольку большинство языковых функций не будут доступны, и вы уже находитесь на C/С++, чтобы добавить оболочку для точка входа.