Подтвердить что ты не робот

Возможно ли написать расширение node.js в C (не С++)?

Быстрый поиск в Google дает по крайней мере один учебник для написания С++ "Hello World" для node.js, но неясно, можно ли написать такую расширение, использующее только C. Предполагая, что с какими проблемами/ограничениями я сталкиваюсь?

4b9b3361

Ответ 1

Вы можете написать части своего расширения в C, если хотите, но вам понадобится хотя бы небольшой код С++ для склеивания кода C с помощью Node.

Как вы видели в своем HelloWorld, расширения полагаются на заголовки v8.h и node.h, которые имеют все классы, которые ожидает Node. Без них вы не сможете правильно создать объект JS для экспорта обратно в Node.

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

Ответ 2

Найдено в Hacker News:

https://github.com/wesolows/v8plus

v8 +: Node аддон С++ до границы C

Этот слой предлагает способ записи, по крайней мере, простых Node аддонов в C без всякого ужасного С++ goop, которого вы в противном случае ожидали использовать. Этот goop все еще существует, но вам не нужно его писать. Что еще более важно, вы можете написать свой модуль в разумной среде программирования, избегая запутанной и подверженной ошибкам семантики С++.

Ответ 3

Необходимо объявить отдельную функцию C в коде С++ с использованием синтаксиса extern "C"

Пример:

#define BUILDING_NODE_EXTENSION
#include <node.h>

extern "C" void f(int i, char c, float x);

using namespace v8;

если у вас есть несколько функций C, тогда его можно сгруппировать по фигурным скобкам:

extern "C" {
  void   f(int i, char c, float x);
  int    g(char* s, char const* s2);
  double sqrtOfSumOfSquares(double a, double b);
}

затем вызовите функцию из функции С++:

Handle<Value> MyFunction(const Arguments& args) {
  HandleScope scope;
   f(7, 'x', 3.14);    // <--- 
  return scope.Close(String::New("Hello"));
}

Handle<Value> CreateFunction(const Arguments& args) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction);
  Local<Function> fn = tpl->GetFunction();
  fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous

  return scope.Close(fn);
}

void Init(Handle<Object> target) {
  target->Set(String::NewSymbol("createFunction"),
      FunctionTemplate::New(CreateFunction)->GetFunction());
}


NODE_MODULE(addon, Init)

Примечание. Использование примера кода из Nodejs Addons

Ответ 4

Теперь у нас есть как минимум 3 хорошие варианты:

node -ffi: Node.js Интерфейс внешних функций
аддон для загрузки и вызова динамических библиотек с использованием чистого JavaScript. Его можно использовать для создания привязок к родным библиотекам без написания кода C
https://github.com/node-ffi/node-ffi

SWIG: Упрощенный Wrapper и Interface Generator
(он создает обертки для многих языков, что одновременно решает многие проблемы)
http://www.swig.org/

emscripten
Компилирует C и С++ в высоко оптимизируемый JavaScript, который работает даже в Интернете с близкой скоростью, без плагинов.
http://kripken.github.io/emscripten-site/

Ответ 5

Код, который напрямую взаимодействует с node.js, должен быть написан на С++.

Вы можете написать обертки extern "C", используя непрозрачные типы для всего, что вам нужно от node.h и v8.h, но, вероятно, проще просто использовать С++ вместо этого (что, конечно же, может вызвать код C).

Ответ 6

Если ваш модуль использует libuv, вы можете связать его с исполняемым файлом node. Он экспортирует функции libuv в качестве общей библиотеки.

Затем вы можете использовать node -ffi для взаимодействия с ним (здесь не требуется знание С++).

Вот как я сделал это в Windows, используя MSVS:

  • Создайте новое решение для DLL в MSVS
  • Загрузите libuv и скопируйте файлы include и lib в MSVS
  • Загрузите node.lib файл и поместите его в папку lib из MSVS
  • Скомпилируйте приведенный ниже пример источника, который добавляет таймер в цикл основного события

testlib.c:

#include <stdio.h>
#include <stdlib.h>
#include "uv.h"

void (*p_callback)(int number, char *text);

void timer_cb1 (uv_timer_t* timer, int status) {
  printf("libuv timer here\n", status);
  p_callback(123, "it worked!");
}

void set_timer (int interval, void *pfunction) {
  uv_loop_t *loop;
  uv_timer_t *timer1;

  printf("set_timer called. interval=%d callback=%p\n", interval, pfunction);

  p_callback = pfunction;

  printf("uv_version_string = %s\n", uv_version_string());

  loop = uv_default_loop();
  if (loop == 0) {
    puts("could not get the reference to the default loop");
    return;
  }

  puts("got the default loop. now allocating the timer struct");

  timer1 = (uv_timer_t *) malloc(sizeof(uv_timer_t));
  if (timer1 == 0) {
    puts("malloc failed");
    return;
  }

  puts("initializing timer");
  uv_timer_init(loop, timer1);

  puts("starting timer");
  uv_timer_start(timer1, (uv_timer_cb) &timer_cb1, interval, interval);

  puts("timer created. returning");

}

используйте testlib.def:

EXPORTS set_timer

И не забудьте ссылаться на node.lib

  • Переместите созданную dll в тестовую папку и запустите там следующие команды:

npm install ffi (в настоящее время требуются инструменты сборки, проверьте инструкции)

node test-lib.js

test-lib.js находится здесь:

var ffi = require('ffi');

var testlib = ffi.Library('testlib', {
  'set_timer': [ 'void', [ 'int', 'pointer' ] ]
});

var callback = ffi.Callback('void', ['int', 'string'],
  function(number, text) {
    console.log("javascript callback here!!!  number=" + number + "  text=" + text);
  }
);

console.log('registering the callback...');
testlib.set_timer(500, callback);
console.log('done')

Используйте свое воображение. У нас есть сети, рабочие потоки и другие варианты внутри libuv...