Skip to content
Permalink
Browse files

Fixed N-API support on Windows (#1875)

IoT.js-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com
  • Loading branch information...
László Langó authored and yichoi committed May 15, 2019
1 parent b601aa7 commit a9f714ec6b9aeb5583e5efc1c8b1cc7845528ece
@@ -0,0 +1,19 @@
# Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x64)

set(CMAKE_C_COMPILER CL.exe)
set(CMAKE_C_COMPILER_WORKS TRUE)
@@ -504,16 +504,28 @@ else()

# FIXME: module specific condition should not be in the main cmake
if(${ENABLE_MODULE_NAPI})
# Some tests require the GC to be exposed
iotjs_add_compile_flags(-DEXPOSE_GC)

# Force symbols to be entered in the output file as undefined symbols.
file(READ "${IOTJS_SOURCE_DIR}/napi/node_symbols.txt" NODE_SYMBOLS)
string(REGEX REPLACE "[\r|\n]" ";" NODE_SYMBOLS "${NODE_SYMBOLS}")
set(NODE_SYMBOLS_LINK_FLAGS "-Wl")
# Some tests require the GC to be exposed
iotjs_add_compile_flags(-DEXPOSE_GC)

if(USING_MSVC)
set(NODE_SYMBOL_SEPARATOR " /INCLUDE:")
if("${TARGET_ARCH}" STREQUAL "i686")
set(NODE_SYMBOL_SEPARATOR "${NODE_SYMBOL_SEPARATOR}_")
endif()
else()
set(NODE_SYMBOLS_LINK_FLAGS "-Wl")
set(NODE_SYMBOL_SEPARATOR ",-u,")
endif()

foreach(NODE_SYMBOL ${NODE_SYMBOLS})
set(NODE_SYMBOLS_LINK_FLAGS
"${NODE_SYMBOLS_LINK_FLAGS},-u,${NODE_SYMBOL}")
"${NODE_SYMBOLS_LINK_FLAGS}${NODE_SYMBOL_SEPARATOR}${NODE_SYMBOL}")
endforeach()

iotjs_add_link_flags(${NODE_SYMBOLS_LINK_FLAGS})
endif()
endif(CREATE_SHARED_LIB)
@@ -23,7 +23,6 @@
#include "internal/node_api_internal_types.h"
#include "node_api.h"

#define GET_3TH_ARG(arg1, arg2, arg3, ...) arg3
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4

#define AS_JERRY_VALUE(nvalue) (jerry_value_t)(uintptr_t) nvalue
@@ -43,63 +42,47 @@
return status; \
} while (0)

#define NAPI_RETURN_NO_MSG(status) \
#define NAPI_RETURN(status) \
do { \
iotjs_napi_set_error_info(iotjs_get_current_napi_env(), status, NULL, 0, \
NULL); \
return status; \
} while (0)

#define NAPI_RETURN_MACRO_CHOOSER(...) \
GET_3TH_ARG(__VA_ARGS__, NAPI_RETURN_WITH_MSG, NAPI_RETURN_NO_MSG, )

#define NAPI_RETURN(...) NAPI_RETURN_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
/** MARK: - END N-API Returns */

/** MARK: - N-API Asserts */
/**
* A weak assertion, which don't crash the program on failed assertion
* rather returning a napi error code back to caller.
*/
#define NAPI_WEAK_ASSERT_NO_MSG(error_t, assertion) \
do { \
if (!(assertion)) \
NAPI_RETURN(error_t, "Assertion (" #assertion ") failed"); \
#define NAPI_WEAK_ASSERT(error_t, assertion) \
do { \
if (!(assertion)) \
NAPI_RETURN_WITH_MSG(error_t, "Assertion (" #assertion ") failed"); \
} while (0)

#define NAPI_WEAK_ASSERT_MSG(error_t, assertion, message) \
do { \
if (!(assertion)) \
NAPI_RETURN(error_t, message); \
#define NAPI_WEAK_ASSERT_WITH_MSG(error_t, assertion, message) \
do { \
if (!(assertion)) \
NAPI_RETURN_WITH_MSG(error_t, message); \
} while (0)

#define NAPI_WEAK_ASSERT_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, NAPI_WEAK_ASSERT_MSG, NAPI_WEAK_ASSERT_NO_MSG, )

/**
* NAPI_WEAK_ASSERT
* - error_t: napi status code
* - assertion: assertion expression
* - message: (optional) an optional message about the assertion error
*/
#define NAPI_WEAK_ASSERT(...) \
NAPI_WEAK_ASSERT_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)

/**
* A convenience weak assertion on jerry value type.
*/
#define NAPI_TRY_TYPE(type, jval) \
NAPI_WEAK_ASSERT(napi_##type##_expected, jerry_value_is_##type(jval), \
#type " was expected")
#define NAPI_TRY_TYPE(type, jval) \
NAPI_WEAK_ASSERT_WITH_MSG(napi_##type##_expected, \
jerry_value_is_##type(jval), \
#type " was expected")

/**
* A convenience weak assertion on N-API Env matching.
*/
#define NAPI_TRY_ENV(env) \
do { \
if (napi_try_env_helper(env)) { \
NAPI_RETURN(napi_invalid_arg, "N-API env not match."); \
} \
#define NAPI_TRY_ENV(env) \
do { \
if (napi_try_env_helper(env)) { \
NAPI_RETURN_WITH_MSG(napi_invalid_arg, "N-API env not match."); \
} \
} while (0)

/**
@@ -145,7 +128,7 @@ int napi_module_init_pending(jerry_value_t* exports);
/** MARK: - END node_api_module.c */

/** MARK: - node_api_env.c */
napi_env iotjs_get_current_napi_env();
napi_env iotjs_get_current_napi_env(void);
bool napi_try_env_helper(napi_env env);
void iotjs_napi_set_current_callback(napi_env env,
iotjs_callback_info_t* callback_info);
@@ -168,8 +151,8 @@ iotjs_object_info_t* iotjs_get_object_native_info(jerry_value_t jval,
size_t native_info_size);
iotjs_object_info_t* iotjs_try_get_object_native_info(jerry_value_t jval,
size_t native_info_size);
void iotjs_setup_napi();
void iotjs_cleanup_napi();
void iotjs_setup_napi(void);
void iotjs_cleanup_napi(void);
/** MARK: - END node_api_lifetime.c */

napi_status napi_assign_bool(bool value, bool* result);
@@ -21,8 +21,6 @@
#include <uv.h>
#include "node_api.h"

typedef napi_value (*jerry_addon_register_func)(void* env,
jerry_value_t exports);
typedef void (*iotjs_cleanup_hook_fn)(void* arg);

typedef struct iotjs_async_context_s iotjs_async_context_t;
@@ -72,11 +70,11 @@ struct iotjs_reference_s {
iotjs_reference_t* ref_end;

struct iotjs_object_info_s {
IOTJS_OBJECT_INFO_FIELDS;
IOTJS_OBJECT_INFO_FIELDS
};

struct iotjs_function_info_s {
IOTJS_OBJECT_INFO_FIELDS;
IOTJS_OBJECT_INFO_FIELDS

napi_callback cb;
void* data;
@@ -183,6 +183,7 @@ void iotjs_run(iotjs_environment_t* env) {
bool throw_exception = !iotjs_environment_is_exiting(env);
#ifdef JERRY_DEBUGGER
throw_exception = throw_exception &&
iotjs_environment_config(env)->debugger &&
!iotjs_environment_config(env)->debugger->context_reset;
#endif
if (throw_exception) {
@@ -115,7 +115,8 @@ void iotjs_buffer_release(char* buffer) {
}

void print_stacktrace(void) {
#if defined(__linux__) && defined(DEBUG) && !defined(__OPENWRT__)
#if !defined(NDEBUG) && defined(__linux__) && defined(DEBUG) && \
!defined(__OPENWRT__)
// TODO: support other platforms
const int numOfStackTrace = 100;
void* buffer[numOfStackTrace];
@@ -147,7 +148,8 @@ void print_stacktrace(void) {
}

free(strings);
#endif // defined(__linux__) && defined(DEBUG) && !defined(__OPENWRT__)
#endif // !defined(NDEBUG) && defined(__linux__) && defined(DEBUG) &&
// !defined(__OPENWRT__)
}

void force_terminate(void) {
@@ -29,6 +29,8 @@ char* iotjs_buffer_allocate_from_number_array(size_t size,
char* iotjs_buffer_reallocate(char* buffer, size_t size);
void iotjs_buffer_release(char* buff);

void print_stacktrace(void);

#define IOTJS_ALLOC(type) /* Allocate (type)-sized, (type*)-typed memory */ \
(type*)iotjs_buffer_allocate(sizeof(type))

@@ -52,10 +52,14 @@ if (process.platform === 'windows') {
* replace all '\' characters to '/' for ease of use for now.
*/
path = {
pathReplacer: new RegExp('\\\\', 'g'),
unixPathReplacer: new RegExp('/', 'g'),
winPathReplacer: new RegExp('\\\\', 'g'),
pathSeparator: '\\',
normalizeSeparators: function(pathString) {
return pathString.replace(path.pathReplacer, '/');
toUnixPath: function(pathString) {
return pathString.replace(path.winPathReplacer, '/');
},
toWindowsPath: function(pathString) {
return pathString.replace(path.unixPathReplacer, '\\\\');
},
isDeviceRoot: function(pathString) {
if (pathString.charCodeAt(1) !== 0x3A /* ':' */) {
@@ -66,7 +70,7 @@ if (process.platform === 'windows') {
|| (drive >= 0x41 /* A */ && drive <= 0x5A /* Z */);
},
normalizePath: function(pathString) {
pathString = path.normalizeSeparators(pathString);
pathString = path.toUnixPath(pathString);

var deviceRoot = '';
if (!path.isDeviceRoot(pathString)) {
@@ -77,7 +81,7 @@ if (process.platform === 'windows') {
return deviceRoot + pathElements.join('/');
},
cwd: function() {
return path.normalizeSeparators(process.cwd());
return path.toUnixPath(process.cwd());
},
};
} else {
@@ -275,7 +279,11 @@ Module.load = function(id, parent) {
source = Builtin.readSource(modPath);
module.exports = JSON.parse(source);
} else if (dynamicloader && ext === 'node') {
module.exports = dynamicloader(modPath);
if (process.platform === 'windows') {
module.exports = dynamicloader(path.toWindowsPath(modPath));
} else {
module.exports = dynamicloader(modPath);
}
}

Module.cache[modPath] = module;
@@ -253,8 +253,7 @@
"napi/node_api_object_wrap.c",
"napi/node_api_property.c",
"napi/node_api_value.c"],
"init": "InitDynamicloader",
"external_libs": ["dl"]
"init": "InitDynamicloader"
},
"net": {
"js_file": "js/net.js",
@@ -17,56 +17,71 @@

#include "iotjs_def.h"

#if _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdlib.h>

JS_FUNCTION(OpenNativeModule) {
iotjs_string_t location = JS_GET_ARG(0, string);

#if _WIN32
// Get a handle to the node module.
HINSTANCE handle = LoadLibrary(iotjs_string_data(&location));
#else
void* handle = dlopen(iotjs_string_data(&location), RTLD_LAZY);
#endif
iotjs_string_destroy(&location);

// If the handle is valid, try to get the function address.
if (handle == NULL) {
#if _WIN32
char* err_msg = "";
DWORD dw = GetLastError();

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_msg,
0, NULL);
#else
char* err_msg = dlerror();
#endif
jerry_value_t jval_error =
jerry_create_error(JERRY_ERROR_COMMON, (jerry_char_t*)err_msg);
return jval_error;
}

jerry_value_t exports;
jerry_value_t exports = jerry_create_undefined();

int status = napi_module_init_pending(&exports);
if (status == napi_module_load_ok) {
return exports;
}

if (status == napi_pending_exception) {
/** exports is an error reference */
/* exports is an error reference */
#if _WIN32
FreeLibrary(handle);
#else
dlclose(handle);
#endif
return exports;
}

if (status == napi_module_no_nm_register_func) {
#if _WIN32
FreeLibrary(handle);
#else
dlclose(handle);
#endif
jerry_value_t jval_error = jerry_create_error(
JERRY_ERROR_COMMON,
(jerry_char_t*)"Module has no declared entry point.");
return jval_error;
}

void (*init_fn)(jerry_value_t);
init_fn = dlsym(handle, "iotjs_module_register");
// check for dlsym
if (init_fn == NULL) {
char* err_msg = dlerror();
dlclose(handle);
char* msg_tpl = "dlopen(%s)";
char msg[strlen(err_msg) + 8];
sprintf(msg, msg_tpl, err_msg);

jerry_value_t jval_error =
jerry_create_error(JERRY_ERROR_COMMON, (jerry_char_t*)msg);
return jval_error;
}

exports = jerry_create_object();
(*init_fn)(exports);
return exports;
}

@@ -25,11 +25,13 @@ static napi_node_version node_version = {

napi_status napi_get_node_version(napi_env env,
const napi_node_version** version) {
NAPI_TRY_ENV(env);
NAPI_ASSIGN(version, &node_version);
NAPI_RETURN(napi_ok);
}

napi_status napi_get_version(napi_env env, uint32_t* result) {
NAPI_TRY_ENV(env);
NAPI_ASSIGN(result, NAPI_VERSION);
NAPI_RETURN(napi_ok);
}

0 comments on commit a9f714e

Please sign in to comment.
You can’t perform that action at this time.