Skip to content

Commit

Permalink
Add native module support on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
zeromake authored Sep 10, 2024
1 parent ada24f3 commit 902cc2c
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 53 deletions.
24 changes: 21 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,20 @@ jobs:
- uses: actions/checkout@v4
- name: build
run: |
cmake -B build -G "Visual Studio 17 2022" -A ${{matrix.arch}}
cmake -B build -DBUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -A ${{matrix.arch}}
cmake --build build --config ${{matrix.buildType}} --target qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source
cmake --build build --config ${{matrix.buildType}} --target fib
cmake --build build --config ${{matrix.buildType}} --target point
- name: stats
run: |
build\${{matrix.buildType}}\qjs.exe -qd
- name: test
run: |
cp build\${{matrix.buildType}}\fib.dll examples\
cp build\${{matrix.buildType}}\point.dll examples\
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
Expand All @@ -224,14 +230,20 @@ jobs:
- uses: actions/checkout@v4
- name: build
run: |
cmake -B build -G "Visual Studio 17 2022" -T ClangCL
cmake -B build -DBUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -T ClangCL
cmake --build build --config ${{matrix.buildType}} --target qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source
cmake --build build --config ${{matrix.buildType}} --target fib
cmake --build build --config ${{matrix.buildType}} --target point
- name: stats
run: |
build\${{matrix.buildType}}\qjs.exe -qd
- name: test
run: |
cp build\${{matrix.buildType}}\fib.dll examples\
cp build\${{matrix.buildType}}\point.dll examples\
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
Expand All @@ -257,14 +269,20 @@ jobs:
ninja.exe --version
- name: build
run: |
cmake -B build -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
cmake -B build -DBUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
cmake --build build --target qjs_exe
cmake --build build --target function_source
cmake --build build --target fib
cmake --build build --target point
- name: stats
run: |
build\qjs.exe -qd
- name: test
run: |
cp build\fib.dll examples\
cp build\point.dll examples\
build\qjs.exe examples\test_fib.js
build\qjs.exe examples\test_point.js
build\qjs.exe tests\test_bigint.js
build\qjs.exe tests\test_bjson.js
build\qjs.exe tests\test_closure.js
Expand Down
44 changes: 24 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ target_link_libraries(function_source ${qjs_libs})
# Examples
#

if(BUILD_EXAMPLES AND NOT WIN32)
if(BUILD_EXAMPLES)
add_executable(hello
gen/hello.c
)
Expand All @@ -290,27 +290,31 @@ if(BUILD_EXAMPLES AND NOT WIN32)
target_compile_definitions(hello_module PRIVATE ${qjs_defines})
target_link_libraries(hello_module ${qjs_libs})

if(NOT WIN32)
add_library(fib MODULE examples/fib.c)
set_target_properties(fib PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
if(APPLE)
target_link_options(fib PRIVATE -undefined dynamic_lookup)
endif()
add_library(fib MODULE examples/fib.c)
set_target_properties(fib PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
if(WIN32)
target_link_libraries(fib ${qjs_libs})
endif()
if(APPLE)
target_link_options(fib PRIVATE -undefined dynamic_lookup)
endif()

add_library(point MODULE examples/point.c)
set_target_properties(point PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY)
if(APPLE)
target_link_options(point PRIVATE -undefined dynamic_lookup)
endif()
add_library(point MODULE examples/point.c)
set_target_properties(point PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY)
if(WIN32)
target_link_libraries(point ${qjs_libs})
endif()
if(APPLE)
target_link_options(point PRIVATE -undefined dynamic_lookup)
endif()

add_executable(test_fib
examples/fib.c
Expand Down
10 changes: 9 additions & 1 deletion examples/fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ static int js_fib_init(JSContext *ctx, JSModuleDef *m)
#define JS_INIT_MODULE js_init_module_fib
#endif

JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
#ifndef JS_EXTERN
#ifdef _WIN32
#define JS_EXTERN __declspec(dllexport)
#else
#define JS_EXTERN
#endif
#endif

JS_EXTERN JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_fib_init);
Expand Down
10 changes: 9 additions & 1 deletion examples/point.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,15 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m)
return 0;
}

JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
#ifndef JS_EXTERN
#ifdef _WIN32
#define JS_EXTERN __declspec(dllexport)
#else
#define JS_EXTERN
#endif
#endif

JS_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_point_init);
Expand Down
4 changes: 3 additions & 1 deletion examples/test_fib.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* example of JS module importing a C module */
import * as os from "os";

import { fib } from "./fib.so";
const isWin = os.platform === 'win32';
const { fib } = await import(`./fib.${isWin ? 'dll' : 'so'}`);

console.log("Hello World");
console.log("fib(10)=", fib(10));
5 changes: 4 additions & 1 deletion examples/test_point.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* example of JS module importing a C module */
import { Point } from "./point.so";
import * as os from "os";

const isWin = os.platform === 'win32';
const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`);

function assert(b, str)
{
Expand Down
64 changes: 40 additions & 24 deletions gen/test_fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,46 @@

#include "quickjs-libc.h"

const uint32_t qjsc_test_fib_size = 167;
const uint32_t qjsc_test_fib_size = 293;

const uint8_t qjsc_test_fib[167] = {
0x0d, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
const uint8_t qjsc_test_fib[293] = {
0x0d, 0x0d, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
0x2e, 0x2f, 0x66, 0x69, 0x62, 0x2e, 0x73, 0x6f,
0x06, 0x66, 0x69, 0x62, 0x0e, 0x63, 0x6f, 0x6e,
0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67,
0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb8, 0x03,
0x01, 0xba, 0x03, 0x00, 0x00, 0x01, 0x00, 0xbc,
0x03, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0xa2,
0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32,
0x00, 0xbc, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02,
0x29, 0x38, 0xdf, 0x00, 0x00, 0x00, 0x42, 0xe0,
0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00,
0x24, 0x01, 0x00, 0x0e, 0x38, 0xdf, 0x00, 0x00,
0x00, 0x42, 0xe0, 0x00, 0x00, 0x00, 0x04, 0xe2,
0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a,
0xee, 0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb8,
0x03, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04,
0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x04,
0x6f, 0x73, 0x0a, 0x69, 0x73, 0x57, 0x69, 0x6e,
0x06, 0x66, 0x69, 0x62, 0x10, 0x70, 0x6c, 0x61,
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x0a, 0x77, 0x69,
0x6e, 0x33, 0x32, 0x0c, 0x2e, 0x2f, 0x66, 0x69,
0x62, 0x2e, 0x06, 0x64, 0x6c, 0x6c, 0x04, 0x73,
0x6f, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c,
0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48, 0x65,
0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
0x64, 0x10, 0x66, 0x69, 0x62, 0x28, 0x31, 0x30,
0x29, 0x3d, 0x0d, 0xb8, 0x03, 0x01, 0xba, 0x03,
0x00, 0x00, 0x01, 0x00, 0xfc, 0x01, 0x00, 0x01,
0x0c, 0x20, 0xfa, 0x01, 0xa2, 0x01, 0x00, 0x00,
0x00, 0x05, 0x03, 0x00, 0x73, 0x00, 0xba, 0x03,
0x00, 0x0d, 0xbc, 0x03, 0x00, 0x0d, 0xbe, 0x03,
0x01, 0x0d, 0x08, 0xe9, 0x02, 0x29, 0x65, 0x00,
0x00, 0x41, 0xe0, 0x00, 0x00, 0x00, 0x04, 0xe1,
0x00, 0x00, 0x00, 0xae, 0xe1, 0x06, 0x11, 0xf1,
0xea, 0x0b, 0x70, 0x42, 0xdf, 0x00, 0x00, 0x00,
0xe2, 0x0e, 0xeb, 0x24, 0x0e, 0x04, 0xe2, 0x00,
0x00, 0x00, 0x42, 0x5d, 0x00, 0x00, 0x00, 0x65,
0x01, 0x00, 0xe9, 0x08, 0x04, 0xe3, 0x00, 0x00,
0x00, 0xeb, 0x06, 0x04, 0xe4, 0x00, 0x00, 0x00,
0x24, 0x01, 0x00, 0x35, 0x8b, 0xeb, 0xd4, 0x38,
0xe5, 0x00, 0x00, 0x00, 0x42, 0xe6, 0x00, 0x00,
0x00, 0x04, 0xe7, 0x00, 0x00, 0x00, 0x24, 0x01,
0x00, 0x0e, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x42,
0xe6, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00,
0x00, 0x65, 0x02, 0x00, 0xbb, 0x0a, 0xee, 0x24,
0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb8, 0x03, 0x01,
0x01, 0x22, 0x01, 0x01, 0x00, 0x04, 0x08, 0x1e,
0x2a, 0x18, 0x1b, 0x08, 0x0d, 0x3b, 0x1b, 0x0c,
0x07, 0x04, 0x25, 0x08, 0x0c, 0x04, 0x07, 0x10,
0x43, 0x2c, 0x25, 0x10, 0x25, 0x04, 0x27, 0x6b,
0x62, 0x00, 0x4d, 0x30, 0x00,
};

static JSContext *JS_NewCustomContext(JSRuntime *rt)
Expand All @@ -34,8 +50,8 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
if (!ctx)
return NULL;
{
extern JSModuleDef *js_init_module_fib(JSContext *ctx, const char *name);
js_init_module_fib(ctx, "examples/fib.so");
extern JSModuleDef *js_init_module_os(JSContext *ctx, const char *name);
js_init_module_os(ctx, "os");
}
return ctx;
}
Expand Down
58 changes: 56 additions & 2 deletions quickjs-libc.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ extern char **environ;

#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)

#ifndef QJS_NATIVE_MODULE_SUFFIX
#ifdef _WIN32
#define QJS_NATIVE_MODULE_SUFFIX ".dll"
#else
#define QJS_NATIVE_MODULE_SUFFIX ".so"
#endif
#endif

/* TODO:
- add socket calls
*/
Expand Down Expand Up @@ -483,7 +491,53 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
const char *module_name);


#if defined(_WIN32) || defined(__wasi__)
#if defined(_WIN32)
static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
{
JSModuleDef *m;
HINSTANCE hd;
JSInitModuleFunc *init;
char *filename = NULL;
size_t len = strlen(module_name);
JS_BOOL is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') ||
(module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':';
JS_BOOL is_relative = len > 2 && module_name[0] == '.' && (module_name[1] == '/' || module_name[1] == '\\');
if (is_absolute || is_relative) {
filename = (char *)module_name;
} else {
filename = js_malloc(ctx, len + 2 + 1);
if (!filename)
return NULL;
strcpy(filename, "./");
strcpy(filename + 2, module_name);
}
hd = LoadLibraryA(filename);
if (filename != module_name)
js_free(ctx, filename);
if (hd == NULL) {
JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu",
module_name, GetLastError());
goto fail;
}
init = (JSInitModuleFunc *)(uintptr_t)GetProcAddress(hd, "js_init_module");
if (!init) {
JS_ThrowReferenceError(ctx, "js_init_module '%s' not found: %lu",
module_name, GetLastError());
goto fail;
}
m = init(ctx, module_name);
if (!m) {
JS_ThrowReferenceError(ctx, "js_call_module '%s' initialization error",
module_name);
fail:
if (hd != NULL)
FreeLibrary(hd);
return NULL;
}
return m;
}
#elif defined(__wasi__)
static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
{
Expand Down Expand Up @@ -599,7 +653,7 @@ JSModuleDef *js_module_loader(JSContext *ctx,
{
JSModuleDef *m;

if (has_suffix(module_name, ".so")) {
if (has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) {
m = js_module_loader_so(ctx, module_name);
} else {
size_t buf_len;
Expand Down

0 comments on commit 902cc2c

Please sign in to comment.