CLI: add --renderer argument (#4320)

* Add --renderer argument to the CLI

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Make `--platform native` work

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Emit `krates` error when cargo metadata fails

* Reinstate default "desktop" feature for examples

* Remove commented 'no platform specified' error

Signed-off-by: Nico Burns <nico@nicoburns.com>

* use the target tripple and bundle format as the source of truth for the build

* resolve renderer and bundle format

* add shorthand flags

* add headings to the help for shorthands

* resolve the renderer from the target triple if it isn't passed

* make value after --fullstack optional

* convert desktop -> mobile when targeting mobile webview

* use the new shorthand flags in the playwright tests

* fix clippy

* merge fix

* cleanup merge conflicts

* fix clippy

* remove nit

* restore platform as a legacy argument

* improve help message

* vendor openssl on native, pin server_fn

* print build errors as warnings

* add --desktop arg compat

* adjust cli headings

* prefer self.is_wasm_or_wasi()

---------

Signed-off-by: Nico Burns <nico@nicoburns.com>
Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
Co-authored-by: Evan Almloff <evanalmloff@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-07-22 14:32:54 -07:00
1 parent 4848e714ae
commit b257e7e8ce
28 files changed
+998 -549

No files matched your search

+41 -41
View File
@@ -1,5 +1,5 @@
use crate::{
serve::WebServer, BuildArtifacts, BuildRequest, BuildStage, BuilderUpdate, Platform,
serve::WebServer, BuildArtifacts, BuildRequest, BuildStage, BuilderUpdate, BundleFormat,
ProgressRx, ProgressTx, Result, RustcArgs, StructuredOutput,
};
use anyhow::{bail, Context};
@@ -16,6 +16,7 @@ use std::{
process::Stdio,
};
use subsecond_types::JumpTable;
use target_lexicon::Architecture;
use tokio::{
io::{AsyncBufReadExt, BufReader, Lines},
process::{Child, ChildStderr, ChildStdout, Command},
@@ -189,7 +190,7 @@ impl AppBuilder {
match bundle {
Ok(Ok(bundle)) => BuilderUpdate::BuildReady { bundle },
Ok(Err(err)) => BuilderUpdate::BuildFailed { err },
Err(err) => BuilderUpdate::BuildFailed { err: anyhow::anyhow!("Build panicked! {:#?}", err) },
Err(err) => BuilderUpdate::BuildFailed { err: anyhow::anyhow!("Build panicked! {err:#?}") },
}
},
Some(Ok(Some(msg))) = OptionFuture::from(self.stdout.as_mut().map(|f| f.next_line())) => {
@@ -300,7 +301,13 @@ impl AppBuilder {
// for all other platforms, we need to use the ASLR reference to know where to insert the patch.
let aslr_reference = match self.aslr_reference {
Some(val) => val,
None if self.build.platform == Platform::Web => 0,
None if matches!(
self.build.triple.architecture,
Architecture::Wasm32 | Architecture::Wasm64
) =>
{
0
}
None => {
tracing::warn!(
"Ignoring hotpatch since there is no ASLR reference. Is the client connected?"
@@ -542,18 +549,18 @@ impl AppBuilder {
);
// We try to use stdin/stdout to communicate with the app
match self.build.platform {
match self.build.bundle {
// Unfortunately web won't let us get a proc handle to it (to read its stdout/stderr) so instead
// use use the websocket to communicate with it. I wish we could merge the concepts here,
// like say, opening the socket as a subprocess, but alas, it's simpler to do that somewhere else.
Platform::Web => {
BundleFormat::Web => {
// Only the first build we open the web app, after that the user knows it's running
if open_browser {
self.open_web(open_address.unwrap_or(devserver_ip));
}
}
Platform::Ios => {
BundleFormat::Ios => {
if self.build.device {
self.codesign_ios().await?;
self.open_ios_device().await?
@@ -562,16 +569,15 @@ impl AppBuilder {
}
}
Platform::Android => {
BundleFormat::Android => {
self.open_android_sim(false, devserver_ip, envs).await?;
}
// These are all just basically running the main exe, but with slightly different resource dir paths
Platform::Server
| Platform::MacOS
| Platform::Windows
| Platform::Linux
| Platform::Liveview => self.open_with_main_exe(envs, args)?,
BundleFormat::Server
| BundleFormat::MacOS
| BundleFormat::Windows
| BundleFormat::Linux => self.open_with_main_exe(envs, args)?,
};
self.builds_opened += 1;
@@ -661,7 +667,7 @@ impl AppBuilder {
}
// If the emulator is android, we need to copy the asset to the device with `adb push asset /data/local/tmp/dx/assets/filename.ext`
if self.build.platform == Platform::Android {
if self.build.bundle == BundleFormat::Android {
let bundled_name = PathBuf::from(bundled.bundled_path());
_ = self.copy_file_to_android_tmp(&from, &bundled_name).await;
}
@@ -684,7 +690,7 @@ impl AppBuilder {
let mut jump_table = crate::build::create_jump_table(&new, &triple, cache)?;
// If it's android, we need to copy the assets to the device and then change the location of the patch
if self.build.platform == Platform::Android {
if self.build.bundle == BundleFormat::Android {
jump_table.lib = self
.copy_file_to_android_tmp(&new, &(PathBuf::from(new.file_name().unwrap())))
.await?;
@@ -777,7 +783,7 @@ impl AppBuilder {
}
// If the emulator is android, we need to copy the asset to the device with `adb push asset /data/local/tmp/dx/assets/filename.ext`
if self.build.platform == Platform::Android {
if self.build.bundle == BundleFormat::Android {
_ = self
.copy_file_to_android_tmp(&changed_file, &bundled_name)
.await;
@@ -972,7 +978,7 @@ impl AppBuilder {
.await?;
if !output.status.success() {
bail!("Failed to install app: {:?}", output);
bail!("Failed to install app: {output:?}");
}
let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?)
@@ -1007,7 +1013,7 @@ impl AppBuilder {
.await?;
if !output.status.success() {
bail!("Failed to launch app: {:?}", output);
bail!("Failed to launch app: {output:?}");
}
let json: Value = serde_json::from_str(&std::fs::read_to_string(tmpfile.path())?)
@@ -1032,7 +1038,7 @@ impl AppBuilder {
.await?;
if !output.status.success() {
bail!("Failed to resume app: {:?}", output);
bail!("Failed to resume app: {output:?}");
}
Ok(())
@@ -1255,8 +1261,8 @@ We checked the folders:
let port = devserver_socket.port();
if let Err(e) = Command::new(&adb)
.arg("reverse")
.arg(format!("tcp:{}", port))
.arg(format!("tcp:{}", port))
.arg(format!("tcp:{port}"))
.arg(format!("tcp:{port}"))
.output()
.await
{
@@ -1362,18 +1368,14 @@ We checked the folders:
let mut main_exe = self.build.main_exe();
// The requirement here is based on the platform, not necessarily our current architecture.
let requires_entropy = match self.build.platform {
let requires_entropy = match self.build.bundle {
// When running "bundled", we don't need entropy
Platform::Web => false,
Platform::MacOS => false,
Platform::Ios => false,
Platform::Android => false,
BundleFormat::Web | BundleFormat::MacOS | BundleFormat::Ios | BundleFormat::Android => {
false
}
// But on platforms that aren't running as "bundled", we do.
Platform::Windows => true,
Platform::Linux => true,
Platform::Server => true,
Platform::Liveview => true,
BundleFormat::Windows | BundleFormat::Linux | BundleFormat::Server => true,
};
if requires_entropy || crate::devcfg::should_force_entropy() {
@@ -1443,24 +1445,22 @@ We checked the folders:
}
pub(crate) async fn open_debugger(&mut self, server: &WebServer) -> Result<()> {
let url = match self.build.platform {
Platform::MacOS
| Platform::Windows
| Platform::Linux
| Platform::Server
| Platform::Liveview => {
let url = match self.build.bundle {
BundleFormat::MacOS
| BundleFormat::Windows
| BundleFormat::Linux
| BundleFormat::Server => {
let Some(Some(pid)) = self.child.as_mut().map(|f| f.id()) else {
tracing::warn!("No process to attach debugger to");
return Ok(());
};
format!(
"vscode://vadimcn.vscode-lldb/launch/config?{{'request':'attach','pid':{}}}",
pid
"vscode://vadimcn.vscode-lldb/launch/config?{{'request':'attach','pid':{pid}}}"
)
}
Platform::Web => {
BundleFormat::Web => {
// code --open-url "vscode://DioxusLabs.dioxus/debugger?uri=http://127.0.0.1:8080"
// todo - debugger could open to the *current* page afaik we don't have a way to have that info
let address = server.devserver_address();
@@ -1474,7 +1474,7 @@ We checked the folders:
format!("vscode://DioxusLabs.dioxus/debugger?uri={protocol}://{address}{base_path}")
}
Platform::Ios => {
BundleFormat::Ios => {
let Some(pid) = self.pid else {
tracing::warn!("No process to attach debugger to");
return Ok(());
@@ -1513,7 +1513,7 @@ We checked the folders:
// (lldb) settings append target.exec-search-paths target/dx/tw6/debug/android/app/app/src/main/jniLibs/arm64-v8a/libdioxusmain.so
// (lldb) process handle SIGSEGV --pass true --stop false --notify true (otherwise the java threads cause crash)
//
Platform::Android => {
BundleFormat::Android => {
// adb push ./sdk/ndk/29.0.13113456/toolchains/llvm/prebuilt/darwin-x86_64/lib/clang/20/lib/linux/aarch64/lldb-server /tmp
// adb shell "/tmp/lldb-server --server --listen ..."
// "vscode://vadimcn.vscode-lldb/launch/config?{{'request':'connect','port': {}}}",
@@ -1601,7 +1601,7 @@ We checked the folders:
}
};
tracing::info!("Opening debugger for [{}]: {url}", self.build.platform);
tracing::info!("Opening debugger for [{}]: {url}", self.build.bundle);
_ = tokio::process::Command::new("code")
.arg("--open-url")
+1 -1
View File
@@ -105,7 +105,7 @@ impl BuildContext {
}
pub(crate) fn status_build_error(&self, line: String) {
tracing::debug!(dx_src = ?TraceSrc::Cargo, "{line}");
tracing::warn!(dx_src = ?TraceSrc::Cargo, "{line}");
}
pub(crate) fn status_build_message(&self, line: String) {
+2 -2
View File
@@ -775,7 +775,7 @@ pub fn create_undefined_symbol_stub(
let mut defined_symbols = HashSet::new();
for path in sorted {
let bytes = std::fs::read(path).with_context(|| format!("failed to read {:?}", path))?;
let bytes = std::fs::read(path).with_context(|| format!("failed to read {path:?}"))?;
let file = File::parse(bytes.deref() as &[u8])?;
for symbol in file.symbols() {
if symbol.is_undefined() {
@@ -853,7 +853,7 @@ pub fn create_undefined_symbol_stub(
if aslr_reference < aslr_ref_address {
return Err(PatchError::InvalidModule(
format!(
"ASLR reference is less than the main module's address - is there a `main`?. {:x} < {:x}", aslr_reference, aslr_ref_address )
"ASLR reference is less than the main module's address - is there a `main`?. {aslr_reference:x} < {aslr_ref_address:x}" )
));
}
File diff suppressed because it is too large. Load diff