diff --git a/CMakeLists.txt b/CMakeLists.txt index 518a20e..da02493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,23 @@ if(QJS_LIB_TYPE STREQUAL "SHARED_LIBRARY") ) 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}) @@ -442,6 +459,15 @@ target_link_libraries(function_source PRIVATE qjs) # 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 ) @@ -461,35 +487,30 @@ if(QJS_BUILD_EXAMPLES) 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 PRIVATE 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 PRIVATE 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 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 b965acc..a9eb29d 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 08c9d87..08f0329 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 a82df15..baa0638 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 e664c61..ab25a5d 100644 --- a/meson.build +++ b/meson.build @@ -181,13 +181,6 @@ qjs_lib = library( qjs_srcs, qjs_libc ? qjs_libc_srcs : [], - # export public headers - generator( - find_program('cp', 'xcopy'), - output: ['@PLAINNAME@'], - arguments: ['@INPUT@', '@OUTPUT@'], - ).process(qjs_hdrs), - dependencies: qjs_sys_deps, link_with: cutils_lib, c_args: qjs_c_args, @@ -214,10 +207,23 @@ 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( @@ -643,6 +649,14 @@ 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', @@ -663,7 +677,6 @@ if examples.allowed() executable( 'test_fib', - 'examples/fib.c', 'gen/test_fib.c', c_args: qjs_c_args, diff --git a/quickjs.h b/quickjs.h index ad7662b..c208f0a 100644 --- a/quickjs.h +++ b/quickjs.h @@ -111,6 +111,28 @@ extern "C" { # 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