Skip to content

Use suffix .dylib for MacOS native modules #1107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,10 @@ if(QJS_BUILD_EXAMPLES)
target_compile_definitions(hello_module PRIVATE ${qjs_defines})
target_link_libraries(hello_module qjs)

add_library(fib MODULE examples/fib.c)
add_library(fib SHARED examples/fib.c)
set_target_properties(fib PROPERTIES
PREFIX ""
SUFFIX ".qjs"
C_VISIBILITY_PRESET default
)
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
Expand All @@ -391,8 +392,9 @@ if(QJS_BUILD_EXAMPLES)
target_link_options(fib PRIVATE -undefined dynamic_lookup)
endif()

add_library(point MODULE examples/point.c)
add_library(point SHARED examples/point.c)
set_target_properties(point PROPERTIES
OUTPUT_NAME "point.qjs"
PREFIX ""
C_VISIBILITY_PRESET default
)
Expand Down
4 changes: 1 addition & 3 deletions examples/test_fib.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* example of JS module importing a C module */
import * as os from "qjs:os";

const isWin = os.platform === 'win32';
const { fib } = await import(`./fib.${isWin ? 'dll' : 'so'}`);
const { fib } = await import(`./fib.qjs`);

console.log("Hello World");
console.log("fib(10)=", fib(10));
8 changes: 5 additions & 3 deletions examples/test_point.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
/* example of JS module importing a C module */
import * as os from "qjs:os";

const isWin = os.platform === 'win32';
const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`);
// This should look for:
// - point.qjs.dll on Win32,
// - point.qjs.so on Linux,
// - point.qjs.dylib on macOS
const { Point } = await import(`./point.qjs`);

function assert(b, str)
{
Expand Down
104 changes: 87 additions & 17 deletions quickjs-libc.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,15 @@ extern char **environ;
#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)
#endif

#ifndef QJS_NATIVE_MODULE_SUFFIX
#define QJS_NATIVE_MODULE_COMMON_SUFFIX ".qjs" // Common suffix

#ifndef QJS_NATIVE_MODULE_PLATFORM_SUFFIX
#ifdef _WIN32
#define QJS_NATIVE_MODULE_SUFFIX ".dll"
#define QJS_NATIVE_MODULE_PLATFORM_SUFFIX ".dll"
#elif defined(__APPLE__)
#define QJS_NATIVE_MODULE_PLATFORM_SUFFIX ".dylib"
#else
#define QJS_NATIVE_MODULE_SUFFIX ".so"
#define QJS_NATIVE_MODULE_PLATFORM_SUFFIX ".so"
#endif
#endif

Expand Down Expand Up @@ -622,29 +626,60 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,


#if defined(_WIN32)
static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
static HINSTANCE js_module_loader_open(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
HINSTANCE hd;
JSInitModuleFunc *init;
char *filename = NULL;
char *filename;
size_t len = strlen(module_name);

bool is_absolute = len > 2 && ((module_name[0] >= 'A' && module_name[0] <= 'Z') ||
(module_name[0] >= 'a' && module_name[0] <= 'z')) && module_name[1] == ':';
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);
filename = js_malloc(ctx,
len + 2 + sizeof(QJS_NATIVE_MODULE_PLATFORM_SUFFIX) + 1);
if (!filename)
return NULL;
strcpy(filename, "./");
strcpy(filename + 2, module_name);
len += 2;
}
hd = LoadLibraryA(filename);
if (!hd) {
// Try to add the platform suffix to the file name
if (filename == module_name) {
// Allocate new filename
filename = js_malloc(ctx, len + sizeof(QJS_NATIVE_MODULE_PLATFORM_SUFFIX));
if (!filename)
return NULL;
strcpy(filename, module_name);
}

strcpy(filename + len, QJS_NATIVE_MODULE_PLATFORM_SUFFIX);
hd = LoadLibraryA(filename);
}

if (filename != module_name)
js_free(ctx, filename);

return hd;
}

static void js_module_loader_close(HINSTANCE hd)
{
FreeLibrary(hd);
}

static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
{
JSModuleDef *m;
HINSTANCE hd;
JSInitModuleFunc *init;

hd = js_module_loader_open(ctx, module_name);
if (hd == NULL) {
JS_ThrowReferenceError(ctx, "js_load_module '%s' error: %lu",
module_name, GetLastError());
Expand All @@ -662,7 +697,7 @@ static JSModuleDef *js_module_loader_so(JSContext *ctx,
module_name);
fail:
if (hd != NULL)
FreeLibrary(hd);
js_module_loader_close(hd);
return NULL;
}
return m;
Expand All @@ -675,30 +710,63 @@ static JSModuleDef *js_module_loader_so(JSContext *ctx,
return NULL;
}
#else
static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
static void *js_module_loader_open(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
void *hd;
JSInitModuleFunc *init;
char *filename;
size_t len = strlen(module_name);

// Process the module name then store the processed value to filename
if (!strchr(module_name, '/')) {
/* must add a '/' so that the DLL is not searched in the
system library paths */
filename = js_malloc(ctx, strlen(module_name) + 2 + 1);
filename = js_malloc(ctx,
len + 2 + sizeof(QJS_NATIVE_MODULE_PLATFORM_SUFFIX) + 1);
if (!filename)
return NULL;
strcpy(filename, "./");
strcpy(filename + 2, module_name);
len += 2;
} else {
filename = (char *)module_name;
}

/* C module */
hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
if (!hd) {
// Try to add the platform suffix to the file name
if (filename == module_name) {
// Allocate new filename
filename = js_malloc(ctx, len + sizeof(QJS_NATIVE_MODULE_PLATFORM_SUFFIX));
if (!filename)
return NULL;
strcpy(filename, module_name);
}

strcpy(filename + len, QJS_NATIVE_MODULE_PLATFORM_SUFFIX);
hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
}

if (filename != module_name)
js_free(ctx, filename);

return hd;
}

static void js_module_loader_close(void *hd)
{
dlclose(hd);
}

static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
{
JSModuleDef *m;
void *hd;
JSInitModuleFunc *init;

/* C module */
hd = js_module_loader_open(ctx, module_name);
if (!hd) {
JS_ThrowReferenceError(ctx, "could not load module filename '%s' as shared library: %s",
module_name, dlerror());
Expand All @@ -718,7 +786,7 @@ static JSModuleDef *js_module_loader_so(JSContext *ctx,
module_name);
fail:
if (hd)
dlclose(hd);
js_module_loader_close(hd);
return NULL;
}
return m;
Expand Down Expand Up @@ -783,7 +851,9 @@ JSModuleDef *js_module_loader(JSContext *ctx,
{
JSModuleDef *m;

if (js__has_suffix(module_name, QJS_NATIVE_MODULE_SUFFIX)) {
if (js__has_suffix(module_name, QJS_NATIVE_MODULE_PLATFORM_SUFFIX) ||
js__has_suffix(module_name, QJS_NATIVE_MODULE_COMMON_SUFFIX))
{
m = js_module_loader_so(ctx, module_name);
} else {
size_t buf_len;
Expand Down