feat: add dx print command, drive hotpatching engine directly. (#4602)

* feat: add dx print command

* small tweak to how client_target is handled

* hotpatching engine wired up!

* small cleanups

* lighter diff

* little bit more light cleanups

* remove changes to manganis

* fix wrong dir error

* move session_cache fixing to prebuild step
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-08-21 20:29:49 -07:00
1 parent d899afaf4a
commit 083e04bb6c
19 files changed
+633 -234

No files matched your search

+7 -7
View File
@@ -170,7 +170,7 @@ impl AppBuilder {
tx: tx.clone(),
};
request.verify_tooling(&ctx).await?;
request.prepare_build_dir()?;
request.prebuild(&ctx).await?;
request.build(&ctx).await
}
});
@@ -406,14 +406,14 @@ impl AppBuilder {
_ => {}
}
tracing::info!(json = ?StructuredOutput::BuildUpdate { stage: stage.clone() });
tracing::info!(json = %StructuredOutput::BuildUpdate { stage: stage.clone() });
}
BuilderUpdate::CompilerMessage { message } => {
tracing::info!(json = ?StructuredOutput::RustcOutput { message: message.clone() }, %message);
tracing::info!(json = %StructuredOutput::RustcOutput { message: message.clone() }, %message);
}
BuilderUpdate::BuildReady { bundle } => {
tracing::debug!(json = ?StructuredOutput::BuildFinished {
path: self.build.root_dir(),
tracing::debug!(json = %StructuredOutput::BuildFinished {
artifacts: bundle.clone().into_structured_output(),
});
return Ok(bundle);
}
@@ -421,7 +421,7 @@ impl AppBuilder {
// Flush remaining compiler messages
while let Ok(Some(msg)) = self.rx.try_next() {
if let BuilderUpdate::CompilerMessage { message } = msg {
tracing::info!(json = ?StructuredOutput::RustcOutput { message: message.clone() }, %message);
tracing::info!(json = %StructuredOutput::RustcOutput { message: message.clone() }, %message);
}
}
@@ -517,7 +517,7 @@ impl AppBuilder {
}
// If there's any CARGO vars in the rustc_wrapper files, push those too
if let Ok(res) = std::fs::read_to_string(self.build.rustc_wrapper_args_file.path()) {
if let Ok(res) = std::fs::read_to_string(self.build.rustc_wrapper_args_file()) {
if let Ok(res) = serde_json::from_str::<RustcArgs>(&res) {
for (key, value) in res.envs {
if key.starts_with("CARGO_") {
+129 -155
View File
@@ -349,7 +349,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH},
};
use target_lexicon::{Architecture, Environment, OperatingSystem, Triple};
use tempfile::{NamedTempFile, TempDir};
use tempfile::TempDir;
use tokio::{io::AsyncBufReadExt, process::Command};
use uuid::Uuid;
@@ -392,15 +392,11 @@ pub(crate) struct BuildRequest {
pub(crate) debug_symbols: bool,
pub(crate) inject_loading_scripts: bool,
pub(crate) custom_linker: Option<PathBuf>,
pub(crate) session_cache_dir: Arc<TempDir>,
pub(crate) link_args_file: Arc<NamedTempFile>,
pub(crate) link_err_file: Arc<NamedTempFile>,
pub(crate) rustc_wrapper_args_file: Arc<NamedTempFile>,
pub(crate) command_file: Arc<NamedTempFile>,
pub(crate) base_path: Option<String>,
pub(crate) using_dioxus_explicitly: bool,
pub(crate) apple_entitlements: Option<PathBuf>,
pub(crate) apple_team_id: Option<String>,
pub(crate) session_cache_dir: PathBuf,
}
/// dx can produce different "modes" of a build. A "regular" build is a "base" build. The Fat and Thin
@@ -447,6 +443,7 @@ pub enum BuildMode {
/// The patch cache is only populated on fat builds and then used for thin builds (see `BuildMode::Thin`).
#[derive(Clone, Debug)]
pub struct BuildArtifacts {
pub(crate) root_dir: PathBuf,
pub(crate) bundle: BundleFormat,
pub(crate) exe: PathBuf,
pub(crate) direct_rustc: RustcArgs,
@@ -476,11 +473,7 @@ impl BuildRequest {
///
/// Note: Build requests are typically created only when the CLI is invoked or when significant
/// changes are detected in the `Cargo.toml` (e.g., features added or removed).
pub(crate) async fn new(
args: &TargetArgs,
main_target: Option<String>,
workspace: Arc<Workspace>,
) -> Result<Self> {
pub(crate) async fn new(args: &TargetArgs, workspace: Arc<Workspace>) -> Result<Self> {
let crate_package = workspace.find_main_package(args.package.clone())?;
let config = workspace
@@ -524,8 +517,8 @@ impl BuildRequest {
.unwrap_or(workspace.krates[crate_package].name.clone());
// Use the main_target for the client + server build if it is set, otherwise use the target name for this
// specific build
let main_target = main_target.unwrap_or(target_name.clone());
// specific build. This is important for @client @server syntax so we use the client's output directory for the bundle.
let main_target = args.client_target.clone().unwrap_or(target_name.clone());
let crate_target = main_package
.targets
@@ -771,25 +764,10 @@ impl BuildRequest {
}
}
// Set up some tempfiles so we can do some IPC between us and the linker/rustc wrapper (which is occasionally us!)
let link_args_file = Arc::new(
NamedTempFile::with_suffix(".txt")
.context("Failed to create temporary file for linker args")?,
);
let link_err_file = Arc::new(
NamedTempFile::with_suffix(".txt")
.context("Failed to create temporary file for linker args")?,
);
let rustc_wrapper_args_file = Arc::new(
NamedTempFile::with_suffix(".json")
.context("Failed to create temporary file for rustc wrapper args")?,
);
let session_cache_dir = Arc::new(
TempDir::new().context("Failed to create temporary directory for session cache")?,
);
let command_file = Arc::new(
NamedTempFile::new().context("Failed to create temporary file for linker args")?,
);
let session_cache_dir = args
.session_cache_dir
.clone()
.unwrap_or_else(|| TempDir::new().unwrap().into_path());
let extra_rustc_args = shell_words::split(&args.rustc_args.clone().unwrap_or_default())
.context("Failed to parse rustc args")?;
@@ -801,22 +779,10 @@ impl BuildRequest {
r#"Target Info:
• features: {features:?}
• triple: {triple}
• bundle format: {bundle:?}"#
);
tracing::debug!(
r#"Log Files:
• link_args_file: {},
• link_err_file: {},
• rustc_wrapper_args_file: {},
• session_cache_dir: {}
• linker: {:?}
• target_dir: {:?}"#,
link_args_file.path().display(),
link_err_file.path().display(),
rustc_wrapper_args_file.path().display(),
session_cache_dir.path().display(),
custom_linker,
target_dir,
• bundle format: {bundle:?}
• session cache dir: {session_cache_dir:?}
• linker: {custom_linker:?}
• target_dir: {target_dir:?}"#,
);
Ok(Self {
@@ -832,11 +798,6 @@ impl BuildRequest {
config,
target_dir,
custom_linker,
link_args_file,
link_err_file,
command_file,
session_cache_dir,
rustc_wrapper_args_file,
extra_rustc_args,
extra_cargo_args,
release,
@@ -845,6 +806,7 @@ impl BuildRequest {
rustflags,
using_dioxus_explicitly,
should_codesign,
session_cache_dir,
skip_assets: args.skip_assets,
base_path: args.base_path.clone(),
wasm_split: args.wasm_split,
@@ -855,6 +817,39 @@ impl BuildRequest {
})
}
pub(crate) async fn prebuild(&self, ctx: &BuildContext) -> Result<()> {
// Create the session cache directory
let cache_dir = self.session_cache_dir();
_ = std::fs::create_dir_all(&cache_dir);
_ = std::fs::File::create_new(self.rustc_wrapper_args_file());
_ = std::fs::File::create_new(self.link_err_file());
_ = std::fs::File::create_new(self.link_args_file());
_ = std::fs::File::create_new(self.windows_command_file());
if !matches!(ctx.mode, BuildMode::Thin { .. }) {
self.prepare_build_dir()?;
}
if self.bundle == BundleFormat::Server {
return Ok(());
}
// Run the tailwind build before bundling anything else
_ = crate::TailwindCli::run_once(
self.package_manifest_dir(),
self.config.application.tailwind_input.clone(),
self.config.application.tailwind_output.clone(),
)
.await;
// We want to copy over the prebuilt OpenSSL binaries to ~/.dx/prebuilt/openssl-<version>
if self.bundle == BundleFormat::Android {
AndroidTools::unpack_prebuilt_openssl()?;
}
Ok(())
}
pub(crate) async fn build(&self, ctx: &BuildContext) -> Result<BuildArtifacts> {
let time_start = SystemTime::now();
@@ -862,9 +857,6 @@ impl BuildRequest {
// We need to make sure to not react to this though, so the filemap must cache it
_ = self.bust_fingerprint(ctx);
// Run any pre-build steps like tailwind, etc
self.prebuild().await?;
// Run the cargo build to produce our artifacts
let mut artifacts = self.cargo_build(ctx).await?;
@@ -908,7 +900,7 @@ impl BuildRequest {
// Populate the patch cache if we're in fat mode
if matches!(ctx.mode, BuildMode::Fat) {
artifacts.patch_cache = Some(Arc::new(self.create_patch_cache(&artifacts.exe).await?));
artifacts.patch_cache = Some(Arc::new(self.create_patch_cache(&artifacts.exe)?));
}
// Calculate some final metadata for logging
@@ -947,13 +939,13 @@ impl BuildRequest {
// "Thin" builds only build the final exe, so we only need to build one crate
let crate_count = match ctx.mode {
BuildMode::Thin { .. } => 1,
_ => self.get_unit_count_estimate(ctx).await,
_ => self.get_unit_count_estimate(&ctx.mode).await,
};
// Update the status to show that we're starting the build and how many crates we expect to build
ctx.status_starting_build(crate_count);
let mut cmd = self.build_command(ctx)?;
let mut cmd = self.build_command(&ctx.mode)?;
tracing::debug!(dx_src = ?TraceSrc::Build, "Executing cargo for {} using {}", self.bundle, self.triple);
let mut child = cmd
@@ -1049,14 +1041,14 @@ impl BuildRequest {
// Accumulate the rustc args from the wrapper, if they exist and can be parsed.
let mut direct_rustc = RustcArgs::default();
if let Ok(res) = std::fs::read_to_string(self.rustc_wrapper_args_file.path()) {
if let Ok(res) = std::fs::read_to_string(self.rustc_wrapper_args_file()) {
if let Ok(res) = serde_json::from_str(&res) {
direct_rustc = res;
}
}
// If there's any warnings from the linker, we should print them out
if let Ok(linker_warnings) = std::fs::read_to_string(self.link_err_file.path()) {
if let Ok(linker_warnings) = std::fs::read_to_string(self.link_err_file()) {
if !linker_warnings.is_empty() {
if output_location.is_none() {
tracing::error!("Linker warnings: {}", linker_warnings);
@@ -1067,7 +1059,7 @@ impl BuildRequest {
}
// Collect the linker args from the and update the rustc args
direct_rustc.link_args = std::fs::read_to_string(self.link_args_file.path())
direct_rustc.link_args = std::fs::read_to_string(self.link_args_file())
.context("Failed to read link args from file")?
.lines()
.map(|s| s.to_string())
@@ -1077,8 +1069,9 @@ impl BuildRequest {
// Fat builds need to be linked with the fat linker. Would also like to link here for thin builds
if matches!(ctx.mode, BuildMode::Fat) {
ctx.status_starting_link();
let link_start = SystemTime::now();
self.run_fat_link(ctx, &exe, &direct_rustc).await?;
self.run_fat_link(&exe, &direct_rustc).await?;
tracing::debug!(
"Fat linking completed in {}us",
SystemTime::now()
@@ -1109,6 +1102,7 @@ impl BuildRequest {
assets,
mode,
depinfo,
root_dir: self.root_dir(),
patch_cache: None,
})
}
@@ -1425,13 +1419,7 @@ impl BuildRequest {
) -> Result<()> {
ctx.status_hotpatching();
tracing::debug!(
"Original builds for patch: {}",
self.link_args_file.path().display()
);
let raw_args = std::fs::read_to_string(self.link_args_file.path())
.context("Failed to read link args from file")?;
let args = raw_args.lines().collect::<Vec<_>>();
let args = artifacts.direct_rustc.link_args.clone();
// Extract out the incremental object files.
//
@@ -1551,9 +1539,9 @@ impl BuildRequest {
.iter()
.map(|s| format!("\"{}\"", s.to_string_lossy()))
.join(" ");
std::fs::write(self.command_file.path(), cmd_contents)
std::fs::write(self.windows_command_file(), cmd_contents)
.context("Failed to write linker command file")?;
out_args = vec![format!("@{}", self.command_file.path().display()).into()];
out_args = vec![format!("@{}", self.windows_command_file().display()).into()];
}
// Run the linker directly!
@@ -1589,7 +1577,7 @@ impl BuildRequest {
// Fortunately, this binary exists in two places - the deps dir and the target out dir. We
// can just remove the one in the deps dir and the problem goes away.
if let Some(idx) = args.iter().position(|arg| *arg == "-o") {
_ = std::fs::remove_file(PathBuf::from(args[idx + 1]));
_ = std::fs::remove_file(PathBuf::from(args[idx + 1].as_str()));
}
// Now extract the assets from the fat binary
@@ -1614,7 +1602,7 @@ impl BuildRequest {
///
/// This is basically just stripping away the rlibs and other libraries that will be satisfied
/// by our stub step.
fn thin_link_args(&self, original_args: &[&str]) -> Result<Vec<String>> {
fn thin_link_args(&self, original_args: &[String]) -> Result<Vec<String>> {
let mut out_args = vec![];
match self.linker_flavor() {
@@ -1828,14 +1816,7 @@ impl BuildRequest {
///
/// todo: I think we can traverse our immediate dependencies and inspect their symbols, unless they `pub use` a crate
/// todo: we should try and make this faster with memmapping
pub(crate) async fn run_fat_link(
&self,
ctx: &BuildContext,
exe: &Path,
rustc_args: &RustcArgs,
) -> Result<()> {
ctx.status_starting_link();
pub(crate) async fn run_fat_link(&self, exe: &Path, rustc_args: &RustcArgs) -> Result<()> {
// Filter out the rlib files from the arguments
let rlibs = rustc_args
.link_args
@@ -2078,9 +2059,9 @@ impl BuildRequest {
let mut out_args = args.clone();
if cfg!(windows) {
let cmd_contents: String = out_args.iter().map(|f| format!("\"{f}\"")).join(" ");
std::fs::write(self.command_file.path(), cmd_contents)
std::fs::write(self.windows_command_file(), cmd_contents)
.context("Failed to write linker command file")?;
out_args = vec![format!("@{}", self.command_file.path().display())];
out_args = vec![format!("@{}", self.windows_command_file().display())];
}
// Run the linker directly!
@@ -2226,8 +2207,8 @@ impl BuildRequest {
///
/// When processing the output of this command, you need to make sure to handle both cases which
/// both have different formats (but with json output for both).
fn build_command(&self, ctx: &BuildContext) -> Result<Command> {
match &ctx.mode {
fn build_command(&self, build_mode: &BuildMode) -> Result<Command> {
match build_mode {
// We're assembling rustc directly, so we need to be *very* careful. Cargo sets rustc's
// env up very particularly, and we want to match it 1:1 but with some changes.
//
@@ -2248,7 +2229,7 @@ impl BuildRequest {
cmd.env_remove("RUSTC_WRAPPER");
cmd.env_remove(DX_RUSTC_WRAPPER_ENV_VAR);
cmd.envs(
self.cargo_build_env_vars(ctx)?
self.cargo_build_env_vars(build_mode)?
.iter()
.map(|(k, v)| (k.as_ref(), v)),
);
@@ -2276,12 +2257,12 @@ impl BuildRequest {
_ => {
let mut cmd = Command::new("cargo");
let env = self.cargo_build_env_vars(ctx)?;
let args = self.cargo_build_arguments(ctx);
let env = self.cargo_build_env_vars(build_mode)?;
let args = self.cargo_build_arguments(build_mode);
tracing::trace!("Building with cargo rustc");
for e in env.iter() {
tracing::trace!(": {}={}", e.0, e.1);
tracing::trace!(": {}={}", e.0, e.1.to_string_lossy());
}
for a in args.iter() {
@@ -2295,11 +2276,11 @@ impl BuildRequest {
.args(args)
.envs(env.iter().map(|(k, v)| (k.as_ref(), v)));
if matches!(ctx.mode, BuildMode::Fat | BuildMode::Base { run: true }) {
if matches!(build_mode, BuildMode::Fat | BuildMode::Base { run: true }) {
cmd.env(
DX_RUSTC_WRAPPER_ENV_VAR,
dunce::canonicalize(self.rustc_wrapper_args_file.path())
.unwrap()
dunce::canonicalize(self.rustc_wrapper_args_file())
.context("Failed to canonicalize rustc wrapper args file")?
.display()
.to_string(),
);
@@ -2319,7 +2300,7 @@ impl BuildRequest {
/// We always use `cargo rustc` *or* `rustc` directly. This means we can pass extra flags like
/// `-C` arguments directly to the compiler.
#[allow(clippy::vec_init_then_push)]
fn cargo_build_arguments(&self, ctx: &BuildContext) -> Vec<String> {
pub(crate) fn cargo_build_arguments(&self, build_mode: &BuildMode) -> Vec<String> {
let mut cargo_args = Vec::with_capacity(4);
// Set the `--config profile.{profile}.{key}={value}` flags for the profile, filling in adhoc profile
@@ -2383,7 +2364,7 @@ impl BuildRequest {
// dx *always* links android and thin builds
if self.custom_linker.is_some()
|| matches!(ctx.mode, BuildMode::Thin { .. } | BuildMode::Fat)
|| matches!(build_mode, BuildMode::Thin { .. } | BuildMode::Fat)
{
cargo_args.push(format!(
"-Clinker={}",
@@ -2420,7 +2401,7 @@ impl BuildRequest {
// We need save-temps and no-dead-strip in both cases though. When we run `cargo rustc` with
// these args, they will be captured and re-ran for the fast compiles in the future, so whatever
// we set here will be set for all future hot patches too.
if matches!(ctx.mode, BuildMode::Thin { .. } | BuildMode::Fat) {
if matches!(build_mode, BuildMode::Thin { .. } | BuildMode::Fat) {
// rustc gives us some portable flags required:
// - link-dead-code: prevents rust from passing -dead_strip to the linker since that's the default.
// - save-temps=true: keeps the incremental object files around, which we need for manually linking.
@@ -2497,7 +2478,10 @@ impl BuildRequest {
cargo_args
}
fn cargo_build_env_vars(&self, ctx: &BuildContext) -> Result<Vec<(Cow<'static, str>, String)>> {
pub(crate) fn cargo_build_env_vars(
&self,
build_mode: &BuildMode,
) -> Result<Vec<(Cow<'static, str>, OsString)>> {
let mut env_vars = vec![];
// Make sure to set all the crazy android flags. Cross-compiling is hard, man.
@@ -2509,10 +2493,13 @@ impl BuildRequest {
// todo: should we even be doing this? might be better being a build.rs or something else.
if self.release {
if let Some(base_path) = self.base_path() {
env_vars.push((ASSET_ROOT_ENV.into(), base_path.to_string()));
env_vars.push((ASSET_ROOT_ENV.into(), base_path.to_string().into()));
}
env_vars.push((APP_TITLE_ENV.into(), self.config.web.app.title.clone()));
env_vars.push((PRODUCT_NAME_ENV.into(), self.bundled_app_name()));
env_vars.push((
APP_TITLE_ENV.into(),
self.config.web.app.title.clone().into(),
));
env_vars.push((PRODUCT_NAME_ENV.into(), self.bundled_app_name().into()));
}
// Assemble the rustflags by peering into the `.cargo/config.toml` file
@@ -2520,7 +2507,7 @@ impl BuildRequest {
// Disable reference types on wasm when using hotpatching
// https://blog.rust-lang.org/2024/09/24/webassembly-targets-change-in-default-target-features/#disabling-on-by-default-webassembly-proposals
if self.is_wasm_or_wasi() && matches!(ctx.mode, BuildMode::Thin { .. } | BuildMode::Fat) {
if self.is_wasm_or_wasi() && matches!(build_mode, BuildMode::Thin { .. } | BuildMode::Fat) {
rust_flags.flags.push("-Ctarget-cpu=mvp".to_string());
}
@@ -2530,19 +2517,20 @@ impl BuildRequest {
"RUSTFLAGS".into(),
rust_flags
.encode_space_separated()
.context("Failed to encode RUSTFLAGS")?,
.context("Failed to encode RUSTFLAGS")?
.into(),
));
}
// If we're either zero-linking or using a custom linker, make `dx` itself do the linking.
if self.custom_linker.is_some()
|| matches!(ctx.mode, BuildMode::Thin { .. } | BuildMode::Fat)
|| matches!(build_mode, BuildMode::Thin { .. } | BuildMode::Fat)
{
LinkAction {
triple: self.triple.clone(),
linker: self.custom_linker.clone(),
link_err_file: dunce::canonicalize(self.link_err_file.path())?,
link_args_file: dunce::canonicalize(self.link_args_file.path())?,
link_err_file: dunce::canonicalize(self.link_err_file())?,
link_args_file: dunce::canonicalize(self.link_args_file())?,
}
.write_env_vars(&mut env_vars)?;
}
@@ -2563,7 +2551,7 @@ impl BuildRequest {
/// cargo-ndk is MIT licensed.
///
/// <https://github.com/bbqsrc/cargo-ndk>
fn android_env_vars(&self) -> Result<Vec<(Cow<'static, str>, String)>> {
fn android_env_vars(&self) -> Result<Vec<(Cow<'static, str>, OsString)>> {
// Derived from getenv_with_target_prefixes in `cc` crate.
fn cc_env(var_base: &str, triple: &str) -> (String, Option<String>) {
#[inline]
@@ -2611,7 +2599,7 @@ impl BuildRequest {
}) as _
}
let mut env_vars: Vec<(Cow<'static, str>, String)> = vec![];
let mut env_vars: Vec<(Cow<'static, str>, OsString)> = vec![];
let min_sdk_version = self.min_sdk_version_or_default();
@@ -2635,7 +2623,7 @@ impl BuildRequest {
if let Some(java_home) = java_home {
tracing::debug!("Setting JAVA_HOME to {java_home:?}");
env_vars.push(("JAVA_HOME".into(), java_home.display().to_string()));
env_vars.push(("JAVA_HOME".into(), java_home.into_os_string()));
}
let triple = self.triple.to_string();
@@ -2786,13 +2774,7 @@ impl BuildRequest {
// https://github.com/KyleMayes/clang-sys?tab=readme-ov-file#environment-variables
("CLANG_PATH".into(), target_cc.with_extension("exe").into()),
] {
env_vars.push((
env.0.into(),
env.1
.to_str()
.expect("Failed to convert env var value to string")
.to_string(),
));
env_vars.push((env.0.into(), env.1));
}
if std::env::var("MSYSTEM").is_ok() || std::env::var("CYGWIN").is_ok() {
@@ -2800,7 +2782,7 @@ impl BuildRequest {
// Convert windows paths to unix-style paths
// This is a workaround for the fact that the `cc` crate expects unix-style paths
// and will fail if it encounters windows-style paths.
var.1 = var.1.replace('\\', "/");
var.1 = var.1.to_string_lossy().replace('\\', "/").into();
}
}
@@ -2811,9 +2793,9 @@ impl BuildRequest {
/// will return an estimate of the number of units in the crate based on cargo metadata.
///
/// TODO: always use <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#unit-graph> once it is stable
async fn get_unit_count_estimate(&self, ctx: &BuildContext) -> usize {
async fn get_unit_count_estimate(&self, build_mode: &BuildMode) -> usize {
// Try to get it from nightly
if let Ok(count) = self.get_unit_count(ctx).await {
if let Ok(count) = self.get_unit_count(build_mode).await {
return count;
}
@@ -2833,7 +2815,7 @@ impl BuildRequest {
/// available with the current version of rustc the user has installed.
///
/// It also might not be super reliable - I think in practice it occasionally returns 2x the units.
async fn get_unit_count(&self, ctx: &BuildContext) -> crate::Result<usize> {
async fn get_unit_count(&self, build_mode: &BuildMode) -> crate::Result<usize> {
#[derive(Debug, Deserialize)]
struct UnitGraph {
units: Vec<serde_json::Value>,
@@ -2845,9 +2827,9 @@ impl BuildRequest {
.arg("--unit-graph")
.arg("-Z")
.arg("unstable-options")
.args(self.cargo_build_arguments(ctx))
.args(self.cargo_build_arguments(build_mode))
.envs(
self.cargo_build_env_vars(ctx)?
self.cargo_build_env_vars(build_mode)?
.iter()
.map(|(k, v)| (k.as_ref(), v)),
)
@@ -3180,7 +3162,23 @@ impl BuildRequest {
///
/// The directory is specific for this app and might be
pub(crate) fn session_cache_dir(&self) -> PathBuf {
self.session_cache_dir.path().to_path_buf()
self.session_cache_dir.join(self.bundle.to_string())
}
pub(crate) fn rustc_wrapper_args_file(&self) -> PathBuf {
self.session_cache_dir().join("rustc_wrapper_args.txt")
}
fn link_err_file(&self) -> PathBuf {
self.session_cache_dir().join("link_err.txt")
}
fn link_args_file(&self) -> PathBuf {
self.session_cache_dir().join("link_args.json")
}
fn windows_command_file(&self) -> PathBuf {
self.session_cache_dir().join("windows_command.txt")
}
/// Get the outdir specified by the Dioxus.toml, relative to the crate directory.
@@ -4120,8 +4118,6 @@ __wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{
_ = remove_dir_all(self.exe_dir());
}
self.flush_session_cache();
create_dir_all(self.root_dir())?;
create_dir_all(self.exe_dir())?;
create_dir_all(self.asset_dir())?;
@@ -4233,12 +4229,6 @@ __wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{
self.platform_dir().join(".cli-version")
}
fn flush_session_cache(&self) {
let cache_dir = self.session_cache_dir();
_ = std::fs::remove_dir_all(&cache_dir);
_ = std::fs::create_dir_all(&cache_dir);
}
/// Check for tooling that might be required for this build.
///
/// This should generally be only called on the first build since it takes time to verify the tooling
@@ -4433,13 +4423,18 @@ __wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{
Ok(())
}
async fn create_patch_cache(&self, exe: &Path) -> Result<HotpatchModuleCache> {
let exe = match self.bundle {
pub(crate) fn patch_cache_exe(&self, exe: &Path) -> PathBuf {
match self.bundle {
BundleFormat::Web => self.wasm_bindgen_wasm_output_file(),
_ => exe.to_path_buf(),
};
}
}
Ok(HotpatchModuleCache::new(&exe, &self.triple)?)
pub(crate) fn create_patch_cache(&self, exe: &Path) -> Result<HotpatchModuleCache> {
Ok(HotpatchModuleCache::new(
&self.patch_cache_exe(exe),
&self.triple,
)?)
}
/// Users create an index.html for their SPA if they want it
@@ -4850,27 +4845,6 @@ __wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{
.collect()
}
async fn prebuild(&self) -> Result<()> {
if self.bundle == BundleFormat::Server {
return Ok(());
}
// Run the tailwind build before bundling anything else
crate::TailwindCli::run_once(
self.package_manifest_dir(),
self.config.application.tailwind_input.clone(),
self.config.application.tailwind_output.clone(),
)
.await?;
// We want to copy over the prebuilt OpenSSL binaries to ~/.dx/prebuilt/openssl-<version>
if self.bundle == BundleFormat::Android {
AndroidTools::unpack_prebuilt_openssl()?;
}
Ok(())
}
pub async fn codesign_ios(&self) -> Result<()> {
// We don't want to drop the entitlements file, until the end of the block, so we hoist it to this temporary.
let mut _saved_entitlements = None;