Add native module support on Windows

This commit is contained in:
zeromake 2024-09-11 04:47:40 +08:00 committed by GitHub
parent ada24f33f3
commit 902cc2cf0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 127 additions and 30 deletions

View file

@ -195,14 +195,20 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: build - name: build
run: | 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 qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source 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 - name: stats
run: | run: |
build\${{matrix.buildType}}\qjs.exe -qd build\${{matrix.buildType}}\qjs.exe -qd
- name: test - name: test
run: | 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_bigint.js
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
@ -224,14 +230,20 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: build - name: build
run: | 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 qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source 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 - name: stats
run: | run: |
build\${{matrix.buildType}}\qjs.exe -qd build\${{matrix.buildType}}\qjs.exe -qd
- name: test - name: test
run: | 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_bigint.js
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
@ -257,14 +269,20 @@ jobs:
ninja.exe --version ninja.exe --version
- name: build - name: build
run: | 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 qjs_exe
cmake --build build --target function_source cmake --build build --target function_source
cmake --build build --target fib
cmake --build build --target point
- name: stats - name: stats
run: | run: |
build\qjs.exe -qd build\qjs.exe -qd
- name: test - name: test
run: | 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_bigint.js
build\qjs.exe tests\test_bjson.js build\qjs.exe tests\test_bjson.js
build\qjs.exe tests\test_closure.js build\qjs.exe tests\test_closure.js

View file

@ -273,7 +273,7 @@ target_link_libraries(function_source ${qjs_libs})
# Examples # Examples
# #
if(BUILD_EXAMPLES AND NOT WIN32) if(BUILD_EXAMPLES)
add_executable(hello add_executable(hello
gen/hello.c gen/hello.c
) )
@ -290,27 +290,31 @@ if(BUILD_EXAMPLES AND NOT WIN32)
target_compile_definitions(hello_module PRIVATE ${qjs_defines}) target_compile_definitions(hello_module PRIVATE ${qjs_defines})
target_link_libraries(hello_module ${qjs_libs}) target_link_libraries(hello_module ${qjs_libs})
if(NOT WIN32) add_library(fib MODULE examples/fib.c)
add_library(fib MODULE examples/fib.c) set_target_properties(fib PROPERTIES
set_target_properties(fib PROPERTIES PREFIX ""
PREFIX "" C_VISIBILITY_PRESET default
C_VISIBILITY_PRESET default )
) target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY) if(WIN32)
if(APPLE) target_link_libraries(fib ${qjs_libs})
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()
endif() 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(WIN32)
target_link_libraries(point ${qjs_libs})
endif()
if(APPLE)
target_link_options(point PRIVATE -undefined dynamic_lookup)
endif()
add_executable(test_fib add_executable(test_fib
examples/fib.c examples/fib.c

View file

@ -61,7 +61,15 @@ static int js_fib_init(JSContext *ctx, JSModuleDef *m)
#define JS_INIT_MODULE js_init_module_fib #define JS_INIT_MODULE js_init_module_fib
#endif #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; JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_fib_init); m = JS_NewCModule(ctx, module_name, js_fib_init);

View file

@ -141,7 +141,15 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m)
return 0; 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; JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_point_init); m = JS_NewCModule(ctx, module_name, js_point_init);

View file

@ -1,6 +1,8 @@
/* example of JS module importing a C module */ /* 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("Hello World");
console.log("fib(10)=", fib(10)); console.log("fib(10)=", fib(10));

View file

@ -1,5 +1,8 @@
/* example of JS module importing a C module */ /* 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) function assert(b, str)
{ {

Binary file not shown.

View file

@ -96,6 +96,14 @@ extern char **environ;
#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1) #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: /* TODO:
- add socket calls - add socket calls
*/ */
@ -483,7 +491,53 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
const char *module_name); 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, static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name) const char *module_name)
{ {
@ -599,7 +653,7 @@ JSModuleDef *js_module_loader(JSContext *ctx,
{ {
JSModuleDef *m; 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); m = js_module_loader_so(ctx, module_name);
} else { } else {
size_t buf_len; size_t buf_len;