diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f37978dd..3507db09b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -648,11 +648,14 @@ jobs: - name: clang+sanitize args: >- "-Db_sanitize=address,undefined" + "-Db_lundef=false" extra_envs: CC: clang CXX: clang++ - name: clang+msan - args: -Db_sanitize=memory + args: >- + "-Db_sanitize=memory" + "-Db_lundef=false" extra_envs: CC: clang CXX: clang++ @@ -662,6 +665,7 @@ jobs: - name: clang-cl+sanitize args: >- "-Db_sanitize=address,undefined" + "-Db_lundef=false" extra_envs: CC: clang-cl CXX: clang-cl diff --git a/CMakeLists.txt b/CMakeLists.txt index 76ab2a519..e41754555 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,9 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD 11) +# Used to properly define JS_LIBC_EXTERN. +add_compile_definitions(QUICKJS_NG_BUILD) + # MINGW doesn't exist in older cmake versions, newer versions don't know # about CMAKE_COMPILER_IS_MINGW, and there is no unique CMAKE_C_COMPILER_ID # for mingw-based compilers... @@ -232,7 +235,7 @@ endif() xoption(QJS_BUILD_LIBC "Build standard library modules as part of the library" OFF) macro(add_qjs_libc_if_needed target) if(NOT QJS_BUILD_LIBC) - target_sources(${target} PRIVATE quickjs-libc.c) + target_link_libraries(${target} PRIVATE qjs-libc) endif() endmacro() macro(add_static_if_needed target) @@ -245,7 +248,6 @@ macro(add_static_if_needed target) endmacro() set(qjs_sources - cutils.c dtoa.c libregexp.c libunicode.c @@ -254,6 +256,8 @@ set(qjs_sources if(QJS_BUILD_LIBC) list(APPEND qjs_sources quickjs-libc.c) + # The definition must be added to the entire project. + add_compile_definitions(QJS_BUILD_LIBC) endif() list(APPEND qjs_defines _GNU_SOURCE) if(WIN32) @@ -278,6 +282,10 @@ if(M_LIBRARIES OR CMAKE_C_COMPILER_ID STREQUAL "TinyCC") list(APPEND qjs_libs m) endif() +add_library(cutils STATIC cutils.c) +target_compile_definitions(cutils PRIVATE ${qjs_defines}) +target_link_libraries(cutils PRIVATE ${qjs_libs}) + add_library(qjs ${qjs_sources}) target_compile_definitions(qjs PRIVATE ${qjs_defines}) target_include_directories(qjs PUBLIC @@ -285,6 +293,39 @@ target_include_directories(qjs PUBLIC $ ) target_link_libraries(qjs PUBLIC ${qjs_libs}) +target_link_libraries(qjs PRIVATE $) + +# Pass a compiler definition so that Windows gets its declspec's right. +get_target_property(QJS_LIB_TYPE qjs TYPE) +if(QJS_LIB_TYPE STREQUAL "SHARED_LIBRARY") + target_compile_definitions(qjs + PRIVATE BUILDING_QJS_SHARED + PUBLIC USING_QJS_SHARED + ) +endif() + +# An interface library for modules. +add_library(qjs_module_lib INTERFACE) +target_include_directories(qjs_module_lib INTERFACE + $ +) +target_compile_definitions(qjs_module_lib INTERFACE + QUICKJS_NG_MODULE_BUILD + $ +) +if(WIN32) + # Since Windows cannot resolve symbols at load time, we need to + # explicitly link it to qjs. + target_link_libraries(qjs_module_lib INTERFACE + qjs + ) +endif() + +if(NOT QJS_BUILD_LIBC) + add_library(qjs-libc STATIC quickjs-libc.c) + target_compile_definitions(qjs-libc PRIVATE ${qjs_defines}) + target_link_libraries(qjs-libc PRIVATE ${qjs_libs} qjs cutils) +endif() if(EMSCRIPTEN) add_executable(qjs_wasm ${qjs_sources}) @@ -301,7 +342,7 @@ if(EMSCRIPTEN) -sEXPORTED_RUNTIME_METHODS=ccall,cwrap ) target_compile_definitions(qjs_wasm PRIVATE ${qjs_defines}) - target_link_libraries(qjs_wasm m) + target_link_libraries(qjs_wasm PRIVATE m) endif() @@ -314,7 +355,7 @@ add_executable(qjsc add_qjs_libc_if_needed(qjsc) add_static_if_needed(qjsc) target_compile_definitions(qjsc PRIVATE ${qjs_defines}) -target_link_libraries(qjsc qjs) +target_link_libraries(qjsc PRIVATE qjs cutils) # QuickJS CLI @@ -331,10 +372,8 @@ set_target_properties(qjs_exe PROPERTIES OUTPUT_NAME "qjs" ) target_compile_definitions(qjs_exe PRIVATE ${qjs_defines}) -target_link_libraries(qjs_exe qjs) -if(NOT WIN32) - set_target_properties(qjs_exe PROPERTIES ENABLE_EXPORTS TRUE) -endif() +target_link_libraries(qjs_exe PRIVATE qjs cutils) +set_target_properties(qjs_exe PROPERTIES ENABLE_EXPORTS TRUE) # WASI Reactor # @@ -369,9 +408,9 @@ if(QJS_BUILD_CLI_WITH_MIMALLOC OR QJS_BUILD_CLI_WITH_STATIC_MIMALLOC) find_package(mimalloc REQUIRED) # Upstream mimalloc doesn't provide a way to know if both libraries are supported. if(QJS_BUILD_CLI_WITH_STATIC_MIMALLOC) - target_link_libraries(qjs_exe mimalloc-static) + target_link_libraries(qjs_exe PRIVATE mimalloc-static) else() - target_link_libraries(qjs_exe mimalloc) + target_link_libraries(qjs_exe PRIVATE mimalloc) endif() endif() @@ -384,7 +423,7 @@ if(NOT EMSCRIPTEN) ) add_qjs_libc_if_needed(run-test262) target_compile_definitions(run-test262 PRIVATE ${qjs_defines}) - target_link_libraries(run-test262 qjs) + target_link_libraries(run-test262 PRIVATE qjs cutils) endif() # Interrupt test @@ -394,17 +433,17 @@ add_executable(api-test api-test.c ) target_compile_definitions(api-test PRIVATE ${qjs_defines}) -target_link_libraries(api-test qjs) +target_link_libraries(api-test PRIVATE qjs cutils) # Unicode generator # add_executable(unicode_gen EXCLUDE_FROM_ALL - cutils.c libunicode.c unicode_gen.c ) target_compile_definitions(unicode_gen PRIVATE ${qjs_defines}) +target_link_libraries(unicode_gen PRIVATE cutils) add_executable(function_source gen/function_source.c @@ -412,19 +451,28 @@ add_executable(function_source add_qjs_libc_if_needed(function_source) target_include_directories(function_source PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_definitions(function_source PRIVATE ${qjs_defines}) -target_link_libraries(function_source qjs) +target_link_libraries(function_source PRIVATE qjs) # Examples # if(QJS_BUILD_EXAMPLES) + if(WIN32 AND NOT (QJS_LIB_TYPE STREQUAL "SHARED_LIBRARY")) + message(AUTHOR_WARNING + "Binary modules used with static qjs on Windows. There might be\n" + "runtime errors when the module is used due to two copies of qjs\n" + "in memory.\n" + "Please use \"-DBUILD_SHARED_LIBS=true\" if possible." + ) + endif() + add_executable(hello gen/hello.c ) add_qjs_libc_if_needed(hello) target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_definitions(hello PRIVATE ${qjs_defines}) - target_link_libraries(hello qjs) + target_link_libraries(hello PRIVATE qjs) add_executable(hello_module gen/hello_module.c @@ -432,40 +480,35 @@ if(QJS_BUILD_EXAMPLES) add_qjs_libc_if_needed(hello_module) target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_definitions(hello_module PRIVATE ${qjs_defines}) - target_link_libraries(hello_module qjs) + target_link_libraries(hello_module PRIVATE qjs) 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) - elseif(APPLE) + target_link_libraries(fib PRIVATE qjs_module_lib) + 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) - elseif(APPLE) + target_link_libraries(point PRIVATE qjs_module_lib) + if(APPLE) target_link_options(point PRIVATE -undefined dynamic_lookup) endif() add_executable(test_fib - examples/fib.c gen/test_fib.c ) add_qjs_libc_if_needed(test_fib) target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_definitions(test_fib PRIVATE ${qjs_defines}) - target_link_libraries(test_fib qjs) + target_link_libraries(test_fib PRIVATE qjs) + # Loads fib.so which depends on symbols from libqjs. + set_target_properties(test_fib PROPERTIES ENABLE_EXPORTS TRUE) endif() # Install target diff --git a/examples/fib.c b/examples/fib.c index b965acc5b..a9eb29d92 100644 --- a/examples/fib.c +++ b/examples/fib.c @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "../quickjs.h" + +#include #define countof(x) (sizeof(x) / sizeof((x)[0])) @@ -55,21 +56,7 @@ static int js_fib_init(JSContext *ctx, JSModuleDef *m) countof(js_fib_funcs)); } -#ifdef JS_SHARED_LIBRARY -#define JS_INIT_MODULE js_init_module -#else -#define JS_INIT_MODULE js_init_module_fib -#endif - -#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) +JS_MODULE_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) { JSModuleDef *m; m = JS_NewCModule(ctx, module_name, js_fib_init); diff --git a/examples/meson.build b/examples/meson.build index 08c9d87b6..08f0329f1 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -3,9 +3,8 @@ shared_module( 'fib.c', name_prefix: '', - gnu_symbol_visibility: 'default', - c_args: ['-DJS_SHARED_LIBRARY'], - dependencies: host_system == 'windows' ? qjs_dep : [], + gnu_symbol_visibility: 'hidden', + dependencies: qjs_module_dep, ) shared_module( @@ -13,7 +12,6 @@ shared_module( 'point.c', name_prefix: '', - gnu_symbol_visibility: 'default', - c_args: ['-DJS_SHARED_LIBRARY'], - dependencies: host_system == 'windows' ? qjs_dep : [], + gnu_symbol_visibility: 'hidden', + dependencies: qjs_module_dep, ) diff --git a/examples/point.c b/examples/point.c index a82df1519..baa06388c 100644 --- a/examples/point.c +++ b/examples/point.c @@ -21,9 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "../quickjs.h" + #include +#include + #define countof(x) (sizeof(x) / sizeof((x)[0])) /* Point Class */ @@ -141,15 +143,7 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m) return 0; } -#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) +JS_MODULE_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) { JSModuleDef *m; m = JS_NewCModule(ctx, module_name, js_point_init); diff --git a/meson.build b/meson.build index cf79060bc..bff731a23 100644 --- a/meson.build +++ b/meson.build @@ -5,7 +5,6 @@ project( default_options: [ 'c_std=gnu11,c11', 'warning_level=3', - 'default_library=static', ], license: 'MIT', license_files: 'LICENSE', @@ -15,6 +14,8 @@ project( host_system = host_machine.system() cc = meson.get_compiler('c') +add_project_arguments('-DQUICKJS_NG_BUILD', language: 'c') + qjs_gcc_warning_args = [ '-Wno-unsafe-buffer-usage', '-Wno-sign-conversion', @@ -133,7 +134,6 @@ qjs_sys_deps += dependency('threads', required: false) qjs_sys_deps += dependency('dl', required: false) qjs_srcs = files( - 'cutils.c', 'dtoa.c', 'libregexp.c', 'libunicode.c', @@ -149,6 +149,10 @@ qjs_libc_hdrs = files('quickjs-libc.h') if qjs_libc qjs_hdrs += qjs_libc_hdrs + add_project_arguments( + '-DQJS_BUILD_LIBC', + language: 'c' + ) endif qjs_parser = get_option('parser') @@ -163,29 +167,23 @@ if not qjs_parser qjs_c_args += ['-DQJS_DISABLE_PARSER'] endif -qjs_libc_lib = static_library( - 'quickjs-libc', - qjs_libc_srcs, +cutils_lib = static_library( + 'cutils', + 'cutils.c', dependencies: qjs_sys_deps, - c_args: qjs_c_args, - gnu_symbol_visibility: 'hidden', + c_args: qjs_c_args ) qjs_lib = library( 'qjs', qjs_srcs, - - # export public headers - generator( - find_program('cp', 'xcopy'), - output: ['@PLAINNAME@'], - arguments: ['@INPUT@', '@OUTPUT@'], - ).process(qjs_hdrs), + qjs_libc ? qjs_libc_srcs : [], dependencies: qjs_sys_deps, - link_whole: qjs_libc ? qjs_libc_lib : [], - c_args: qjs_c_args, + link_with: cutils_lib, + c_args: [qjs_c_args, '-DQUICKJS_NG_QJS_INTERNAL'], + c_shared_args: ['-DBUILDING_QJS_SHARED'], gnu_symbol_visibility: 'hidden', install: true, @@ -196,13 +194,58 @@ qjs_export_variables = [ f'have_parser=@qjs_parser@' ] +# This note is only of interest on Windows. +# Be conservative here: only pass -DUSING_QJS_SHARED iff default_library == +# 'shared', thus qjs is guarranteed to be a DLL. Not passing -DUSING_QJS_SHARED if +# qjs is a DLL is not harmful, but passing the definition for DLL qjs is desired. +# Conversely, if -DUSING_QJS_SHARED is passed for static qjs, the consumers +# will not compile. +qjs_dep_args = get_option('default_library') == 'shared' ? ['-DUSING_QJS_SHARED'] : [] + qjs_dep = declare_dependency( + compile_args: qjs_dep_args, link_with: qjs_lib, dependencies: qjs_sys_deps, - include_directories: qjs_lib.private_dir_include(), + include_directories: include_directories('.'), variables: qjs_export_variables, ) +if host_system != 'windows' + qjs_module_dep = declare_dependency( + compile_args: [qjs_dep_args, '-DQUICKJS_NG_MODULE_BUILD'], + include_directories: include_directories('.'), + ) +else + qjs_module_dep = declare_dependency( + compile_args: [qjs_dep_args, '-DQUICKJS_NG_MODULE_BUILD'], + include_directories: include_directories('.'), + # Windows can't resolve symbols at runtime thus we explicitly link to qjs. + dependencies: qjs_dep, + ) +endif + +if qjs_libc + qjs_libc_dep = declare_dependency( + include_directories: include_directories('.'), + dependencies: qjs_dep, + ) +else + qjs_libc_lib = static_library( + 'quickjs-libc', + qjs_libc_srcs, + + c_args: qjs_c_args, + link_with: cutils_lib, + dependencies: [qjs_sys_deps, qjs_dep], + gnu_symbol_visibility: 'hidden', + ) + qjs_libc_dep = declare_dependency( + link_with: qjs_libc_lib, + # Pick up quickjs-libc.h. + include_directories: include_directories('.'), + ) +endif + if host_system == 'emscripten' qjs_wasm_export_name = 'getQuickJs' executable( @@ -259,6 +302,8 @@ import('pkgconfig').generate( url: 'https://github.com/quickjs-ng/quickjs', version: meson.project_version(), variables: qjs_export_variables, + # Export -DUSING_QJS_SHARED, if needed, in the pkgconfig file. + extra_cflags: qjs_dep_args, ) if not qjs_parser @@ -274,9 +319,8 @@ qjsc_exe = executable( qjsc_srcs, c_args: qjs_c_args, - link_with: qjs_libc ? [] : qjs_libc_lib, - dependencies: qjs_dep, - + link_with: [cutils_lib], + dependencies: [qjs_dep, qjs_libc_dep], install: true, ) @@ -300,8 +344,8 @@ qjs_exe = executable( qjs_exe_srcs, c_args: qjs_c_args, - link_with: qjs_libc ? [] : qjs_libc_lib, - dependencies: [qjs_dep, mimalloc_dep], + link_with: [cutils_lib], + dependencies: [qjs_dep, qjs_libc_dep, mimalloc_dep], export_dynamic: true, install: true, @@ -328,7 +372,7 @@ if meson.is_cross_build() qjs_libc_srcs, dependencies: qjs_sys_native_deps, - c_args: qjs_c_args, + c_args: [qjs_c_args, '-DQUICKJS_NG_QJS_INTERNAL'], gnu_symbol_visibility: 'hidden', build_by_default: false, @@ -381,10 +425,10 @@ if tests.allowed() run262_exe = executable( 'run-test262', 'run-test262.c', - qjs_libc_srcs, + link_with: cutils_lib, c_args: qjs_c_args, - dependencies: qjs_dep, + dependencies: [qjs_dep, qjs_libc_dep] ) test( @@ -484,6 +528,7 @@ if tests.allowed() 'api-test', 'api-test.c', + link_with: cutils_lib, c_args: qjs_c_args, dependencies: qjs_dep, build_by_default: false, @@ -496,10 +541,9 @@ if tests.allowed() executable( 'function_source', 'gen/function_source.c', - qjs_libc_srcs, c_args: qjs_c_args, - dependencies: qjs_dep, + dependencies: [qjs_dep, qjs_libc_dep], build_by_default: false, ), ) @@ -508,9 +552,9 @@ endif # Unicode generator unicode_gen = executable( 'unicode_gen', - 'cutils.c', 'unicode_gen.c', + link_with: cutils_lib, c_args: qjs_c_args, build_by_default: false, ) @@ -604,34 +648,38 @@ alias_target('codegen', ) if examples.allowed() + if host_system == 'windows' and get_option('default_library') != 'shared' + warning('Binary modules used with static qjs on Windows.') + warning( + 'There might be runtime errors when the modules are used due to', + 'two copies of qjs in memory.' + ) + warning('Please use "-Ddefault_library=shared" if possible.') + endif executable( 'hello', 'gen/hello.c', - qjs_libc_srcs, c_args: qjs_c_args, - dependencies: qjs_dep, + dependencies: [qjs_dep, qjs_libc_dep] ) executable( 'hello_module', 'gen/hello_module.c', - qjs_libc_srcs, c_args: qjs_c_args, - dependencies: qjs_dep, + dependencies: [qjs_dep, qjs_libc_dep] ) subdir('examples') executable( 'test_fib', - 'examples/fib.c', 'gen/test_fib.c', - qjs_libc_srcs, c_args: qjs_c_args, - dependencies: qjs_dep, + dependencies: [qjs_dep, qjs_libc_dep], export_dynamic: true, ) endif diff --git a/quickjs-libc.h b/quickjs-libc.h index abfd6c2c4..6cded280f 100644 --- a/quickjs-libc.h +++ b/quickjs-libc.h @@ -34,51 +34,43 @@ extern "C" { #endif -#if defined(__GNUC__) || defined(__clang__) -#define JS_EXTERN __attribute__((visibility("default"))) -#else -#define JS_EXTERN /* nothing */ -#endif - -JS_EXTERN JSModuleDef *js_init_module_std(JSContext *ctx, - const char *module_name); -JS_EXTERN JSModuleDef *js_init_module_os(JSContext *ctx, - const char *module_name); -JS_EXTERN JSModuleDef *js_init_module_bjson(JSContext *ctx, - const char *module_name); -JS_EXTERN void js_std_add_helpers(JSContext *ctx, int argc, char **argv); -JS_EXTERN int js_std_loop(JSContext *ctx); -JS_EXTERN int js_std_loop_once(JSContext *ctx); -JS_EXTERN int js_std_poll_io(JSContext *ctx, int timeout_ms); -JS_EXTERN JSValue js_std_await(JSContext *ctx, JSValue obj); -JS_EXTERN void js_std_init_handlers(JSRuntime *rt); -JS_EXTERN void js_std_free_handlers(JSRuntime *rt); -JS_EXTERN void js_std_dump_error(JSContext *ctx); -JS_EXTERN uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, - const char *filename); -JS_EXTERN int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, - bool use_realpath, bool is_main); -JS_EXTERN JSModuleDef *js_module_loader(JSContext *ctx, - const char *module_name, void *opaque, - JSValueConst attributes); -JS_EXTERN int js_module_check_attributes(JSContext *ctx, void *opaque, - JSValueConst attributes); -JS_EXTERN int js_module_test_json(JSContext *ctx, JSValueConst attributes); -JS_EXTERN void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, - size_t buf_len, int flags); -JS_EXTERN void js_std_promise_rejection_tracker(JSContext *ctx, - JSValueConst promise, - JSValueConst reason, - bool is_handled, - void *opaque); +JS_LIBC_EXTERN JSModuleDef *js_init_module_std(JSContext *ctx, + const char *module_name); +JS_LIBC_EXTERN JSModuleDef *js_init_module_os(JSContext *ctx, + const char *module_name); +JS_LIBC_EXTERN JSModuleDef *js_init_module_bjson(JSContext *ctx, + const char *module_name); +JS_LIBC_EXTERN void js_std_add_helpers(JSContext *ctx, int argc, char **argv); +JS_LIBC_EXTERN int js_std_loop(JSContext *ctx); +JS_LIBC_EXTERN int js_std_loop_once(JSContext *ctx); +JS_LIBC_EXTERN int js_std_poll_io(JSContext *ctx, int timeout_ms); +JS_LIBC_EXTERN JSValue js_std_await(JSContext *ctx, JSValue obj); +JS_LIBC_EXTERN void js_std_init_handlers(JSRuntime *rt); +JS_LIBC_EXTERN void js_std_free_handlers(JSRuntime *rt); +JS_LIBC_EXTERN void js_std_dump_error(JSContext *ctx); +JS_LIBC_EXTERN uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, + const char *filename); +JS_LIBC_EXTERN int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + bool use_realpath, bool is_main); +JS_LIBC_EXTERN JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque, + JSValueConst attributes); +JS_LIBC_EXTERN int js_module_check_attributes(JSContext *ctx, void *opaque, + JSValueConst attributes); +JS_LIBC_EXTERN int js_module_test_json(JSContext *ctx, JSValueConst attributes); +JS_LIBC_EXTERN void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, + size_t buf_len, int flags); +JS_LIBC_EXTERN void js_std_promise_rejection_tracker(JSContext *ctx, + JSValueConst promise, + JSValueConst reason, + bool is_handled, + void *opaque); // Defaults to JS_NewRuntime, no-op if compiled without worker support. // Call before creating the first worker thread. -JS_EXTERN void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void)); +JS_LIBC_EXTERN void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void)); // Defaults to JS_NewContext, no-op if compiled without worker support. // Call before creating the first worker thread. -JS_EXTERN void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); - -#undef JS_EXTERN +JS_LIBC_EXTERN void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); #ifdef __cplusplus } /* extern "C" { */ diff --git a/quickjs.h b/quickjs.h index d66051324..0a42abfe6 100644 --- a/quickjs.h +++ b/quickjs.h @@ -39,14 +39,100 @@ extern "C" { #define QUICKJS_NG 1 +/* Helpers. */ +#if defined(_WIN32) || defined(__CYGWIN__) +# define QUICKJS_NG_PLAT_WIN32 1 +#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + #if defined(__GNUC__) || defined(__clang__) -#define js_force_inline inline __attribute__((always_inline)) -#define JS_EXTERN __attribute__((visibility("default"))) +# define QUICKJS_NG_CC_GNULIKE 1 +#endif /* defined(__GNUC__) || defined(__clang__) */ + +/* + * `js_force_inline` -- helper macro forcing the inlining of a function. + */ +#ifdef QUICKJS_NG_PLAT_WIN32 +# ifdef QUICKJS_NG_CC_GNULIKE +# define js_force_inline inline __attribute__((always_inline)) +# else +# define js_force_inline __forceinline +# endif +#else +# ifdef QUICKJS_NG_CC_GNULIKE +# define js_force_inline inline __attribute__((always_inline)) +# else +# define js_force_inline inline +# endif +#endif /* QUICKJS_NG_PLAT_WIN32 */ + +/* + * `JS_EXTERN` -- helper macro that must be used to mark the external + * interfaces of libqjs. + * + * Define BUILDING_QJS_SHARED when building and USING_QJS_SHARED when using + * shared libqjs. + * + * Windows note: The `__declspec` syntax is supported by both Clang and GCC. + * The QUICKJS_NG_QJS_INTERNAL macro must be defined for libqjs (and only for + * it) to properly export symbols. + */ +#ifdef QUICKJS_NG_PLAT_WIN32 +# if defined(BUILDING_QJS_SHARED) +# define JS_EXTERN __declspec(dllexport) +# elif defined(USING_QJS_SHARED) +# define JS_EXTERN __declspec(dllimport) +# else +# define JS_EXTERN /* nothing */ +# endif +#else +# ifdef QUICKJS_NG_CC_GNULIKE +# define JS_EXTERN __attribute__((visibility("default"))) +# else +# define JS_EXTERN /* nothing */ +# endif +#endif /* QUICKJS_NG_PLAT_WIN32 */ + +/* + * `JS_LIBC_EXTERN` -- helper macro that must be used to mark the extern + * interfaces of quickjs-libc specifically. + */ +#if defined(QUICKJS_NG_BUILD) && !defined(QJS_BUILD_LIBC) && defined(QUICKJS_NG_PLAT_WIN32) +/* + * We are building QuickJS-NG, quickjs-libc is a static library and we are on + * Windows. Then, make sure to not export any interfaces. + */ +# define JS_LIBC_EXTERN /* nothing */ #else -#define js_force_inline inline -#define JS_EXTERN /* nothing */ +/* + * Otherwise, if we are either (1) not building QuickJS-NG, (2) libc is built as + * a part of libqjs, or (3) we are not on Windows, define JS_LIBC_EXTERN to + * JS_EXTERN. + */ +# define JS_LIBC_EXTERN JS_EXTERN #endif +/* + * `JS_MODULE_EXTERN` -- helper macro that must be used to mark `js_init_module` + * and other public functions of the binary modules. See examples/ for examples + * of the usage. + * + * Windows note: -DQUICKJS_NG_MODULE_BUILD must be set when building a binary + * module to properly set __declspec. + */ +#ifdef QUICKJS_NG_PLAT_WIN32 +# ifdef QUICKJS_NG_MODULE_BUILD +# define JS_MODULE_EXTERN __declspec(dllexport) +# else +# define JS_MODULE_EXTERN __declspec(dllimport) +# endif +#else +# ifdef QUICKJS_NG_CC_GNULIKE +# define JS_MODULE_EXTERN __attribute__((visibility("default"))) +# else +# define JS_MODULE_EXTERN /* nothing */ +# endif +#endif /* QUICKJS_NG_PLAT_WIN32 */ + /* Borrowed from Folly */ #ifndef JS_PRINTF_FORMAT #ifdef _MSC_VER @@ -65,6 +151,9 @@ extern "C" { #endif #endif +#undef QUICKJS_NG_CC_GNULIKE +#undef QUICKJS_NG_PLAT_WIN32 + typedef struct JSRuntime JSRuntime; typedef struct JSContext JSContext; typedef struct JSObject JSObject; @@ -1325,7 +1414,6 @@ JS_EXTERN const char* JS_GetVersion(void); /* Integration point for quickjs-libc.c, not for public use. */ JS_EXTERN uintptr_t js_std_cmd(int cmd, ...); -#undef JS_EXTERN #undef js_force_inline #ifdef __cplusplus