cli: add --emit-exe (+ --emit-exe-nyrt/--emit-exe-libs) to build native exe via ny-llvmc; docs updated
This commit is contained in:
@ -37,9 +37,12 @@ Wiring(Rust 側)
|
||||
2) `python3 tools/llvmlite_harness.py --in <mir.json> --out <obj.o>` を起動
|
||||
3) 成功後は通常のリンク手順(NyRT とリンク)
|
||||
|
||||
Tools(統合フロー)
|
||||
Tools / CLI(統合フロー)
|
||||
- crate 直結の EXE 出力: `NYASH_LLVM_COMPILER=crate NYASH_LLVM_EMIT=exe tools/build_llvm.sh apps/tests/ternary_basic.nyash -o app`
|
||||
- 環境変数 `NYASH_LLVM_NYRT` で NyRT の場所を、`NYASH_LLVM_LIBS` で追加フラグを指定できる。
|
||||
- CLI から直接 EXE 出力(新規):
|
||||
- `./target/release/nyash --emit-exe tmp/app --backend mir apps/tests/ternary_basic.nyash`
|
||||
- 追加オプション: `--emit-exe-nyrt <dir>` / `--emit-exe-libs "<flags>"`
|
||||
|
||||
Scope(Phase 15)
|
||||
- 最小命令: Const/BinOp/Compare/Phi/Branch/Jump/Return
|
||||
|
||||
@ -20,6 +20,7 @@ CI Workflows
|
||||
2) EXE 生成: `./target/release/ny-llvmc --in tmp/app.json --emit exe --nyrt target/release --out tmp/app`
|
||||
3) 実行: `./tmp/app`(戻り値が exit code)
|
||||
- ワンコマンドスモーク: `bash tools/crate_exe_smoke.sh apps/tests/ternary_basic.nyash`
|
||||
- CLI で直接 EXE 出力: `./target/release/nyash --emit-exe tmp/app --backend mir apps/tests/ternary_basic.nyash`
|
||||
- Installs LLVM 18 + llvmlite, then runs `tools/exe_first_smoke.sh`.
|
||||
|
||||
Useful Env Flags
|
||||
|
||||
28
src/cli.rs
28
src/cli.rs
@ -71,6 +71,10 @@ pub struct CliConfig {
|
||||
pub cli_usings: Vec<String>,
|
||||
// Emit MIR JSON to a file and exit (bridge mode)
|
||||
pub emit_mir_json: Option<String>,
|
||||
// Emit native executable via ny-llvmc (crate) and exit
|
||||
pub emit_exe: Option<String>,
|
||||
pub emit_exe_nyrt: Option<String>,
|
||||
pub emit_exe_libs: Option<String>,
|
||||
}
|
||||
|
||||
impl CliConfig {
|
||||
@ -139,6 +143,24 @@ impl CliConfig {
|
||||
.value_name("FILE")
|
||||
.help("Emit MIR JSON v0 to file (validation-friendly) and exit")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("emit-exe")
|
||||
.long("emit-exe")
|
||||
.value_name("FILE")
|
||||
.help("Emit native executable via ny-llvmc (crate) and exit")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("emit-exe-nyrt")
|
||||
.long("emit-exe-nyrt")
|
||||
.value_name("DIR")
|
||||
.help("Directory containing libnyrt.a (used with --emit-exe)")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("emit-exe-libs")
|
||||
.long("emit-exe-libs")
|
||||
.value_name("FLAGS")
|
||||
.help("Extra linker flags for ny-llvmc when emitting executable")
|
||||
)
|
||||
.arg(
|
||||
Arg::new("stage3")
|
||||
.long("stage3")
|
||||
@ -491,6 +513,9 @@ impl CliConfig {
|
||||
.map(|v| v.cloned().collect())
|
||||
.unwrap_or_else(|| Vec::new()),
|
||||
emit_mir_json: matches.get_one::<String>("emit-mir-json").cloned(),
|
||||
emit_exe: matches.get_one::<String>("emit-exe").cloned(),
|
||||
emit_exe_nyrt: matches.get_one::<String>("emit-exe-nyrt").cloned(),
|
||||
emit_exe_libs: matches.get_one::<String>("emit-exe-libs").cloned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -546,6 +571,9 @@ impl Default for CliConfig {
|
||||
build_target: None,
|
||||
cli_usings: Vec::new(),
|
||||
emit_mir_json: None,
|
||||
emit_exe: None,
|
||||
emit_exe_nyrt: None,
|
||||
emit_exe_libs: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,6 +181,48 @@ impl NyashRunner {
|
||||
println!("MIR JSON written: {}", p.display());
|
||||
std::process::exit(0);
|
||||
}
|
||||
// If CLI requested EXE emit, generate JSON then invoke ny-llvmc to link NyRT and exit.
|
||||
if let Some(exe_out) = self.config.emit_exe.as_ref() {
|
||||
let tmp_dir = std::path::Path::new("tmp");
|
||||
let _ = std::fs::create_dir_all(tmp_dir);
|
||||
let json_path = tmp_dir.join("nyash_cli_emit.json");
|
||||
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, &json_path) {
|
||||
eprintln!("❌ MIR JSON emit error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
// Resolve ny-llvmc
|
||||
let ny_llvmc = std::env::var("NYASH_NY_LLVM_COMPILER")
|
||||
.ok()
|
||||
.and_then(|s| if !s.is_empty() { Some(std::path::PathBuf::from(s)) } else { None })
|
||||
.or_else(|| which::which("ny-llvmc").ok())
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("target/release/ny-llvmc"));
|
||||
// Build command
|
||||
let mut cmd = std::process::Command::new(ny_llvmc);
|
||||
cmd.arg("--in").arg(&json_path)
|
||||
.arg("--emit").arg("exe")
|
||||
.arg("--out").arg(exe_out);
|
||||
if let Some(dir) = self.config.emit_exe_nyrt.as_ref() {
|
||||
cmd.arg("--nyrt").arg(dir);
|
||||
} else {
|
||||
// default hint
|
||||
cmd.arg("--nyrt").arg("target/release");
|
||||
}
|
||||
if let Some(flags) = self.config.emit_exe_libs.as_ref() {
|
||||
if !flags.trim().is_empty() {
|
||||
cmd.arg("--libs").arg(flags);
|
||||
}
|
||||
}
|
||||
let status = cmd.status().unwrap_or_else(|e| {
|
||||
eprintln!("❌ failed to spawn ny-llvmc: {}", e);
|
||||
std::process::exit(1);
|
||||
});
|
||||
if !status.success() {
|
||||
eprintln!("❌ ny-llvmc failed with status: {:?}", status.code());
|
||||
std::process::exit(1);
|
||||
}
|
||||
println!("EXE written: {}", exe_out);
|
||||
std::process::exit(0);
|
||||
}
|
||||
use crate::backend::MirInterpreter;
|
||||
use crate::box_trait::{BoolBox, IntegerBox, StringBox};
|
||||
use crate::boxes::FloatBox;
|
||||
|
||||
@ -75,5 +75,45 @@ impl NyashRunner {
|
||||
println!("MIR JSON written: {}", p.display());
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// Emit native executable via ny-llvmc (crate) and exit
|
||||
if let Some(exe_out) = self.config.emit_exe.as_ref() {
|
||||
let tmp_dir = std::path::Path::new("tmp");
|
||||
let _ = std::fs::create_dir_all(tmp_dir);
|
||||
let json_path = tmp_dir.join("nyash_cli_emit.json");
|
||||
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(&compile_result.module, &json_path) {
|
||||
eprintln!("❌ MIR JSON emit error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
let ny_llvmc = std::env::var("NYASH_NY_LLVM_COMPILER")
|
||||
.ok()
|
||||
.and_then(|s| if !s.is_empty() { Some(std::path::PathBuf::from(s)) } else { None })
|
||||
.or_else(|| which::which("ny-llvmc").ok())
|
||||
.unwrap_or_else(|| std::path::PathBuf::from("target/release/ny-llvmc"));
|
||||
let mut cmd = std::process::Command::new(ny_llvmc);
|
||||
cmd.arg("--in").arg(&json_path)
|
||||
.arg("--emit").arg("exe")
|
||||
.arg("--out").arg(exe_out);
|
||||
if let Some(dir) = self.config.emit_exe_nyrt.as_ref() {
|
||||
cmd.arg("--nyrt").arg(dir);
|
||||
} else {
|
||||
cmd.arg("--nyrt").arg("target/release");
|
||||
}
|
||||
if let Some(flags) = self.config.emit_exe_libs.as_ref() {
|
||||
if !flags.trim().is_empty() {
|
||||
cmd.arg("--libs").arg(flags);
|
||||
}
|
||||
}
|
||||
let status = cmd.status().unwrap_or_else(|e| {
|
||||
eprintln!("❌ failed to spawn ny-llvmc: {}", e);
|
||||
std::process::exit(1);
|
||||
});
|
||||
if !status.success() {
|
||||
eprintln!("❌ ny-llvmc failed with status: {:?}", status.code());
|
||||
std::process::exit(1);
|
||||
}
|
||||
println!("EXE written: {}", exe_out);
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user