Skip to content

Commit 902cc2c

Browse files
authored
Add native module support on Windows
1 parent ada24f3 commit 902cc2c

File tree

8 files changed

+166
-53
lines changed

8 files changed

+166
-53
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,14 +195,20 @@ jobs:
195195
- uses: actions/checkout@v4
196196
- name: build
197197
run: |
198-
cmake -B build -G "Visual Studio 17 2022" -A ${{matrix.arch}}
198+
cmake -B build -DBUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -A ${{matrix.arch}}
199199
cmake --build build --config ${{matrix.buildType}} --target qjs_exe
200200
cmake --build build --config ${{matrix.buildType}} --target function_source
201+
cmake --build build --config ${{matrix.buildType}} --target fib
202+
cmake --build build --config ${{matrix.buildType}} --target point
201203
- name: stats
202204
run: |
203205
build\${{matrix.buildType}}\qjs.exe -qd
204206
- name: test
205207
run: |
208+
cp build\${{matrix.buildType}}\fib.dll examples\
209+
cp build\${{matrix.buildType}}\point.dll examples\
210+
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
211+
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
206212
build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
207213
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
208214
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
@@ -224,14 +230,20 @@ jobs:
224230
- uses: actions/checkout@v4
225231
- name: build
226232
run: |
227-
cmake -B build -G "Visual Studio 17 2022" -T ClangCL
233+
cmake -B build -DBUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -T ClangCL
228234
cmake --build build --config ${{matrix.buildType}} --target qjs_exe
229235
cmake --build build --config ${{matrix.buildType}} --target function_source
236+
cmake --build build --config ${{matrix.buildType}} --target fib
237+
cmake --build build --config ${{matrix.buildType}} --target point
230238
- name: stats
231239
run: |
232240
build\${{matrix.buildType}}\qjs.exe -qd
233241
- name: test
234242
run: |
243+
cp build\${{matrix.buildType}}\fib.dll examples\
244+
cp build\${{matrix.buildType}}\point.dll examples\
245+
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
246+
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
235247
build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
236248
build\${{matrix.buildType}}\qjs.exe tests\test_bjson.js
237249
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
@@ -257,14 +269,20 @@ jobs:
257269
ninja.exe --version
258270
- name: build
259271
run: |
260-
cmake -B build -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
272+
cmake -B build -DBUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
261273
cmake --build build --target qjs_exe
262274
cmake --build build --target function_source
275+
cmake --build build --target fib
276+
cmake --build build --target point
263277
- name: stats
264278
run: |
265279
build\qjs.exe -qd
266280
- name: test
267281
run: |
282+
cp build\fib.dll examples\
283+
cp build\point.dll examples\
284+
build\qjs.exe examples\test_fib.js
285+
build\qjs.exe examples\test_point.js
268286
build\qjs.exe tests\test_bigint.js
269287
build\qjs.exe tests\test_bjson.js
270288
build\qjs.exe tests\test_closure.js

CMakeLists.txt

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ target_link_libraries(function_source ${qjs_libs})
273273
# Examples
274274
#
275275

276-
if(BUILD_EXAMPLES AND NOT WIN32)
276+
if(BUILD_EXAMPLES)
277277
add_executable(hello
278278
gen/hello.c
279279
)
@@ -290,27 +290,31 @@ if(BUILD_EXAMPLES AND NOT WIN32)
290290
target_compile_definitions(hello_module PRIVATE ${qjs_defines})
291291
target_link_libraries(hello_module ${qjs_libs})
292292

293-
if(NOT WIN32)
294-
add_library(fib MODULE examples/fib.c)
295-
set_target_properties(fib PROPERTIES
296-
PREFIX ""
297-
C_VISIBILITY_PRESET default
298-
)
299-
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
300-
if(APPLE)
301-
target_link_options(fib PRIVATE -undefined dynamic_lookup)
302-
endif()
293+
add_library(fib MODULE examples/fib.c)
294+
set_target_properties(fib PROPERTIES
295+
PREFIX ""
296+
C_VISIBILITY_PRESET default
297+
)
298+
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
299+
if(WIN32)
300+
target_link_libraries(fib ${qjs_libs})
301+
endif()
302+
if(APPLE)
303+
target_link_options(fib PRIVATE -undefined dynamic_lookup)
304+
endif()
303305

304-
add_library(point MODULE examples/point.c)
305-
set_target_properties(point PROPERTIES
306-
PREFIX ""
307-
C_VISIBILITY_PRESET default
308-
)
309-
target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY)
310-
if(APPLE)
311-
target_link_options(point PRIVATE -undefined dynamic_lookup)
312-
endif()
306+
add_library(point MODULE examples/point.c)
307+
set_target_properties(point PROPERTIES
308+
PREFIX ""
309+
C_VISIBILITY_PRESET default
310+
)
311+
target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY)
312+
if(WIN32)
313+
target_link_libraries(point ${qjs_libs})
313314
endif()
315+
if(APPLE)
316+
target_link_options(point PRIVATE -undefined dynamic_lookup)
317+
endif()
314318

315319
add_executable(test_fib
316320
examples/fib.c

examples/fib.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ static int js_fib_init(JSContext *ctx, JSModuleDef *m)
6161
#define JS_INIT_MODULE js_init_module_fib
6262
#endif
6363

64-
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
64+
#ifndef JS_EXTERN
65+
#ifdef _WIN32
66+
#define JS_EXTERN __declspec(dllexport)
67+
#else
68+
#define JS_EXTERN
69+
#endif
70+
#endif
71+
72+
JS_EXTERN JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
6573
{
6674
JSModuleDef *m;
6775
m = JS_NewCModule(ctx, module_name, js_fib_init);

examples/point.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,15 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m)
141141
return 0;
142142
}
143143

144-
JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
144+
#ifndef JS_EXTERN
145+
#ifdef _WIN32
146+
#define JS_EXTERN __declspec(dllexport)
147+
#else
148+
#define JS_EXTERN
149+
#endif
150+
#endif
151+
152+
JS_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
145153
{
146154
JSModuleDef *m;
147155
m = JS_NewCModule(ctx, module_name, js_point_init);

examples/test_fib.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* example of JS module importing a C module */
2+
import * as os from "os";
23

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

57
console.log("Hello World");
68
console.log("fib(10)=", fib(10));

examples/test_point.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/* example of JS module importing a C module */
2-
import { Point } from "./point.so";
2+
import * as os from "os";
3+
4+
const isWin = os.platform === 'win32';
5+
const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`);
36

47
function assert(b, str)
58
{

gen/test_fib.c

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,46 @@
22

33
#include "quickjs-libc.h"
44

5-
const uint32_t qjsc_test_fib_size = 167;
5+
const uint32_t qjsc_test_fib_size = 293;
66

7-
const uint8_t qjsc_test_fib[167] = {
8-
0x0d, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
7+
const uint8_t qjsc_test_fib[293] = {
8+
0x0d, 0x0d, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
99
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
10-
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
11-
0x2e, 0x2f, 0x66, 0x69, 0x62, 0x2e, 0x73, 0x6f,
12-
0x06, 0x66, 0x69, 0x62, 0x0e, 0x63, 0x6f, 0x6e,
13-
0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67,
14-
0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
15-
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
16-
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb8, 0x03,
17-
0x01, 0xba, 0x03, 0x00, 0x00, 0x01, 0x00, 0xbc,
18-
0x03, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0xa2,
19-
0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32,
20-
0x00, 0xbc, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02,
21-
0x29, 0x38, 0xdf, 0x00, 0x00, 0x00, 0x42, 0xe0,
22-
0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00,
23-
0x24, 0x01, 0x00, 0x0e, 0x38, 0xdf, 0x00, 0x00,
24-
0x00, 0x42, 0xe0, 0x00, 0x00, 0x00, 0x04, 0xe2,
25-
0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a,
26-
0xee, 0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb8,
27-
0x03, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04,
28-
0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
10+
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x04,
11+
0x6f, 0x73, 0x0a, 0x69, 0x73, 0x57, 0x69, 0x6e,
12+
0x06, 0x66, 0x69, 0x62, 0x10, 0x70, 0x6c, 0x61,
13+
0x74, 0x66, 0x6f, 0x72, 0x6d, 0x0a, 0x77, 0x69,
14+
0x6e, 0x33, 0x32, 0x0c, 0x2e, 0x2f, 0x66, 0x69,
15+
0x62, 0x2e, 0x06, 0x64, 0x6c, 0x6c, 0x04, 0x73,
16+
0x6f, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c,
17+
0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48, 0x65,
18+
0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
19+
0x64, 0x10, 0x66, 0x69, 0x62, 0x28, 0x31, 0x30,
20+
0x29, 0x3d, 0x0d, 0xb8, 0x03, 0x01, 0xba, 0x03,
21+
0x00, 0x00, 0x01, 0x00, 0xfc, 0x01, 0x00, 0x01,
22+
0x0c, 0x20, 0xfa, 0x01, 0xa2, 0x01, 0x00, 0x00,
23+
0x00, 0x05, 0x03, 0x00, 0x73, 0x00, 0xba, 0x03,
24+
0x00, 0x0d, 0xbc, 0x03, 0x00, 0x0d, 0xbe, 0x03,
25+
0x01, 0x0d, 0x08, 0xe9, 0x02, 0x29, 0x65, 0x00,
26+
0x00, 0x41, 0xe0, 0x00, 0x00, 0x00, 0x04, 0xe1,
27+
0x00, 0x00, 0x00, 0xae, 0xe1, 0x06, 0x11, 0xf1,
28+
0xea, 0x0b, 0x70, 0x42, 0xdf, 0x00, 0x00, 0x00,
29+
0xe2, 0x0e, 0xeb, 0x24, 0x0e, 0x04, 0xe2, 0x00,
30+
0x00, 0x00, 0x42, 0x5d, 0x00, 0x00, 0x00, 0x65,
31+
0x01, 0x00, 0xe9, 0x08, 0x04, 0xe3, 0x00, 0x00,
32+
0x00, 0xeb, 0x06, 0x04, 0xe4, 0x00, 0x00, 0x00,
33+
0x24, 0x01, 0x00, 0x35, 0x8b, 0xeb, 0xd4, 0x38,
34+
0xe5, 0x00, 0x00, 0x00, 0x42, 0xe6, 0x00, 0x00,
35+
0x00, 0x04, 0xe7, 0x00, 0x00, 0x00, 0x24, 0x01,
36+
0x00, 0x0e, 0x38, 0xe5, 0x00, 0x00, 0x00, 0x42,
37+
0xe6, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00,
38+
0x00, 0x65, 0x02, 0x00, 0xbb, 0x0a, 0xee, 0x24,
39+
0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb8, 0x03, 0x01,
40+
0x01, 0x22, 0x01, 0x01, 0x00, 0x04, 0x08, 0x1e,
41+
0x2a, 0x18, 0x1b, 0x08, 0x0d, 0x3b, 0x1b, 0x0c,
42+
0x07, 0x04, 0x25, 0x08, 0x0c, 0x04, 0x07, 0x10,
43+
0x43, 0x2c, 0x25, 0x10, 0x25, 0x04, 0x27, 0x6b,
44+
0x62, 0x00, 0x4d, 0x30, 0x00,
2945
};
3046

3147
static JSContext *JS_NewCustomContext(JSRuntime *rt)
@@ -34,8 +50,8 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
3450
if (!ctx)
3551
return NULL;
3652
{
37-
extern JSModuleDef *js_init_module_fib(JSContext *ctx, const char *name);
38-
js_init_module_fib(ctx, "examples/fib.so");
53+
extern JSModuleDef *js_init_module_os(JSContext *ctx, const char *name);
54+
js_init_module_os(ctx, "os");
3955
}
4056
return ctx;
4157
}

quickjs-libc.c

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ extern char **environ;
9696

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

99+
#ifndef QJS_NATIVE_MODULE_SUFFIX
100+
#ifdef _WIN32
101+
#define QJS_NATIVE_MODULE_SUFFIX ".dll"
102+
#else
103+
#define QJS_NATIVE_MODULE_SUFFIX ".so"
104+
#endif
105+
#endif
106+
99107
/* TODO:
100108
- add socket calls
101109
*/
@@ -483,7 +491,53 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
483491
const char *module_name);
484492

485493

486-
#if defined(_WIN32) || defined(__wasi__)
494+
#if defined(_WIN32)
495+
static JSModuleDef *js_module_loader_so(JSContext *ctx,
496+
const char *module_name)
497+
{
498+
JSModuleDef *m;
499+
HINSTANCE hd;
500+
JSInitModuleFunc *init;
501+
char *filename = NULL;
502+
size_t len = strlen(module_name);
503+
JS_BOOL is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') ||
504+
(module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':';
505+
JS_BOOL is_relative = len > 2 && module_name[0] == '.' && (module_name[1] == '/' || module_name[1] == '\\');
506+
if (is_absolute || is_relative) {
507+
filename = (char *)module_name;
508+
} else {
509+
filename = js_malloc(ctx, len + 2 + 1);
510+
if (!filename)
511+
return NULL;
512+
strcpy(filename, "./");
513+
strcpy(filename + 2, module_name);
514+
}
515+
hd = LoadLibraryA(filename);
516+
if (filename != module_name)
517+
js_free(ctx, filename);
518+
if (hd == NULL) {
519+
JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu",
520+
module_name, GetLastError());
521+
goto fail;
522+
}
523+
init = (JSInitModuleFunc *)(uintptr_t)GetProcAddress(hd, "js_init_module");
524+
if (!init) {
525+
JS_ThrowReferenceError(ctx, "js_init_module '%s' not found: %lu",
526+
module_name, GetLastError());
527+
goto fail;
528+
}
529+
m = init(ctx, module_name);
530+
if (!m) {
531+
JS_ThrowReferenceError(ctx, "js_call_module '%s' initialization error",
532+
module_name);
533+
fail:
534+
if (hd != NULL)
535+
FreeLibrary(hd);
536+
return NULL;
537+
}
538+
return m;
539+
}
540+
#elif defined(__wasi__)
487541
static JSModuleDef *js_module_loader_so(JSContext *ctx,
488542
const char *module_name)
489543
{
@@ -599,7 +653,7 @@ JSModuleDef *js_module_loader(JSContext *ctx,
599653
{
600654
JSModuleDef *m;
601655

602-
if (has_suffix(module_name, ".so")) {
656+
if (has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) {
603657
m = js_module_loader_so(ctx, module_name);
604658
} else {
605659
size_t buf_len;

0 commit comments

Comments
 (0)