[njs] QuickJS: added support for QuickJS-NG library.

noreply at nginx.com noreply at nginx.com
Fri Jan 24 23:13:02 UTC 2025


details:   https://github.com/nginx/njs/commit/d4f12ad9a96b16bf02ac09d52908299e2bf0f431
branches:  master
commit:    d4f12ad9a96b16bf02ac09d52908299e2bf0f431
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue, 21 Jan 2025 17:09:06 -0800
description:
QuickJS: added support for QuickJS-NG library.


---
 auto/quickjs             | 72 ++++++++++++++++++++++++++++++++++++++++++++----
 external/qjs_fs_module.c | 22 +++++++--------
 nginx/config             | 36 ++++++++++++++++++++----
 nginx/config.make        |  4 +--
 src/qjs.h                |  8 +++++-
 test/shell_test.exp      | 12 ++++----
 6 files changed, 124 insertions(+), 30 deletions(-)

diff --git a/auto/quickjs b/auto/quickjs
index 9aeb485a..97432142 100644
--- a/auto/quickjs
+++ b/auto/quickjs
@@ -53,9 +53,19 @@ if [ $NJS_TRY_QUICKJS = YES ]; then
         . auto/feature
     fi
 
+    if [ $njs_found = no ]; then
+        njs_feature="QuickJS-NG library -lqjs"
+        njs_feature_incs=""
+        njs_feature_libs="-lqjs -lm -ldl -lpthread"
+
+        . auto/feature
+    fi
+
+
     if [ $njs_found = yes ]; then
 
         njs_feature="QuickJS JS_GetClassID()"
+        njs_feature_name=NJS_HAVE_QUICKJS_GET_CLASS_ID
         njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8)
                           #pragma GCC diagnostic push
                           #pragma GCC diagnostic ignored \"-Wcast-function-type\"
@@ -64,7 +74,7 @@ if [ $NJS_TRY_QUICKJS = YES ]; then
                           #include <quickjs.h>
 
                           int main() {
-                              (void) JS_GetClassID;
+                              (void) JS_GetClassID(JS_UNDEFINED);
                               return 0;
                          }"
 
@@ -78,6 +88,7 @@ if [ $NJS_TRY_QUICKJS = YES ]; then
         fi
 
         njs_feature="QuickJS JS_NewTypedArray()"
+        njs_feature_name=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY
         njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8)
                           #pragma GCC diagnostic push
                           #pragma GCC diagnostic ignored \"-Wcast-function-type\"
@@ -86,15 +97,66 @@ if [ $NJS_TRY_QUICKJS = YES ]; then
                           #include <quickjs.h>
 
                           int main() {
-                              (void) JS_NewTypedArray;
+                              JSValue   ta, argv;
+                              JSRuntime *rt;
+                              JSContext *ctx;
+
+                              rt = JS_NewRuntime();
+                              ctx = JS_NewContext(rt);
+                              argv = JS_NewInt64(ctx, 1);
+                              ta = JS_NewTypedArray(ctx, 1, &argv,
+                                                    JS_TYPED_ARRAY_UINT8);
+                              JS_FreeValue(ctx, ta);
+                              JS_FreeContext(ctx);
+                              JS_FreeRuntime(rt);
                               return 0;
                          }"
 
         . auto/feature
 
-        if [ $njs_found = yes ]; then
-            njs_define=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY . auto/define
-        fi
+        njs_feature="QuickJS JS_IsSameValue()"
+        njs_feature_name=NJS_HAVE_QUICKJS_IS_SAME_VALUE
+        njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8)
+                          #pragma GCC diagnostic push
+                          #pragma GCC diagnostic ignored \"-Wcast-function-type\"
+                          #endif
+
+                          #include <quickjs.h>
+
+                          int main() {
+                              JSRuntime *rt;
+                              JSContext *ctx;
+
+                              rt = JS_NewRuntime();
+                              ctx = JS_NewContext(rt);
+                              (void) JS_IsSameValue(ctx, JS_UNDEFINED, JS_UNDEFINED);
+                              JS_FreeContext(ctx);
+                              JS_FreeRuntime(rt);
+                              return 0;
+                         }"
+
+        . auto/feature
+
+        njs_feature="QuickJS version"
+        njs_feature_name=NJS_QUICKJS_VERSION
+        njs_feature_run=value
+        njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8)
+                          #pragma GCC diagnostic push
+                          #pragma GCC diagnostic ignored \"-Wcast-function-type\"
+                          #endif
+
+                          #include <quickjs.h>
+
+                          int main() {
+#if defined(QJS_VERSION_MAJOR)
+                              printf(\"\\\"%s\\\"\", JS_GetVersion());
+#else
+                              printf(\"\\\"Unknown\\\"\");
+#endif
+                              return 0;
+                         }"
+
+        . auto/feature
 
         NJS_HAVE_QUICKJS=YES
         NJS_QUICKJS_LIB="$njs_feature_libs"
diff --git a/external/qjs_fs_module.c b/external/qjs_fs_module.c
index fc2222ff..2adeef20 100644
--- a/external/qjs_fs_module.c
+++ b/external/qjs_fs_module.c
@@ -397,7 +397,7 @@ qjs_fs_access(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, mode, callback)) {
+        if (qjs_is_same_value(cx, mode, callback)) {
             mode = JS_UNDEFINED;
         }
     }
@@ -586,7 +586,7 @@ qjs_fs_mkdir(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -894,7 +894,7 @@ qjs_fs_read_file(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -955,7 +955,7 @@ qjs_fs_read_file(JSContext *cx, JSValueConst this_val, int argc,
     str.length = sb.st_size;
 
     v = qjs_fs_fd_read(cx, fd, &str);
-    if (!JS_SameValue(cx, v, JS_TRUE)) {
+    if (!qjs_is_same_value(cx, v, JS_TRUE)) {
         if (JS_IsException(v)) {
             result = JS_EXCEPTION;
 
@@ -1012,7 +1012,7 @@ qjs_fs_readlink(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -1150,7 +1150,7 @@ qjs_fs_readdir(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -1309,7 +1309,7 @@ qjs_fs_realpath(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -1655,7 +1655,7 @@ qjs_fs_rmdir(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -1817,7 +1817,7 @@ qjs_fs_stat(JSContext *cx, JSValueConst this_val, int argc, JSValueConst *argv,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
@@ -1916,7 +1916,7 @@ qjs_fs_symlink(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, type, callback)) {
+        if (qjs_is_same_value(cx, type, callback)) {
             type = JS_UNDEFINED;
         }
     }
@@ -2168,7 +2168,7 @@ qjs_fs_write_file(JSContext *cx, JSValueConst this_val, int argc,
             return JS_EXCEPTION;
         }
 
-        if (JS_SameValue(cx, options, callback)) {
+        if (qjs_is_same_value(cx, options, callback)) {
             options = JS_UNDEFINED;
         }
     }
diff --git a/nginx/config b/nginx/config
index 436f06cb..8e920477 100644
--- a/nginx/config
+++ b/nginx/config
@@ -39,7 +39,6 @@ if [ $NJS_QUICKJS != NO ]; then
     ngx_feature_test="JSRuntime *rt;
 
                       rt = JS_NewRuntime();
-                      (void) JS_GetClassID;
                       JS_FreeRuntime(rt);
                       return 0;"
     . auto/feature
@@ -66,17 +65,44 @@ if [ $NJS_QUICKJS != NO ]; then
         . auto/feature
     fi
 
+    if [ $ngx_found = no ]; then
+        ngx_feature="QuickJS-NG library -lqjs"
+        ngx_feature_path=""
+        ngx_feature_libs="-lqjs -lm -ldl -lpthread"
+
+        . auto/feature
+    fi
+
     if [ $ngx_found = yes ]; then
 
+        ngx_feature="QuickJS JS_GetClassID()"
+        ngx_feature_name=NJS_HAVE_QUICKJS_GET_CLASS_ID
+        ngx_feature_run=no
+        ngx_feature_test="(void) JS_GetClassID(JS_UNDEFINED);"
+
+        . auto/feature
+
+        if [ $ngx_found = no ]; then
+            echo
+            echo $0: error: QuickJS library found, but JS_GetClassID\(\) is missing.
+            echo
+            exit 1;
+        fi
+
         ngx_feature="QuickJS JS_NewTypedArray()"
-        ngx_feature_test="(void) JS_NewTypedArray;
+        ngx_feature_name=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY
+        ngx_feature_test="JSValue argv;
+                         (void) JS_NewTypedArray(NULL, 1, &argv,
+                                                 JS_TYPED_ARRAY_UINT8);
                           return 0;"
 
         . auto/feature
 
-        if [ $ngx_found = yes ]; then
-            have=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY . auto/have
-        fi
+        ngx_feature="QuickJS JS_IsSameValue()"
+        ngx_feature_name=NJS_HAVE_QUICKJS_IS_SAME_VALUE
+        ngx_feature_test="(void) JS_IsSameValue(NULL, JS_UNDEFINED, JS_UNDEFINED);"
+
+        . auto/feature
 
         NJS_HAVE_QUICKJS=YES
         NJS_QUICKJS_LIB="$ngx_feature_libs"
diff --git a/nginx/config.make b/nginx/config.make
index 2fa40063..404a622b 100644
--- a/nginx/config.make
+++ b/nginx/config.make
@@ -4,14 +4,14 @@ $ngx_addon_dir/../build/libnjs.a: $NGX_MAKEFILE
 	cd $ngx_addon_dir/.. \\
 	&& if [ -f build/Makefile ]; then \$(MAKE) clean; fi \\
 	&& CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-openssl \\
-		--no-libxml2 --no-zlib --no-pcre --no-quickjs \\
+		--no-libxml2 --no-zlib --no-pcre --no-quickjs --ld-opt="$NGX_LD_OPT" \\
 	&& \$(MAKE) libnjs
 
 $ngx_addon_dir/../build/libqjs.a: $NGX_MAKEFILE
 	cd $ngx_addon_dir/.. \\
 	&& if [ -f build/Makefile ]; then \$(MAKE) clean; fi \\
 	&& CFLAGS="\$(CFLAGS)" CC="\$(CC)" ./configure --no-openssl \\
-		--no-libxml2 --no-zlib --no-pcre \\
+		--no-libxml2 --no-zlib --no-pcre --ld-opt="$NGX_LD_OPT" \\
 	&& \$(MAKE) libnjs libqjs
 
 END
diff --git a/src/qjs.h b/src/qjs.h
index 76bf5c3d..71dd297e 100644
--- a/src/qjs.h
+++ b/src/qjs.h
@@ -29,7 +29,6 @@
 #if defined(__GNUC__) && (__GNUC__ >= 8)
 #pragma GCC diagnostic pop
 #endif
-#define NJS_QUICKJS_VERSION  "Unknown version"
 #include <pthread.h>
 
 
@@ -101,6 +100,13 @@ static inline JS_BOOL JS_IsNullOrUndefined(JSValueConst v)
 }
 
 
+#ifdef NJS_HAVE_QUICKJS_IS_SAME_VALUE
+#define qjs_is_same_value(cx, a, b) JS_IsSameValue(cx, a, b)
+#else
+#define qjs_is_same_value(cx, a, b) JS_SameValue(cx, a, b)
+#endif
+
+
 extern qjs_module_t              *qjs_modules[];
 
 #endif /* _QJS_H_INCLUDED_ */
diff --git a/test/shell_test.exp b/test/shell_test.exp
index b713ed09..02828270 100644
--- a/test/shell_test.exp
+++ b/test/shell_test.exp
@@ -302,11 +302,11 @@ njs_test {
 
 njs_test {
     {"function f() { return ({}.a.a); }\r\n"
-     "undefined"}
-    {"var e; try {f()} catch (ee) {e = ee}\r\n"
-     "undefined"}
+     "undefined\r\n>> "}
+    {"var e; try {f()} catch (ee) {e = ee}; undefined\r\n"
+     "undefined\r\n>> "}
     {"Object.keys(null)\r\n"
-     "Thrown:\r\nTypeError: cannot convert*to object"}
+     "Thrown:\r\nTypeError: *annot convert*to object"}
     {"e\r\n"
      "TypeError: cannot * property *a* of undefined"}
 }
@@ -382,11 +382,11 @@ njs_test {
 
 njs_run {"-c" "setTimeout(() => {console.log('A'.repeat(1024))}, 0); ref"} \
 "^Thrown:
-ReferenceError: \['\"\]ref\['\"\] is not defined.*"
+ReferenceError: .* is not defined.*"
 
 njs_run {"-c" "setTimeout(() => {ref}, 0); setTimeout(() => {console.log('A'.repeat(1024))}, 0)"} \
 "^Thrown:
-ReferenceError: \['\"\]ref\['\"\] is not defined.*"
+ReferenceError: .* is not defined.*"
 
 njs_test {
     {"setImmediate(() => { console.log('x'); return Promise.reject('xx'); })\r\n"


More information about the nginx-devel mailing list