packaged binary

This commit is contained in:
Parker TenBroeck 2026-03-11 10:33:51 -04:00
parent 0289d1171f
commit defbd88adf
11 changed files with 110 additions and 24 deletions

58
relay/build.rs Normal file
View file

@ -0,0 +1,58 @@
use std::path::PathBuf;
use std::process::Command;
fn main() {
// silly hack of sorts because bindeps are unstable
let manifest_dir = PathBuf::from(
std::env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR was not set by Cargo"),
);
let workspace_root = manifest_dir
.parent()
.expect("relay crate should live under a workspace root");
println!("cargo:rerun-if-changed={}", workspace_root.join("conn").display());
let isolated_target_dir = workspace_root.join("target").join("conn-build");
let status = Command::new("cargo")
.arg("build")
.arg("--package")
.arg("libvhdl_conn")
.arg("--release")
.arg("--lib")
.arg("--target-dir")
.arg(&isolated_target_dir)
.current_dir(workspace_root)
.status()
.expect("failed to spawn cargo build for conn");
if !status.success() {
panic!(
"build script failed: `cargo build --package conn --release --lib` exited with {status}"
);
}
// Copy the built staticlib into the workspace release target path used by relay/src/build.rs.
let isolated_release_dir = isolated_target_dir.join("release");
let out_release_dir = workspace_root.join("target").join("release");
std::fs::create_dir_all(&out_release_dir).expect("failed to create workspace target/release");
// conn currently builds as libconn.a; keep a compatibility alias for relay/src/build.rs (libvhdl_ui.a).
let src_lib = isolated_release_dir.join("libconn.a");
if !src_lib.exists() {
panic!(
"build script failed: expected static library not found at {}",
src_lib.display()
);
}
let dst_conn = out_release_dir.join("libvhdl_conn.a");
std::fs::copy(&src_lib, &dst_conn).expect("failed to copy libconn.a into workspace target/release");
let dst_compat = out_release_dir.join("libvhdl_conn.a");
std::fs::copy(&src_lib, &dst_compat)
.expect("failed to copy compatibility libvhdl_conn.a into workspace target/release");
}

View file

@ -5,6 +5,9 @@ use tokio::process::{Child, Command};
use crate::HResult;
const EMBEDDED_VHDL_UI_LIB: &[u8] =
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/../target/release/libvhdl_conn.a"));
async fn ensure_ok(child: Child) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let result = child.wait_with_output().await?;
if !result.status.success() {
@ -73,6 +76,8 @@ pub async fn copy_and_build(
pub async fn build(path: &Path, src: &Path) -> HResult<()>{
std::fs::create_dir_all(path)?;
let embedded_lib_path = path.join("libvhdl_conn.a");
std::fs::write(&embedded_lib_path, EMBEDDED_VHDL_UI_LIB)?;
let mut cmd = Command::new("ghdl");
cmd.kill_on_drop(true);
@ -102,7 +107,7 @@ pub async fn build(path: &Path, src: &Path) -> HResult<()>{
cmd.args(["-m", "--std=08"]);
cmd.arg(format!(
"-Wl,{}",
std::fs::canonicalize("../target/release/libvhdl_ui.a")?.display()
embedded_lib_path.display()
));
cmd.arg("tb");
cmd.current_dir(path);
@ -112,4 +117,4 @@ pub async fn build(path: &Path, src: &Path) -> HResult<()>{
ensure_ok(cmd.spawn()?).await?;
Ok(())
}
}

View file

@ -30,7 +30,6 @@ struct Handler {
build_dir: PathBuf,
src_dir: PathBuf,
program: Option<PathBuf>,
process: Option<Process>,
refresh_time: Duration,
@ -45,7 +44,6 @@ impl Handler {
receiver,
build_dir: build,
src_dir: src,
program: None,
process: None,
refresh_time: Duration::from_millis(30),
}
@ -186,10 +184,7 @@ impl Handler {
match build::build(&self.build_dir, &self.src_dir).await {
Ok(_) => {},
Err(err) => {
_ = self
.sender
.send(Message::Text(format!("Failed to build: {err}").into()))
.await;
_ = self.eprint(format!("Failed to build: {err}")).await;
return;
}
};

View file

@ -1,29 +1,60 @@
use axum::{
Router,
extract::ws::WebSocketUpgrade,
http::{StatusCode, header},
response::{Html, IntoResponse},
routing::get,
};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use tower_http::services::ServeDir;
pub mod build;
pub mod run;
pub mod local;
pub mod remote;
const UI_INDEX_HTML: &str = include_str!("../ui/index.html");
const UI_STYLES_CSS: &str = include_str!("../ui/styles.css");
const UI_APP_JS: &str = include_str!("../ui/app.js");
async fn serve_index() -> impl IntoResponse {
Html(UI_INDEX_HTML)
}
async fn serve_styles() -> impl IntoResponse {
(
[(header::CONTENT_TYPE, "text/css; charset=utf-8")],
UI_STYLES_CSS,
)
}
async fn serve_app_js() -> impl IntoResponse {
(
[(header::CONTENT_TYPE, "application/javascript; charset=utf-8")],
UI_APP_JS,
)
}
async fn not_found() -> impl IntoResponse {
(StatusCode::NOT_FOUND, "not found")
}
#[tokio::main]
async fn main() {
let app = Router::new()
.route(
"/ws/local",
get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(remote::ws_handler) }),
)
.route("/", get(serve_index))
.route("/index.html", get(serve_index))
.route("/styles.css", get(serve_styles))
.route("/app.js", get(serve_app_js))
.route(
"/ws/remote",
get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(local::ws_handler) }),
)
.fallback_service(ServeDir::new("ui"));
.route(
"/ws/local",
get(|ws: WebSocketUpgrade| async move { ws.on_upgrade(remote::ws_handler) }),
)
.fallback(get(not_found));
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
println!("Open UI: http://{}/", addr);