@tishlang/tish-format 1.0.12 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +51 -0
- package/LICENSE +13 -0
- package/bin/tish-format +0 -0
- package/crates/js_to_tish/Cargo.toml +11 -0
- package/crates/js_to_tish/README.md +18 -0
- package/crates/js_to_tish/src/error.rs +55 -0
- package/crates/js_to_tish/src/lib.rs +11 -0
- package/crates/js_to_tish/src/span_util.rs +35 -0
- package/crates/js_to_tish/src/transform/expr.rs +611 -0
- package/crates/js_to_tish/src/transform/stmt.rs +503 -0
- package/crates/js_to_tish/src/transform.rs +60 -0
- package/crates/tish/Cargo.toml +62 -0
- package/crates/tish/build.rs +21 -0
- package/crates/tish/src/cargo_native_registry.rs +32 -0
- package/crates/tish/src/cli_help.rs +576 -0
- package/crates/tish/src/main.rs +853 -0
- package/crates/tish/src/repl_completion.rs +199 -0
- package/crates/tish/tests/cargo_example_compile.rs +67 -0
- package/crates/tish/tests/error_source_location.rs +36 -0
- package/crates/tish/tests/fixtures/cargo_example_project/Cargo.toml +3 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/Cargo.toml +11 -0
- package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +12 -0
- package/crates/tish/tests/fixtures/cargo_example_project/package.json +10 -0
- package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +3 -0
- package/crates/tish/tests/fixtures/runtime_error_location.tish +5 -0
- package/crates/tish/tests/fixtures/trycatch_runtime_errors.tish +15 -0
- package/crates/tish/tests/fixtures/tty_capability.tish +9 -0
- package/crates/tish/tests/integration_test.rs +1406 -0
- package/crates/tish/tests/run_optimize_stdout_parity.rs +50 -0
- package/crates/tish/tests/shortcircuit.rs +65 -0
- package/crates/tish/tests/trycatch_runtime_errors.rs +45 -0
- package/crates/tish/tests/tty_capability.rs +43 -0
- package/crates/tish_ast/Cargo.toml +9 -0
- package/crates/tish_ast/src/ast.rs +649 -0
- package/crates/tish_ast/src/lib.rs +5 -0
- package/crates/tish_build_utils/Cargo.toml +11 -0
- package/crates/tish_build_utils/src/lib.rs +577 -0
- package/crates/tish_builtins/Cargo.toml +22 -0
- package/crates/tish_builtins/src/array.rs +803 -0
- package/crates/tish_builtins/src/collections.rs +481 -0
- package/crates/tish_builtins/src/construct.rs +199 -0
- package/crates/tish_builtins/src/date.rs +538 -0
- package/crates/tish_builtins/src/globals.rs +293 -0
- package/crates/tish_builtins/src/helpers.rs +35 -0
- package/crates/tish_builtins/src/iterator.rs +129 -0
- package/crates/tish_builtins/src/lib.rs +21 -0
- package/crates/tish_builtins/src/math.rs +89 -0
- package/crates/tish_builtins/src/number.rs +96 -0
- package/crates/tish_builtins/src/object.rs +36 -0
- package/crates/tish_builtins/src/string.rs +646 -0
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_builtins/src/typedarrays.rs +298 -0
- package/crates/tish_bytecode/Cargo.toml +17 -0
- package/crates/tish_bytecode/src/chunk.rs +164 -0
- package/crates/tish_bytecode/src/compiler.rs +2604 -0
- package/crates/tish_bytecode/src/encoding.rs +102 -0
- package/crates/tish_bytecode/src/lib.rs +20 -0
- package/crates/tish_bytecode/src/opcode.rs +185 -0
- package/crates/tish_bytecode/src/peephole.rs +189 -0
- package/crates/tish_bytecode/src/serialize.rs +193 -0
- package/crates/tish_bytecode/tests/break_continue_bytecode.rs +44 -0
- package/crates/tish_bytecode/tests/constant_folding.rs +84 -0
- package/crates/tish_bytecode/tests/sort_optimization.rs +31 -0
- package/crates/tish_compile/Cargo.toml +27 -0
- package/crates/tish_compile/src/check.rs +774 -0
- package/crates/tish_compile/src/codegen.rs +7317 -0
- package/crates/tish_compile/src/infer.rs +1681 -0
- package/crates/tish_compile/src/lib.rs +206 -0
- package/crates/tish_compile/src/resolve.rs +1951 -0
- package/crates/tish_compile/src/types.rs +605 -0
- package/crates/tish_compile_js/Cargo.toml +18 -0
- package/crates/tish_compile_js/examples/jsx_vdom_smoke.tish +8 -0
- package/crates/tish_compile_js/src/codegen.rs +938 -0
- package/crates/tish_compile_js/src/error.rs +20 -0
- package/crates/tish_compile_js/src/lib.rs +26 -0
- package/crates/tish_compile_js/src/tests_jsx.rs +414 -0
- package/crates/tish_compiler_wasm/Cargo.toml +21 -0
- package/crates/tish_compiler_wasm/src/lib.rs +57 -0
- package/crates/tish_compiler_wasm/src/resolve_virtual.rs +473 -0
- package/crates/tish_core/Cargo.toml +32 -0
- package/crates/tish_core/src/console_style.rs +170 -0
- package/crates/tish_core/src/json.rs +430 -0
- package/crates/tish_core/src/lib.rs +20 -0
- package/crates/tish_core/src/macros.rs +36 -0
- package/crates/tish_core/src/shape.rs +85 -0
- package/crates/tish_core/src/uri.rs +118 -0
- package/crates/tish_core/src/value.rs +1350 -0
- package/crates/tish_core/src/vmref.rs +183 -0
- package/crates/tish_cranelift/Cargo.toml +19 -0
- package/crates/tish_cranelift/src/lib.rs +43 -0
- package/crates/tish_cranelift/src/link.rs +130 -0
- package/crates/tish_cranelift/src/lower.rs +85 -0
- package/crates/tish_cranelift_runtime/Cargo.toml +26 -0
- package/crates/tish_cranelift_runtime/src/lib.rs +45 -0
- package/crates/tish_eval/Cargo.toml +51 -0
- package/crates/tish_eval/src/eval.rs +4265 -0
- package/crates/tish_eval/src/http.rs +191 -0
- package/crates/tish_eval/src/lib.rs +99 -0
- package/crates/tish_eval/src/natives.rs +551 -0
- package/crates/tish_eval/src/promise.rs +179 -0
- package/crates/tish_eval/src/regex.rs +299 -0
- package/crates/tish_eval/src/timers.rs +120 -0
- package/crates/tish_eval/src/value.rs +336 -0
- package/crates/tish_eval/src/value_convert.rs +117 -0
- package/crates/tish_ffi/Cargo.toml +26 -0
- package/crates/tish_ffi/src/lib.rs +518 -0
- package/crates/tish_ffi/tests/fixtures/testmod/Cargo.toml +18 -0
- package/crates/tish_ffi/tests/fixtures/testmod/src/lib.rs +46 -0
- package/crates/tish_ffi/tests/loader.rs +65 -0
- package/crates/tish_fmt/Cargo.toml +16 -0
- package/crates/tish_fmt/src/bin/tish-fmt.rs +41 -0
- package/crates/tish_fmt/src/lib.rs +2157 -0
- package/crates/tish_jsx_web/Cargo.toml +9 -0
- package/crates/tish_jsx_web/README.md +5 -0
- package/crates/tish_jsx_web/src/lib.rs +2 -0
- package/crates/tish_lexer/Cargo.toml +9 -0
- package/crates/tish_lexer/src/lib.rs +1104 -0
- package/crates/tish_lexer/src/token.rs +170 -0
- package/crates/tish_lint/Cargo.toml +18 -0
- package/crates/tish_lint/src/bin/tish-lint.rs +195 -0
- package/crates/tish_lint/src/lib.rs +281 -0
- package/crates/tish_llvm/Cargo.toml +13 -0
- package/crates/tish_llvm/src/lib.rs +115 -0
- package/crates/tish_lsp/Cargo.toml +25 -0
- package/crates/tish_lsp/README.md +26 -0
- package/crates/tish_lsp/src/builtin_goto.rs +362 -0
- package/crates/tish_lsp/src/import_goto.rs +564 -0
- package/crates/tish_lsp/src/main.rs +1459 -0
- package/crates/tish_native/Cargo.toml +16 -0
- package/crates/tish_native/src/build.rs +481 -0
- package/crates/tish_native/src/config.rs +48 -0
- package/crates/tish_native/src/lib.rs +416 -0
- package/crates/tish_opt/Cargo.toml +13 -0
- package/crates/tish_opt/src/lib.rs +1046 -0
- package/crates/tish_parser/Cargo.toml +11 -0
- package/crates/tish_parser/src/lib.rs +386 -0
- package/crates/tish_parser/src/parser.rs +2726 -0
- package/crates/tish_pg/Cargo.toml +34 -0
- package/crates/tish_pg/README.md +38 -0
- package/crates/tish_pg/src/error.rs +52 -0
- package/crates/tish_pg/src/lib.rs +955 -0
- package/crates/tish_resolve/Cargo.toml +13 -0
- package/crates/tish_resolve/src/lib.rs +3601 -0
- package/crates/tish_resolve/src/pos.rs +141 -0
- package/crates/tish_runtime/Cargo.toml +100 -0
- package/crates/tish_runtime/src/http.rs +1347 -0
- package/crates/tish_runtime/src/http_fetch.rs +492 -0
- package/crates/tish_runtime/src/http_hyper.rs +441 -0
- package/crates/tish_runtime/src/http_prefork.rs +189 -0
- package/crates/tish_runtime/src/lib.rs +1447 -0
- package/crates/tish_runtime/src/native_promise.rs +15 -0
- package/crates/tish_runtime/src/promise.rs +558 -0
- package/crates/tish_runtime/src/promise_io.rs +38 -0
- package/crates/tish_runtime/src/timers.rs +172 -0
- package/crates/tish_runtime/src/tty.rs +226 -0
- package/crates/tish_runtime/src/ws.rs +778 -0
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +102 -0
- package/crates/tish_ui/Cargo.toml +17 -0
- package/crates/tish_ui/src/jsx.rs +692 -0
- package/crates/tish_ui/src/lib.rs +20 -0
- package/crates/tish_ui/src/runtime/hooks.rs +573 -0
- package/crates/tish_ui/src/runtime/mod.rs +183 -0
- package/crates/tish_vm/Cargo.toml +60 -0
- package/crates/tish_vm/src/jit.rs +1050 -0
- package/crates/tish_vm/src/lib.rs +41 -0
- package/crates/tish_vm/src/vm.rs +3536 -0
- package/crates/tish_vm/tests/concurrent_shared_state.rs +140 -0
- package/crates/tish_vm/tests/fixtures/or_string_cmd.tish +2 -0
- package/crates/tish_vm/tests/lexical_scope_declare.rs +34 -0
- package/crates/tish_vm/tests/peephole_jump_chain_logical_or.rs +150 -0
- package/crates/tish_wasm/Cargo.toml +15 -0
- package/crates/tish_wasm/src/lib.rs +428 -0
- package/crates/tish_wasm_runtime/Cargo.toml +37 -0
- package/crates/tish_wasm_runtime/src/gpu.rs +429 -0
- package/crates/tish_wasm_runtime/src/lib.rs +42 -0
- package/crates/tishlang_cargo_bindgen/Cargo.toml +26 -0
- package/crates/tishlang_cargo_bindgen/src/classify.rs +261 -0
- package/crates/tishlang_cargo_bindgen/src/discover.rs +125 -0
- package/crates/tishlang_cargo_bindgen/src/infer.rs +382 -0
- package/crates/tishlang_cargo_bindgen/src/lib.rs +349 -0
- package/crates/tishlang_cargo_bindgen/src/main.rs +167 -0
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +117 -0
- package/justfile +276 -0
- package/package.json +2 -2
- package/platform/darwin-arm64/tish-fmt +0 -0
- package/platform/darwin-x64/tish-fmt +0 -0
- package/platform/linux-arm64/tish-fmt +0 -0
- package/platform/linux-x64/tish-fmt +0 -0
- package/platform/win32-x64/tish-fmt.exe +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "tishlang_native"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Native code generation backend for Tish (Cranelift / direct compile)"
|
|
6
|
+
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
9
|
+
[dependencies]
|
|
10
|
+
tishlang_build_utils = { path = "../tish_build_utils", version = ">=0.1" }
|
|
11
|
+
tishlang_ast = { path = "../tish_ast", version = ">=0.1" }
|
|
12
|
+
tishlang_bytecode = { path = "../tish_bytecode", version = ">=0.1" }
|
|
13
|
+
tishlang_compile = { path = "../tish_compile", version = ">=0.1" }
|
|
14
|
+
tishlang_cranelift = { path = "../tish_cranelift", version = ">=0.1" }
|
|
15
|
+
tishlang_llvm = { path = "../tish_llvm", version = ">=0.1" }
|
|
16
|
+
tishlang_opt = { path = "../tish_opt", version = ">=0.1" }
|
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
//! Build native binary via cargo (interim path until Cranelift backend is ready).
|
|
2
|
+
|
|
3
|
+
use std::fs;
|
|
4
|
+
use std::path::Path;
|
|
5
|
+
|
|
6
|
+
use tishlang_compile::ResolvedNativeModule;
|
|
7
|
+
|
|
8
|
+
use crate::config::{NativeArtifact, NativeBuildConfig};
|
|
9
|
+
|
|
10
|
+
/// `tishlang_runtime` Cargo feature names (subset of CLI / compile feature names).
|
|
11
|
+
const RUNTIME_CARGO_FEATURES: &[&str] = &[
|
|
12
|
+
"http",
|
|
13
|
+
"http-hyper",
|
|
14
|
+
"http-io-uring",
|
|
15
|
+
"fs",
|
|
16
|
+
"process",
|
|
17
|
+
"regex",
|
|
18
|
+
"ws",
|
|
19
|
+
"tty",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
/// Map CLI/compile features to flags passed to `tishlang_runtime` in the temp crate's Cargo.toml.
|
|
23
|
+
/// `full` enables every optional runtime capability (matches `tish build --feature full` / LANGUAGE.md).
|
|
24
|
+
fn runtime_features_for_cargo(features: &[String]) -> Vec<String> {
|
|
25
|
+
let mut out = Vec::new();
|
|
26
|
+
for f in features {
|
|
27
|
+
if f == "full" {
|
|
28
|
+
for name in RUNTIME_CARGO_FEATURES {
|
|
29
|
+
if !out.iter().any(|x: &String| x == *name) {
|
|
30
|
+
out.push((*name).to_string());
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if RUNTIME_CARGO_FEATURES.contains(&f.as_str()) && !out.contains(f) {
|
|
36
|
+
out.push(f.clone());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// `[profile.release]` for nested `cargo build` of generated crates.
|
|
43
|
+
fn nested_release_profile_toml() -> &'static str {
|
|
44
|
+
if std::env::var("TISH_FAST_NATIVE_BUILD").as_deref() == Ok("1") {
|
|
45
|
+
r#"[profile.release]
|
|
46
|
+
opt-level = 1
|
|
47
|
+
lto = false
|
|
48
|
+
codegen-units = 16
|
|
49
|
+
incremental = true
|
|
50
|
+
strip = false
|
|
51
|
+
debug = 0
|
|
52
|
+
panic = "abort"
|
|
53
|
+
"#
|
|
54
|
+
} else {
|
|
55
|
+
r#"[profile.release]
|
|
56
|
+
# Reduce binary size: strip symbols, abort on panic (no unwinding), single codegen unit
|
|
57
|
+
strip = true
|
|
58
|
+
panic = "abort"
|
|
59
|
+
codegen-units = 1
|
|
60
|
+
lto = "fat"
|
|
61
|
+
"#
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/// Inject `mod generated_native;` after the crate attribute so the binary crate can call `crate::generated_native::…`.
|
|
66
|
+
fn inject_generated_native_mod(rust_code: &str) -> String {
|
|
67
|
+
if let Some(pos) = rust_code.find("\n\n") {
|
|
68
|
+
let (a, b) = rust_code.split_at(pos + 2);
|
|
69
|
+
format!("{}mod generated_native;\n{}", a, b)
|
|
70
|
+
} else {
|
|
71
|
+
format!("{}\n\nmod generated_native;\n", rust_code)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Whether to embed mimalloc as the `#[global_allocator]` of rust-AOT BINARY output. tish workloads
|
|
76
|
+
/// are allocation-bound (a sampling profile of object/array code spends most time in malloc/free — see
|
|
77
|
+
/// `docs/perf.md`); mimalloc gives ~20% on object/array/bundle code, the same lever as the `tish` CLI's
|
|
78
|
+
/// own `fast-alloc` and the reason JSC ships bmalloc. Default ON; `TISH_NATIVE_FAST_ALLOC=0` opts out
|
|
79
|
+
/// (e.g. a target whose C toolchain can't build mimalloc). Callers also skip it for staticlib output (a
|
|
80
|
+
/// library does not own the final program's allocator) and cross builds (avoid cross-compiling C).
|
|
81
|
+
fn fast_alloc_enabled() -> bool {
|
|
82
|
+
std::env::var("TISH_NATIVE_FAST_ALLOC")
|
|
83
|
+
.map(|v| v != "0")
|
|
84
|
+
.unwrap_or(true)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Insert a mimalloc `#[global_allocator]` into the generated crate root, after the leading
|
|
88
|
+
/// `#![allow(...)]` inner attribute (mirrors [`inject_generated_native_mod`]; an inner attribute must
|
|
89
|
+
/// precede any item, and the codegen emits exactly one — `#![allow(unused, non_snake_case)]`).
|
|
90
|
+
fn inject_global_allocator(rust_code: &str) -> String {
|
|
91
|
+
const STMT: &str =
|
|
92
|
+
"#[global_allocator]\nstatic TISH_GLOBAL_ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;\n\n";
|
|
93
|
+
if let Some(pos) = rust_code.find("\n\n") {
|
|
94
|
+
let (a, b) = rust_code.split_at(pos + 2);
|
|
95
|
+
format!("{a}{STMT}{b}")
|
|
96
|
+
} else {
|
|
97
|
+
format!("{rust_code}\n\n{STMT}")
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
pub(crate) fn rust_code_needs_tokio(rust_code: &str) -> bool {
|
|
102
|
+
rust_code.contains("#[tokio::main]") || rust_code.contains("tokio::runtime::Runtime")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub fn build_via_cargo(
|
|
106
|
+
rust_code: &str,
|
|
107
|
+
native_modules: Vec<ResolvedNativeModule>,
|
|
108
|
+
output_path: &Path,
|
|
109
|
+
features: &[String],
|
|
110
|
+
extra_dependencies_toml: &str,
|
|
111
|
+
generated_native_rs: Option<&str>,
|
|
112
|
+
project_root: Option<&Path>,
|
|
113
|
+
) -> Result<(), String> {
|
|
114
|
+
build_via_cargo_with_config(
|
|
115
|
+
rust_code,
|
|
116
|
+
native_modules,
|
|
117
|
+
output_path,
|
|
118
|
+
features,
|
|
119
|
+
extra_dependencies_toml,
|
|
120
|
+
generated_native_rs,
|
|
121
|
+
project_root,
|
|
122
|
+
&NativeBuildConfig::desktop(),
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[allow(clippy::too_many_arguments)] // orthogonal cargo build inputs; bundling would just relocate the same fields
|
|
127
|
+
pub fn build_via_cargo_with_config(
|
|
128
|
+
rust_code: &str,
|
|
129
|
+
native_modules: Vec<ResolvedNativeModule>,
|
|
130
|
+
output_path: &Path,
|
|
131
|
+
features: &[String],
|
|
132
|
+
extra_dependencies_toml: &str,
|
|
133
|
+
generated_native_rs: Option<&str>,
|
|
134
|
+
project_root: Option<&Path>,
|
|
135
|
+
build_config: &NativeBuildConfig,
|
|
136
|
+
) -> Result<(), String> {
|
|
137
|
+
let out_stem = output_path
|
|
138
|
+
.file_stem()
|
|
139
|
+
.and_then(|s| s.to_str())
|
|
140
|
+
.unwrap_or("tish_out");
|
|
141
|
+
let cargo_name = tishlang_build_utils::cargo_target_name(out_stem);
|
|
142
|
+
let build_dir = tishlang_build_utils::create_build_dir("tish_build", out_stem)?;
|
|
143
|
+
|
|
144
|
+
let runtime_path = tishlang_build_utils::find_runtime_path_for_project(project_root)?;
|
|
145
|
+
|
|
146
|
+
let runtime_features = runtime_features_for_cargo(features);
|
|
147
|
+
let runtime_refs: Vec<&str> = runtime_features.iter().map(String::as_str).collect();
|
|
148
|
+
let features_str = if runtime_refs.is_empty() {
|
|
149
|
+
String::new()
|
|
150
|
+
} else {
|
|
151
|
+
format!(", features = {:?}", runtime_refs)
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
let needs_tokio = rust_code_needs_tokio(rust_code);
|
|
155
|
+
let tokio_dep = if needs_tokio {
|
|
156
|
+
"\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n"
|
|
157
|
+
} else {
|
|
158
|
+
""
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
let native_deps: String = native_modules
|
|
162
|
+
.iter()
|
|
163
|
+
.filter(|m| m.use_path_dependency)
|
|
164
|
+
.map(|m| {
|
|
165
|
+
let path = m.crate_path.display().to_string().replace('\\', "/");
|
|
166
|
+
format!("{} = {{ path = {:?} }}\n", m.package_name, path)
|
|
167
|
+
})
|
|
168
|
+
.collect();
|
|
169
|
+
|
|
170
|
+
let mut more_deps = String::new();
|
|
171
|
+
more_deps.push_str(tokio_dep);
|
|
172
|
+
if !native_deps.is_empty() {
|
|
173
|
+
more_deps.push_str(&format!("\n{}", native_deps));
|
|
174
|
+
}
|
|
175
|
+
if !extra_dependencies_toml.trim().is_empty() {
|
|
176
|
+
more_deps.push_str(&format!("\n{}", extra_dependencies_toml));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let rust_main = if generated_native_rs.is_some() {
|
|
180
|
+
inject_generated_native_mod(rust_code)
|
|
181
|
+
} else {
|
|
182
|
+
rust_code.to_string()
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// mimalloc as the program's global allocator — binary output only (a staticlib does not own the
|
|
186
|
+
// allocator), native only (don't cross-compile mimalloc's C). Adds one cached dep + a global_alloc
|
|
187
|
+
// statement; semantically transparent. `TISH_NATIVE_FAST_ALLOC=0` opts out.
|
|
188
|
+
let use_fast_alloc = fast_alloc_enabled()
|
|
189
|
+
&& build_config.artifact != NativeArtifact::StaticLib
|
|
190
|
+
&& build_config.cargo_target.is_none();
|
|
191
|
+
if use_fast_alloc {
|
|
192
|
+
more_deps.push_str("\nmimalloc = \"0.1\"\n");
|
|
193
|
+
}
|
|
194
|
+
let rust_main = if use_fast_alloc {
|
|
195
|
+
inject_global_allocator(&rust_main)
|
|
196
|
+
} else {
|
|
197
|
+
rust_main
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
let tish_ui_path = std::path::Path::new(&runtime_path)
|
|
201
|
+
.parent()
|
|
202
|
+
.ok_or_else(|| "invalid tishlang_runtime path (no parent)".to_string())?
|
|
203
|
+
.join("tish_ui");
|
|
204
|
+
let ui_dep = if rust_code.contains("tishlang_ui") {
|
|
205
|
+
format!(
|
|
206
|
+
"\ntishlang_ui = {{ path = {:?}, default-features = false, features = [\"runtime\"] }}\n",
|
|
207
|
+
tish_ui_path.display().to_string().replace('\\', "/")
|
|
208
|
+
)
|
|
209
|
+
} else {
|
|
210
|
+
String::new()
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
let profile = nested_release_profile_toml();
|
|
214
|
+
let src_file = if build_config.artifact == NativeArtifact::StaticLib {
|
|
215
|
+
"lib.rs"
|
|
216
|
+
} else {
|
|
217
|
+
"main.rs"
|
|
218
|
+
};
|
|
219
|
+
let crate_section = if build_config.artifact == NativeArtifact::StaticLib {
|
|
220
|
+
format!(
|
|
221
|
+
r#"[lib]
|
|
222
|
+
name = "{}"
|
|
223
|
+
crate-type = ["staticlib"]
|
|
224
|
+
path = "src/lib.rs"
|
|
225
|
+
|
|
226
|
+
"#,
|
|
227
|
+
cargo_name
|
|
228
|
+
)
|
|
229
|
+
} else {
|
|
230
|
+
format!(
|
|
231
|
+
r#"[[bin]]
|
|
232
|
+
name = "{}"
|
|
233
|
+
path = "src/main.rs"
|
|
234
|
+
|
|
235
|
+
"#,
|
|
236
|
+
cargo_name
|
|
237
|
+
)
|
|
238
|
+
};
|
|
239
|
+
let cargo_toml = format!(
|
|
240
|
+
r#"[package]
|
|
241
|
+
name = "tish_output"
|
|
242
|
+
version = "0.1.0"
|
|
243
|
+
edition = "2021"
|
|
244
|
+
|
|
245
|
+
{}{}
|
|
246
|
+
[dependencies]
|
|
247
|
+
tishlang_runtime = {{ path = {:?}{} }}
|
|
248
|
+
{}{}"#,
|
|
249
|
+
crate_section, profile, runtime_path, features_str, more_deps, ui_dep
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
fs::write(build_dir.join("Cargo.toml"), cargo_toml)
|
|
253
|
+
.map_err(|e| format!("Cannot write Cargo.toml: {}", e))?;
|
|
254
|
+
if let Some(gen) = generated_native_rs {
|
|
255
|
+
fs::write(build_dir.join("src/generated_native.rs"), gen)
|
|
256
|
+
.map_err(|e| format!("Cannot write generated_native.rs: {}", e))?;
|
|
257
|
+
}
|
|
258
|
+
fs::write(build_dir.join("src").join(src_file), rust_main)
|
|
259
|
+
.map_err(|e| format!("Cannot write {}: {}", src_file, e))?;
|
|
260
|
+
|
|
261
|
+
let workspace_target = Path::new(&runtime_path)
|
|
262
|
+
.parent()
|
|
263
|
+
.and_then(|p| p.parent())
|
|
264
|
+
.map(|ws| ws.join("target"));
|
|
265
|
+
let target_dir = workspace_target.filter(|p| p.exists());
|
|
266
|
+
let cross = build_config.cargo_target.as_deref();
|
|
267
|
+
let release_sub = if let Some(triple) = cross {
|
|
268
|
+
format!("{triple}/release")
|
|
269
|
+
} else {
|
|
270
|
+
"release".to_string()
|
|
271
|
+
};
|
|
272
|
+
let binary_dir = target_dir
|
|
273
|
+
.as_ref()
|
|
274
|
+
.map(|t| t.join(&release_sub))
|
|
275
|
+
.unwrap_or_else(|| build_dir.join("target").join(&release_sub));
|
|
276
|
+
|
|
277
|
+
tishlang_build_utils::run_cargo_build(&build_dir, target_dir.as_deref(), cross)?;
|
|
278
|
+
|
|
279
|
+
let artifact = if build_config.artifact == NativeArtifact::StaticLib {
|
|
280
|
+
tishlang_build_utils::find_release_staticlib(&binary_dir, &cargo_name)?
|
|
281
|
+
} else {
|
|
282
|
+
tishlang_build_utils::find_release_binary(&binary_dir, &cargo_name)?
|
|
283
|
+
};
|
|
284
|
+
let target = if build_config.artifact == NativeArtifact::StaticLib {
|
|
285
|
+
if output_path.extension().is_some_and(|e| e == "a") {
|
|
286
|
+
output_path.to_path_buf()
|
|
287
|
+
} else if output_path.to_string_lossy().ends_with('/') || output_path.is_dir() {
|
|
288
|
+
output_path.join(format!("lib{out_stem}.a"))
|
|
289
|
+
} else {
|
|
290
|
+
output_path.with_extension("a")
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
tishlang_build_utils::resolve_output_path(output_path, out_stem)
|
|
294
|
+
};
|
|
295
|
+
tishlang_build_utils::copy_binary_to_output(&artifact, &target)?;
|
|
296
|
+
|
|
297
|
+
Ok(())
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/// Build several native binaries in **one** nested Cargo project (shared `tishlang_runtime` compile).
|
|
301
|
+
///
|
|
302
|
+
/// `bins` order must match `outputs`: each `(stem, rust_code, generated_native_rs)` pairs with
|
|
303
|
+
/// `outputs[i].0` (entry path — used only for validation) and `outputs[i].1` (final binary path).
|
|
304
|
+
#[allow(clippy::too_many_arguments)] // orthogonal batch-build inputs (bins/outputs/modules/flags)
|
|
305
|
+
pub(crate) fn build_many_via_cargo(
|
|
306
|
+
bins: Vec<(String, String, Option<String>)>,
|
|
307
|
+
native_modules: Vec<ResolvedNativeModule>,
|
|
308
|
+
features: &[String],
|
|
309
|
+
extra_dependencies_toml: &str,
|
|
310
|
+
needs_tokio: bool,
|
|
311
|
+
needs_ui: bool,
|
|
312
|
+
outputs: &[(&Path, &Path)],
|
|
313
|
+
project_root: Option<&Path>,
|
|
314
|
+
) -> Result<(), String> {
|
|
315
|
+
if bins.len() != outputs.len() {
|
|
316
|
+
return Err(format!(
|
|
317
|
+
"build_many_via_cargo: bins ({}) != outputs ({})",
|
|
318
|
+
bins.len(),
|
|
319
|
+
outputs.len()
|
|
320
|
+
));
|
|
321
|
+
}
|
|
322
|
+
for (i, (stem, _, _)) in bins.iter().enumerate() {
|
|
323
|
+
let entry = outputs[i].0;
|
|
324
|
+
let expect = entry.file_stem().and_then(|s| s.to_str()).unwrap_or("");
|
|
325
|
+
if expect != stem {
|
|
326
|
+
return Err(format!(
|
|
327
|
+
"build_many_via_cargo: stem mismatch at {}: {} vs {}",
|
|
328
|
+
i, stem, expect
|
|
329
|
+
));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
let batch_id = format!("many_{}", std::process::id());
|
|
334
|
+
let build_dir = tishlang_build_utils::create_build_dir("tish_build_many", &batch_id)?;
|
|
335
|
+
|
|
336
|
+
let runtime_path = tishlang_build_utils::find_runtime_path_for_project(project_root)?;
|
|
337
|
+
|
|
338
|
+
let runtime_features = runtime_features_for_cargo(features);
|
|
339
|
+
let runtime_refs: Vec<&str> = runtime_features.iter().map(String::as_str).collect();
|
|
340
|
+
let features_str = if runtime_refs.is_empty() {
|
|
341
|
+
String::new()
|
|
342
|
+
} else {
|
|
343
|
+
format!(", features = {:?}", runtime_refs)
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
let tokio_dep = if needs_tokio {
|
|
347
|
+
"\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n"
|
|
348
|
+
} else {
|
|
349
|
+
""
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
let native_deps: String = native_modules
|
|
353
|
+
.iter()
|
|
354
|
+
.filter(|m| m.use_path_dependency)
|
|
355
|
+
.map(|m| {
|
|
356
|
+
let path = m.crate_path.display().to_string().replace('\\', "/");
|
|
357
|
+
format!("{} = {{ path = {:?} }}\n", m.package_name, path)
|
|
358
|
+
})
|
|
359
|
+
.collect();
|
|
360
|
+
|
|
361
|
+
let mut more_deps = String::new();
|
|
362
|
+
more_deps.push_str(tokio_dep);
|
|
363
|
+
if !native_deps.is_empty() {
|
|
364
|
+
more_deps.push_str(&format!("\n{}", native_deps));
|
|
365
|
+
}
|
|
366
|
+
if !extra_dependencies_toml.trim().is_empty() {
|
|
367
|
+
more_deps.push_str(&format!("\n{}", extra_dependencies_toml));
|
|
368
|
+
}
|
|
369
|
+
// mimalloc global allocator for every binary in the batch (all are executables, always native here).
|
|
370
|
+
let use_fast_alloc = fast_alloc_enabled();
|
|
371
|
+
if use_fast_alloc {
|
|
372
|
+
more_deps.push_str("\nmimalloc = \"0.1\"\n");
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let tish_ui_path = std::path::Path::new(&runtime_path)
|
|
376
|
+
.parent()
|
|
377
|
+
.ok_or_else(|| "invalid tishlang_runtime path (no parent)".to_string())?
|
|
378
|
+
.join("tish_ui");
|
|
379
|
+
let ui_dep = if needs_ui {
|
|
380
|
+
format!(
|
|
381
|
+
"\ntishlang_ui = {{ path = {:?}, default-features = false, features = [\"runtime\"] }}\n",
|
|
382
|
+
tish_ui_path.display().to_string().replace('\\', "/")
|
|
383
|
+
)
|
|
384
|
+
} else {
|
|
385
|
+
String::new()
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
let mut bin_tables = String::new();
|
|
389
|
+
for (stem, rust_code, generated_native_rs) in &bins {
|
|
390
|
+
let bin_dir = build_dir.join("src/bin").join(stem);
|
|
391
|
+
fs::create_dir_all(&bin_dir).map_err(|e| format!("create bin dir: {}", e))?;
|
|
392
|
+
|
|
393
|
+
let rust_main = if generated_native_rs.is_some() {
|
|
394
|
+
inject_generated_native_mod(rust_code)
|
|
395
|
+
} else {
|
|
396
|
+
rust_code.clone()
|
|
397
|
+
};
|
|
398
|
+
let rust_main = if use_fast_alloc {
|
|
399
|
+
inject_global_allocator(&rust_main)
|
|
400
|
+
} else {
|
|
401
|
+
rust_main
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
fs::write(bin_dir.join("main.rs"), rust_main)
|
|
405
|
+
.map_err(|e| format!("write main.rs for {}: {}", stem, e))?;
|
|
406
|
+
if let Some(gen) = generated_native_rs {
|
|
407
|
+
fs::write(bin_dir.join("generated_native.rs"), gen)
|
|
408
|
+
.map_err(|e| format!("write generated_native.rs for {}: {}", stem, e))?;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
bin_tables.push_str(&format!(
|
|
412
|
+
r#"[[bin]]
|
|
413
|
+
name = "{stem}"
|
|
414
|
+
path = "src/bin/{stem}/main.rs"
|
|
415
|
+
|
|
416
|
+
"#
|
|
417
|
+
));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
let profile = nested_release_profile_toml();
|
|
421
|
+
let cargo_toml = format!(
|
|
422
|
+
r#"[package]
|
|
423
|
+
name = "tish_output_many"
|
|
424
|
+
version = "0.1.0"
|
|
425
|
+
edition = "2021"
|
|
426
|
+
|
|
427
|
+
{}{}
|
|
428
|
+
[dependencies]
|
|
429
|
+
tishlang_runtime = {{ path = {:?}{} }}
|
|
430
|
+
{}{}"#,
|
|
431
|
+
bin_tables, profile, runtime_path, features_str, more_deps, ui_dep
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
fs::write(build_dir.join("Cargo.toml"), cargo_toml)
|
|
435
|
+
.map_err(|e| format!("Cannot write Cargo.toml: {}", e))?;
|
|
436
|
+
|
|
437
|
+
let workspace_target = Path::new(&runtime_path)
|
|
438
|
+
.parent()
|
|
439
|
+
.and_then(|p| p.parent())
|
|
440
|
+
.map(|ws| ws.join("target"));
|
|
441
|
+
let target_dir = workspace_target.filter(|p| p.exists());
|
|
442
|
+
let binary_dir = target_dir
|
|
443
|
+
.as_ref()
|
|
444
|
+
.map(|t| t.join("release"))
|
|
445
|
+
.unwrap_or_else(|| build_dir.join("target").join("release"));
|
|
446
|
+
|
|
447
|
+
tishlang_build_utils::run_cargo_build(&build_dir, target_dir.as_deref(), None)?;
|
|
448
|
+
|
|
449
|
+
for i in 0..bins.len() {
|
|
450
|
+
let stem = bins[i].0.as_str();
|
|
451
|
+
let output_path = outputs[i].1;
|
|
452
|
+
let binary = tishlang_build_utils::find_release_binary(binary_dir.as_path(), stem)?;
|
|
453
|
+
let target = tishlang_build_utils::resolve_output_path(output_path, stem);
|
|
454
|
+
tishlang_build_utils::copy_binary_to_output(&binary, &target)?;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
Ok(())
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
#[cfg(test)]
|
|
461
|
+
mod tests {
|
|
462
|
+
use super::runtime_features_for_cargo;
|
|
463
|
+
|
|
464
|
+
#[test]
|
|
465
|
+
fn runtime_features_full_expands() {
|
|
466
|
+
let f = runtime_features_for_cargo(&["full".to_string()]);
|
|
467
|
+
assert!(f.contains(&"http".to_string()));
|
|
468
|
+
assert!(f.contains(&"fs".to_string()));
|
|
469
|
+
assert!(f.contains(&"process".to_string()));
|
|
470
|
+
assert!(f.contains(&"regex".to_string()));
|
|
471
|
+
assert!(f.contains(&"ws".to_string()));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
#[test]
|
|
475
|
+
fn runtime_features_merges_full_and_specific() {
|
|
476
|
+
let f = runtime_features_for_cargo(&["full".to_string(), "http".to_string()]);
|
|
477
|
+
// `full` expands to every RUNTIME_CARGO_FEATURES entry; redundant `http` must not duplicate.
|
|
478
|
+
assert_eq!(f.len(), super::RUNTIME_CARGO_FEATURES.len());
|
|
479
|
+
assert_eq!(f.iter().filter(|x| *x == "http").count(), 1);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
//! Native build configuration (desktop binary vs iOS staticlib, cross-target).
|
|
2
|
+
|
|
3
|
+
use tishlang_compile::NativeEmitMode;
|
|
4
|
+
|
|
5
|
+
/// Output artifact kind for `tish build --target native`.
|
|
6
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
|
7
|
+
pub enum NativeArtifact {
|
|
8
|
+
#[default]
|
|
9
|
+
Bin,
|
|
10
|
+
StaticLib,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// Options passed from the CLI into nested `cargo build`.
|
|
14
|
+
#[derive(Debug, Clone, Default)]
|
|
15
|
+
pub struct NativeBuildConfig {
|
|
16
|
+
pub artifact: NativeArtifact,
|
|
17
|
+
/// When set, run `cargo build --target <triple>` and skip `-C target-cpu=native`.
|
|
18
|
+
pub cargo_target: Option<String>,
|
|
19
|
+
pub emit_mode: NativeEmitMode,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
impl NativeBuildConfig {
|
|
23
|
+
pub fn desktop() -> Self {
|
|
24
|
+
Self::default()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn ios_staticlib(triple: &str) -> Self {
|
|
28
|
+
Self {
|
|
29
|
+
artifact: NativeArtifact::StaticLib,
|
|
30
|
+
cargo_target: Some(triple.to_string()),
|
|
31
|
+
emit_mode: NativeEmitMode::EmbeddedLib,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pub fn is_cross_compile(&self) -> bool {
|
|
36
|
+
self.cargo_target.is_some()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Filter runtime features for iOS sandbox builds.
|
|
41
|
+
pub fn ios_runtime_features(features: &[String]) -> Vec<String> {
|
|
42
|
+
const ALLOW: &[&str] = &["http", "http-hyper", "regex", "timers"];
|
|
43
|
+
features
|
|
44
|
+
.iter()
|
|
45
|
+
.filter(|f| ALLOW.contains(&f.as_str()))
|
|
46
|
+
.cloned()
|
|
47
|
+
.collect()
|
|
48
|
+
}
|