Skip to content

Latest commit

 

History

History
214 lines (134 loc) · 7.93 KB

File metadata and controls

214 lines (134 loc) · 7.93 KB

Che Guevara

Wrapping C++ and Python libraries for JavaScript

The guerilla-slides-jsnation-2025

Guerilla Warfare

C++ in JavaScript

JavaScript has become the new universal language - and it happened almost by accident

  • because of all the R&D that went into highly efficient interpreters
  • because it allows to share backend and frontend code

JavaScript is notoriously difficult to interoperate with other languages.

So, for the last two decades, people have been trying to rewrite all existing software in JavaScript - there was simply no other way around it.

But is this actually feasible?

Today, one can even find a ready-to-use fully functional PNG decoder and encoder as npm package - entirely in JavaScript - compatible with both the browser and Node.js!

However in the C++ world we have ImageMagick - 30 years of experience in implementing state of the art image manipulation algorithms.

I have authored or co-authored the bindings of four major C++ libraries for JavaScript:

  • GDAL - only Node.js
  • ImageMagick - both browser and Node.js, the first SWIG JSE project, about 2 man-months
  • ffmpeg - only Node.js - the first nobind17 project,
  • PROJ - both browser and Node.js

Rewriting these in JavaScript is a monumental task.

Automatically generating wrappers for high-level interpreted languages by compiling the C/C++ header files is a solved problem: it is called

SWIG

and it exists since the 1990s.

However until 2024, JavaScript support was very rudimentary, covered only Node.js and wasn't really updated since the Node.js 0.x era.

The Holy Grail of JavaScript/C++ interoperability

git clone https://github.com/ImageMagick/ImageMagick
abracadabra ImageMagick

then

import { Magick } from '@abracadabra/ImageMagick';

And it works both in Node.js and in the browser!

This has been achieved for Python libraries!

It is called pymport:

npm install pymport
npx pympip3 install numpy

then

const { pymport, proxify } = require('pymport');
const np = proxify(pymport('numpy'));

const a = np.arange(15).reshape(3, 5);
const b = np.ones([2, 3], { dtype: np.int16 });

...For C++ we are not there yet

but at least we are going in the right direction

Today, there are two choices:

SWIG JavaScript Evolution

  • Very powerful, supports both Node.js and WASM but has a very steep learning curve

nobind17 - pybind11-like

  • Very simple to use, does not require any special knowledge beyond C++ but it has its limits and supports only C++ for Node.js
  • GDAL, my first project, as a co-author, was completely hand-written bindings - it costed more than 1 man-year
  • ImageMagick, the first SWIG JSE project, took about 1 man-month, 400k lines of C++ code generated from 800 lines of SWIG JSE code
  • ffmpeg, the first nobind17 project - about 2 man-weeks to get it to mostly working status
  • PROJ, the second SWIG JSE project - about 2 man-weeks

The cost savings are tremendous!

  • The bindings support both synchronous and asynchronous calls - both in Node.js and in the browser (async in the browser requires COOP/COEP)
  • importing is completely automatic - just as if this was JavaScript - the bundler picks up either the browser WASM version or the Node.js native version
  • The TypeScript types are autogenerated
  • The C++ STL is replaced by methods that have native JavaScript feel

Interfacing the two languages is not enough!

End-users expect npm packages - which must be so seamless, that the developer does not need to know about the C++

time to ditch node-gyp

Enter the hadron build system

hadron

  • meson-based build system which is compatible with CMake and autotools
  • xpm-orchestrator for seamless integration with conan and a built-in C++ compiler in an npm package

ImageMagick comes prebuilt with more than 20 libraries - on Linux, macOS and Windows, and WASM - and it can rebuild itself upon installation, pulling the libraries from conan and using its own bundled C++ compiler!

How about doing this the other way around?

Transparent interaction with JavaScript from C++?

try {
  Napi::Platform platform;
  Napi::PlatformEnv env(platform);
  Napi::Function require =
    env.Global().Get("require").As<Napi::Function>();
  Napi::Object axios =
    require({Napi::String::New(env, "axios")}).ToObject();
  Napi::Promise r = axios.Get("get").As<Napi::Function>()
    .MakeCallback(env.Global(), 
    {Napi::String::New(env, "https://www.github.com")})
    .As<Napi::Promise>();
} catch (const Napi::Error &e) {
  fprintf(stderr, "Caught a JS exception: %s\n", e.what());
  return -1;
}

This was one of the most requested Node API features - ability to require and import npm modules from C++.

I created libnode in 2023 as Google Summer of Code project - right before the start of the open hostilities between me and Google.

Alas, the PR is currently frozen as I was blocked from accessing the Node.js repositories in September 2023 after refusing to stop talking about the French police involvement in my affair. It does not work beyond Node 18.x.

The project is currently available as an Ubuntu package but has not been updated since Ubuntu 22.04.

It works reasonably well and it is used by at least one other opensource project.

It is targeted mostly at server-side C++ applications which must support user JavaScript plugins.

It features automatic Promise resolution from C++ and supports loading and calling both synchronous and asynchronous JavaScript functions from CJS and ES6 modules.

I am unemployed and homeless software engineer living on the street on social welfare and working full-time on open source in my van using solar panels.

I am currently the target of a huge extortion, that involves many of the largest IT companies in the world - including Google, X, Microsoft and Facebook - as well as the French police - about a series of irregular criminal and civil cases with sexual motivation.

After covering up false rape charges against me, my employers trying to convince me that I suffer from psychosis using subliminal messages with sexual content at my workplace.

I chose to live on the street with almost no money instead of accepting a job in a criminal company willing to help cover up this affair since I consider this to be a more meaningful use of my life.

I want to live in a society where employers are not allowed to use the police and the criminal justice system for extortion, where the power of the state and commercial interests stops at the doorstep of your home and where your own sexual life is no one else's business.

For great justice!

All your base are belong to us