Skip to content

Commit ed7c94f

Browse files
committed
NativeScriptRuntime framework
1 parent f452bd1 commit ed7c94f

File tree

6 files changed

+219
-142
lines changed

6 files changed

+219
-142
lines changed

runtime/CMakeLists.txt

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,65 @@ include_directories(
1515
${CMAKE_CURRENT_SOURCE_DIR}/include
1616
)
1717

18-
set(EXEC_SOURCE_FILES
19-
src/main.cpp
18+
set(RT_SOURCE_FILES
2019
src/Console.cpp
2120
src/Runtime.cpp
2221
src/segappend.cpp
2322
src/Compiler.cpp
24-
src/Require.mm
23+
src/Require.cpp
2524
src/Performance.cpp
2625
)
2726

2827
add_executable(
2928
${NAME}
30-
${EXEC_SOURCE_FILES}
29+
src/main.cpp
30+
${RT_SOURCE_FILES}
31+
)
32+
33+
add_library(
34+
NativeScriptRuntime
35+
SHARED
36+
${RT_SOURCE_FILES}
37+
)
38+
39+
target_sources(
40+
NativeScriptRuntime
41+
PRIVATE
42+
"include/Console.h;include/Runtime.h;include/Compiler.h;include/Require.h;include/Performance.h"
43+
)
44+
45+
set_target_properties(NativeScriptRuntime PROPERTIES
46+
FRAMEWORK TRUE
47+
PUBLIC_HEADER "include/Console.h;include/Runtime.h;include/Compiler.h;include/Require.h;include/Performance.h"
3148
)
3249

3350
target_link_options(
34-
${NAME}
51+
NativeScriptRuntime
3552
PRIVATE
3653
-Wl,-F${CMAKE_CURRENT_SOURCE_DIR}/Frameworks,-rpath,${CMAKE_CURRENT_SOURCE_DIR}/Frameworks
3754
)
3855

3956
target_link_directories(
40-
${NAME}
57+
NativeScriptRuntime
4158
PRIVATE
4259
${CMAKE_CURRENT_SOURCE_DIR}/../packages/macos/build/macos/Release
4360
)
4461

4562
target_link_libraries(
46-
${NAME}
63+
NativeScriptRuntime
4764
PRIVATE
4865
NativeScript
4966
"-framework hermes"
5067
)
68+
69+
target_link_options(
70+
${NAME}
71+
PRIVATE
72+
-undefined dynamic_lookup
73+
)
74+
75+
target_link_libraries(
76+
${NAME}
77+
PRIVATE
78+
NativeScriptRuntime
79+
)

runtime/include/Require.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef REQUIRE_H
2+
#define REQUIRE_H
3+
4+
#include <string>
5+
#include "js_native_api.h"
6+
7+
class Require {
8+
public:
9+
Require(std::string path, std::string tilde) : path(path), tilde(tilde) {}
10+
11+
static void init(napi_env env, std::string &path, std::string &tilde);
12+
13+
static napi_value createRequire(napi_env env, std::string &path, std::string &tilde);
14+
15+
static void finalize(napi_env env, void *data, void *hint);
16+
17+
std::string resolve(std::string &spec);
18+
napi_value require(napi_env env, std::string &spec);
19+
20+
static napi_value requireCallback(napi_env env, napi_callback_info cbinfo);
21+
22+
std::string path;
23+
std::string tilde;
24+
};
25+
26+
#endif // REQUIRE_H

runtime/include/Runtime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Runtime {
1717

1818
std::unique_ptr<facebook::hermes::HermesRuntime> runtime;
1919
napi_env env;
20+
std::string mainPath;
2021
};
2122

2223
} // namespace charon

runtime/src/Require.cpp

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
#include "Require.h"
2+
#include "NapiUtil.h"
3+
#include "js_native_api.h"
4+
#include <iostream>
5+
#include <string>
6+
7+
napi_value Require::createRequire(napi_env env, std::string& path,
8+
std::string& tilde) {
9+
Require *require = new Require(path, tilde);
10+
napi_value result;
11+
napi_create_function(env, "require", NAPI_AUTO_LENGTH,
12+
Require::requireCallback, require, &result);
13+
napi_ref ref;
14+
napi_wrap(env, result, require, Require::finalize, nullptr, &ref);
15+
return result;
16+
}
17+
18+
void Require::init(napi_env env, std::string& path, std::string& tilde) {
19+
napi_value global;
20+
napi_get_global(env, &global);
21+
22+
napi_value require = createRequire(env, path, tilde);
23+
napi_set_named_property(env, global, "require", require);
24+
}
25+
26+
void Require::finalize(napi_env env, void *data, void *hint) {
27+
Require *require = (Require *)data;
28+
delete require;
29+
}
30+
31+
std::string Require::resolve(std::string &spec) {
32+
if (spec.find("/") == 0) {
33+
return spec;
34+
}
35+
36+
size_t dotpos = spec.find(".");
37+
size_t tildepos = spec.find("~");
38+
std::string result;
39+
if (tildepos == 0) {
40+
result = tilde;
41+
result += "/app";
42+
} else {
43+
result = path;
44+
}
45+
46+
if (dotpos == 0 || tildepos == 0) {
47+
std::string relativeSpec =
48+
spec.substr(spec.find("./") == 0 || spec.find("~/") == 0 ? 2 : 1);
49+
if (relativeSpec.empty()) {
50+
result += "/index.js";
51+
} else {
52+
result += "/" + relativeSpec;
53+
}
54+
} else {
55+
result += "/" + spec;
56+
}
57+
58+
size_t pos = result.rfind("/");
59+
size_t jspos = result.find(".js");
60+
if (jspos < pos || jspos == std::string::npos) {
61+
result += result.ends_with("/") ? "index.js" : "/index.js";
62+
}
63+
64+
return result;
65+
}
66+
67+
napi_value Require::require(napi_env env, std::string &spec) {
68+
std::string path = resolve(spec);
69+
70+
char *source = nullptr;
71+
size_t size = 0;
72+
FILE *file = fopen(path.c_str(), "r");
73+
if (file) {
74+
fseek(file, 0, SEEK_END);
75+
size = ftell(file);
76+
fseek(file, 0, SEEK_SET);
77+
source = (char *)malloc(size + 1);
78+
fread(source, 1, size, file);
79+
source[size] = 0;
80+
fclose(file);
81+
} else {
82+
std::cerr << "error in open file: " << path << std::endl;
83+
return nullptr;
84+
}
85+
86+
if (spec.ends_with(".json")) {
87+
napi_value script, result;
88+
napi_create_string_utf8(env, source, NAPI_AUTO_LENGTH, &script);
89+
napi_run_script(env, script, &result);
90+
return result;
91+
}
92+
93+
std::string bootstrap;
94+
bootstrap = "let cjsModule; try { cjsModule = function c(exports, "
95+
"require, module, __filename, __dirname) {";
96+
bootstrap += source;
97+
bootstrap +=
98+
"\n};\n"
99+
"Object.defineProperty(cjsModule, \"name\", { value: `" +
100+
path + "` });\n} catch (e) { throw new Error(`Failed to evaluate module: ${e.stack}`); }\n cjsModule";
101+
102+
napi_status status;
103+
napi_value func, script, module, exports, require, __filename, __dirname,
104+
global, result;
105+
106+
napi_create_string_utf8(env, bootstrap.c_str(), NAPI_AUTO_LENGTH, &script);
107+
108+
status = napi_run_script(env, script, &func);
109+
if (status != napi_ok) {
110+
const napi_extended_error_info *info;
111+
napi_get_last_error_info(env, &info);
112+
std::cerr << "error in run script: " << status << ", "
113+
<< info->error_message << std::endl;
114+
return nullptr;
115+
}
116+
117+
napi_create_object(env, &module);
118+
napi_create_object(env, &exports);
119+
120+
napi_set_named_property(env, module, "exports", exports);
121+
122+
napi_get_global(env, &global);
123+
124+
napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &__filename);
125+
126+
std::string dirname = path.substr(0, path.rfind("/"));
127+
128+
require = Require::createRequire(env, dirname, tilde);
129+
130+
napi_create_string_utf8(env, dirname.c_str(), NAPI_AUTO_LENGTH, &__dirname);
131+
132+
napi_value argv[5] = {exports, require, module, __filename, __dirname};
133+
134+
status = napi_call_function(env, global, func, 5, argv, &result);
135+
if (status != napi_ok) {
136+
const napi_extended_error_info *info;
137+
napi_get_last_error_info(env, &info);
138+
std::cerr << "error in evaluate module: " << status << ", "
139+
<< info->error_message << std::endl;
140+
return nullptr;
141+
}
142+
143+
napi_get_named_property(env, module, "exports", &exports);
144+
return exports;
145+
}
146+
147+
napi_value Require::requireCallback(napi_env env, napi_callback_info cbinfo) {
148+
napi_value arg;
149+
Require *require;
150+
size_t argc = 1;
151+
napi_get_cb_info(env, cbinfo, &argc, &arg, nullptr, (void **)&require);
152+
std::string spec = getStringValue(env, arg);
153+
return require->require(env, spec);
154+
}

runtime/src/Require.mm

Lines changed: 0 additions & 135 deletions
This file was deleted.

0 commit comments

Comments
 (0)