Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

emnapi WebAssembly build #1674

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 34 additions & 1 deletion .github/workflows/ci.yml
Expand Up @@ -45,13 +45,24 @@ jobs:
node: 16
host: arm64
target: arm64
- os: ubuntu-20.04
node: 16
host: x64
target: wasm32
name: ${{ matrix.os }} (node=${{ matrix.node }}, host=${{ matrix.host }}, target=${{ matrix.target }})
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
architecture: ${{ matrix.host }}

- name: Setup Emscripten (WebAssembly)
if: matrix.target == 'wasm32'
uses: mymindstorm/setup-emsdk@v11
with:
version: '3.1.29'
actions-cache-folder: 'emsdk-cache'

- name: Add yarn (self-hosted)
if: matrix.os == 'macos-m1'
Expand Down Expand Up @@ -84,21 +95,43 @@ jobs:
echo "CXXFLAGS=${CXXFLAGS:-} -include ../src/gcc-preinclude.h" >> $GITHUB_ENV

- name: Configure build
if: matrix.target != 'wasm32'
run: yarn node-pre-gyp configure --target_arch=${{ env.TARGET }}

- name: Configure build (WebAssembly)
if: matrix.target == 'wasm32'
run: yarn node-pre-gyp configure --nodedir=./wasm --target_arch=${{ env.TARGET }}

- name: Build binaries
if: matrix.target != 'wasm32'
run: yarn node-pre-gyp build --target_arch=${{ env.TARGET }}

- name: Build binaries (WebAssembly)
if: matrix.target == 'wasm32'
run: emmake yarn node-pre-gyp build --nodedir=./wasm --target_arch=${{ env.TARGET }}

- name: Print binary info
if: contains(matrix.os, 'ubuntu')
if: contains(matrix.os, 'ubuntu') && matrix.target != 'wasm32'
run: |
ldd lib/binding/*/node_sqlite3.node
echo "---"
nm lib/binding/*/node_sqlite3.node | grep "GLIBC_" | c++filt || true
echo "---"
file lib/binding/napi-v*/*

- name: Print binary info (WebAssembly)
if: contains(matrix.os, 'ubuntu') && matrix.target == 'wasm32'
run: |
file lib/binding/napi-v*/*

- name: Run tests
if: matrix.target != 'wasm32'
run: yarn test

- name: Run tests (WebAssembly)
if: matrix.target == 'wasm32'
env:
npm_config_target_arch: 'wasm32'
run: yarn test

- name: Package prebuilt binaries
Expand Down
99 changes: 67 additions & 32 deletions binding.gyp
Expand Up @@ -16,34 +16,54 @@
"msvs_settings": {
"VCCLCompilerTool": { "ExceptionHandling": 1 },
},
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"],
"conditions": [
["sqlite != 'internal'", {
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")", "<(sqlite)/include" ],
"libraries": [
"-l<(sqlite_libname)"
],
"conditions": [
[ "OS=='linux'", {"libraries+":["-Wl,-rpath=<@(sqlite)/lib"]} ],
[ "OS!='win'", {"libraries+":["-L<@(sqlite)/lib"]} ]
],
'msvs_settings': {
'VCLinkerTool': {
'AdditionalLibraryDirectories': [
'<(sqlite)/lib'
],
},
}
},
{
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")",
"deps/sqlite3.gyp:sqlite3"
]
}
]
["OS == 'emscripten'", {
# make require('xxx.node') work
'product_extension': 'node.js',
'defines': [
# UV_THREADPOOL_SIZE equivalent
'EMNAPI_WORKER_POOL_SIZE=4',
],
"ldflags": [
'-sMODULARIZE=1',
'-sEXPORT_NAME=nodeSqlite3',
# building only for Node.js for now
"-sNODERAWFS=1",
'-sWASM_ASYNC_COMPILATION=0',
],
"dependencies": [
"deps/sqlite3.gyp:sqlite3"
]
}, {
"conditions": [
["sqlite != 'internal'", {
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")", "<(sqlite)/include" ],
"libraries": [
"-l<(sqlite_libname)"
],
"conditions": [
[ "OS=='linux'", {"libraries+":["-Wl,-rpath=<@(sqlite)/lib"]} ],
[ "OS!='win'", {"libraries+":["-L<@(sqlite)/lib"]} ]
],
'msvs_settings': {
'VCLinkerTool': {
'AdditionalLibraryDirectories': [
'<(sqlite)/lib'
],
},
}
}, {
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")",
"deps/sqlite3.gyp:sqlite3"
]
}]
]
}],
],
"sources": [
"src/backup.cc",
Expand All @@ -57,11 +77,26 @@
"target_name": "action_after_build",
"type": "none",
"dependencies": [ "<(module_name)" ],
"copies": [
{
"files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
"destination": "<(module_path)"
}
"conditions": [
["OS == 'emscripten'", {
"copies": [
{
"files": [
"<(PRODUCT_DIR)/<(module_name).node.js",
"<(PRODUCT_DIR)/<(module_name).node.wasm",
"<(PRODUCT_DIR)/<(module_name).node.worker.js",
],
"destination": "<(module_path)"
}
]
}, {
"copies": [
{
"files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
"destination": "<(module_path)"
}
]
}]
]
}
]
Expand Down
19 changes: 17 additions & 2 deletions lib/sqlite3-binding.js
@@ -1,5 +1,20 @@
const binary = require('@mapbox/node-pre-gyp');
const path = require('path');
const binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')));
const binding = require(binding_path);
const binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')), {
target_arch: process.env.npm_config_target_arch || process.env.npm_config_arch || process.arch
});
let binding = require(binding_path);
if (typeof binding === 'function') {
const emnapiInitOptions = {
context: require('@emnapi/runtime').getDefaultContext()
};
try {
// optional dependency
// support async_hooks on Node.js
emnapiInitOptions.nodeBinding = require('@emnapi/node-binding');
} catch (_) {
// ignore
}
binding = binding().emnapiInit(emnapiInitOptions);
}
module.exports = exports = binding;
3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -49,10 +49,12 @@
},
"dependencies": {
"@mapbox/node-pre-gyp": "^1.0.0",
"@emnapi/runtime": "^0.31.0",
"node-addon-api": "^4.2.0",
"tar": "^6.1.11"
},
"devDependencies": {
"emnapi": "^0.31.0",
"eslint": "6.8.0",
"mocha": "7.2.0",
"node-pre-gyp-github": "1.4.4"
Expand All @@ -66,6 +68,7 @@
}
},
"optionalDependencies": {
"@emnapi/node-binding": "^0.31.0",
"node-gyp": "8.x"
},
"scripts": {
Expand Down
6 changes: 6 additions & 0 deletions test/async_calls.test.js
Expand Up @@ -6,6 +6,12 @@ const { createHook, executionAsyncId } = require("async_hooks");


describe('async_hooks', function() {
// before(function() {
// if (process.env.npm_config_arch.includes('wasm')) {
// this.skip();
// }
// });

let db;
let dbId;
let asyncHook;
Expand Down
75 changes: 75 additions & 0 deletions wasm/common.gypi
@@ -0,0 +1,75 @@
# This file is originally created by [RReverser](https://github.com/RReverser)
# in https://github.com/lovell/sharp/pull/3522
{
'variables': {
'OS': 'emscripten',
'napi_build_version%': '8',
'clang': 1,
'target_arch%': 'wasm32',
'wasm_threads%': 1,
'product_extension%': 'js',
},

'target_defaults': {
'type': 'executable',
'product_extension': '<(product_extension)',

'cflags': [
'-Wall',
'-Wextra',
'-Wno-unused-parameter',
'-sDEFAULT_TO_CXX=0',
],
'cflags_cc': [
'-fno-rtti',
'-fno-exceptions',
'-std=gnu++17'
],
'ldflags': [
'--js-library=<!(node -p "require(\'emnapi\').js_library")',
"-sALLOW_MEMORY_GROWTH=1",
"-sEXPORTED_FUNCTIONS=['_malloc','_free']",
'-sNODEJS_CATCH_EXIT=0',
'-sNODEJS_CATCH_REJECTION=0',
'-sAUTO_JS_LIBRARIES=0',
'-sAUTO_NATIVE_LIBRARIES=0',
],
'defines': [
'__STDC_FORMAT_MACROS',
],
'include_dirs': [
'<!(node -p "require(\'emnapi\').include")',
],
'sources': [
'<!@(node -p "require(\'emnapi\').sources.map(x => JSON.stringify(path.relative(process.cwd(), x))).join(\' \')")'
],

'default_configuration': 'Release',
'configurations': {
'Debug': {
'defines': [ 'DEBUG', '_DEBUG' ],
'cflags': [ '-g', '-O0' ],
'ldflags': [ '-g', '-O0', '-sSAFE_HEAP=1' ],
},
'Release': {
'cflags': [ '-O3' ],
'ldflags': [ '-O3' ],
}
},

'conditions': [
['target_arch == "wasm64"', {
'cflags': [
'-sMEMORY64=1',
],
'ldflags': [
'-sMEMORY64=1'
]
}],
['wasm_threads == 1', {
'cflags': [ '-sUSE_PTHREADS=1' ],
'ldflags': [ '-sUSE_PTHREADS=1' ],
}],
],
}
}