diff --git a/Cargo.lock b/Cargo.lock index 701f000..1ad1773 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ dependencies = [ ] [[package]] -name = "cargo-3ds" +name = "cargo-nds" version = "0.1.2" dependencies = [ "cargo_metadata", @@ -91,15 +91,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", + "thiserror", ] [[package]] @@ -149,6 +150,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.8" @@ -159,12 +166,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.9" @@ -184,19 +207,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] -name = "proc-macro2" -version = "1.0.70" +name = "memchr" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" + +[[package]] +name = "proc-macro2" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -269,6 +298,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "shlex" version = "1.2.0" @@ -283,9 +321,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -309,12 +347,57 @@ dependencies = [ ] [[package]] -name = "toml" -version = "0.5.11" +name = "thiserror" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -460,3 +543,12 @@ name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index de30cce..b12696b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,22 @@ [package] -name = "cargo-3ds" +name = "cargo-nds" version = "0.1.2" -authors = ["Rust3DS Org", "Andrea Ciliberti "] -description = "Cargo wrapper for developing Nintendo 3DS homebrew apps" -repository = "https://github.com/rust3ds/cargo-3ds" -keywords = ["3ds", "homebrew"] +authors = ["Rustnds Org", "Andrea Ciliberti "] +description = "Cargo wrapper for developing Nintendo nds homebrew apps" +repository = "https://github.com/rustnds/cargo-nds" +keywords = ["nds", "homebrew"] categories = ["command-line-utilities", "development-tools::cargo-plugins"] exclude = [".github"] license = "MIT OR Apache-2.0" edition = "2021" [dependencies] -cargo_metadata = "0.14.0" +cargo_metadata = "0.18.1" rustc_version = "0.4.0" semver = "1.0.10" serde = { version = "1.0.139", features = ["derive"] } tee = "0.1.0" -toml = "0.5.6" +toml = "0.8.12" clap = { version = "4.0.15", features = ["derive", "wrap_help"] } shlex = "1.1.0" serde_json = "1.0.108" diff --git a/src/command.rs b/src/command.rs index 02f998f..ed3f5c7 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{env, fs}; use std::io::Read; use std::process::Stdio; use std::sync::OnceLock; @@ -6,12 +6,12 @@ use std::sync::OnceLock; use cargo_metadata::Message; use clap::{Args, Parser, Subcommand}; -use crate::{build_3dsx, build_smdh, cargo, get_metadata, link, print_command, CTRConfig}; +use crate::{build_nds, cargo, get_metadata, link, print_command, NDSConfig}; #[derive(Parser, Debug)] #[command(name = "cargo", bin_name = "cargo")] pub enum Cargo { - #[command(name = "3ds")] + #[command(name = "nds")] Input(Input), } @@ -21,7 +21,7 @@ pub struct Input { #[command(subcommand)] pub cmd: CargoCmd, - /// Print the exact commands `cargo-3ds` is running. Note that this does not + /// Print the exact commands `cargo-nds` is running. Note that this does not /// set the verbose flag for cargo itself. To set cargo's verbosity flag, add /// `-- -v` to the end of the command line. #[arg(long, short = 'v', global = true)] @@ -34,32 +34,32 @@ pub struct Input { } /// Run a cargo command. COMMAND will be forwarded to the real -/// `cargo` with the appropriate arguments for the 3DS target. +/// `cargo` with the appropriate arguments for the nds target. /// /// If an unrecognized COMMAND is used, it will be passed through unmodified -/// to `cargo` with the appropriate flags set for the 3DS target. +/// to `cargo` with the appropriate flags set for the nds target. #[derive(Subcommand, Debug)] #[command(allow_external_subcommands = true)] pub enum CargoCmd { - /// Builds an executable suitable to run on a 3DS (3dsx). + /// Builds an executable suitable to run on a DS (nds). Build(Build), - /// Builds an executable and sends it to a device with `3dslink`. + /// Builds an executable and sends it to a device with `dslink`. Run(Run), - /// Builds a test executable and sends it to a device with `3dslink`. + /// Builds a test executable and sends it to a device with `dslink`. /// /// This can be used with `--test` for integration tests, or `--lib` for /// unit tests (which require a custom test runner). Test(Test), - /// Sets up a new cargo project suitable to run on a 3DS. + /// Sets up a new cargo project suitable to run on a DS. New(New), // NOTE: it seems docstring + name for external subcommands are not rendered // in help, but we might as well set them here in case a future version of clap // does include them in help text. - /// Run any other `cargo` command with custom building tailored for the 3DS. + /// Run any other `cargo` command with custom building tailored for the nds. #[command(external_subcommand, name = "COMMAND")] Passthrough(Vec), } @@ -73,7 +73,7 @@ pub struct RemainingArgs { /// /// To pass arguments to an executable being run, a *second* `--` must be /// used to disambiguate cargo arguments from executable arguments. - /// For example, `cargo 3ds run -- -- xyz` runs an executable with the argument + /// For example, `cargo nds run -- -- xyz` runs an executable with the argument /// `xyz`. #[arg( trailing_var_arg = true, @@ -97,23 +97,23 @@ pub struct Build { pub struct Run { /// Specify the IP address of the device to send the executable to. /// - /// Corresponds to 3dslink's `--address` arg, which defaults to automatically + /// Corresponds to ndslink's `--address` arg, which defaults to automatically /// finding the device. #[arg(long, short = 'a')] pub address: Option, /// Set the 0th argument of the executable when running it. Corresponds to - /// 3dslink's `--argv0` argument. + /// ndslink's `--argv0` argument. #[arg(long, short = '0')] pub argv0: Option, - /// Start the 3dslink server after sending the executable. Corresponds to - /// 3dslink's `--server` argument. + /// Start the ndslink server after sending the executable. Corresponds to + /// ndslink's `--server` argument. #[arg(long, short = 's', default_value_t = false)] pub server: bool, /// Set the number of tries when connecting to the device to send the executable. - /// Corresponds to 3dslink's `--retries` argument. + /// Corresponds to ndslink's `--retries` argument. // Can't use `short = 'r'` because that would conflict with cargo's `--release/-r` #[arg(long)] pub retries: Option, @@ -133,7 +133,7 @@ pub struct Test { pub no_run: bool, /// If set, documentation tests will be built instead of unit tests. - /// This implies `--no-run`, unless Cargo's `target.armv6k-nintendo-3ds.runner` + /// This implies `--no-run`, unless Cargo's `target.armv6k-nintendo-nds.runner` /// is configured. #[arg(long)] pub doc: bool, @@ -158,7 +158,7 @@ impl CargoCmd { /// Returns the additional arguments run by the "official" cargo subcommand. pub fn cargo_args(&self) -> Vec { match self { - CargoCmd::Build(build) => build.passthrough.cargo_args(), + CargoCmd::Build(build) =>build.passthrough.cargo_args(), CargoCmd::Run(run) => run.build_args.passthrough.cargo_args(), CargoCmd::Test(test) => test.cargo_args(), CargoCmd::New(new) => { @@ -172,7 +172,7 @@ impl CargoCmd { } } - /// Returns the cargo subcommand run by `cargo-3ds` when handling a [`CargoCmd`]. + /// Returns the cargo subcommand run by `cargo-nds` when handling a [`CargoCmd`]. /// /// # Notes /// @@ -203,13 +203,13 @@ impl CargoCmd { ) } - /// Whether or not this command should build a 3DSX executable file. - pub fn should_build_3dsx(&self) -> bool { + /// Whether or not this command should build a ndsX executable file. + pub fn should_build_ndsx(&self) -> bool { match self { Self::Build(_) | CargoCmd::Run(_) => true, &Self::Test(Test { doc, .. }) => { if doc { - eprintln!("Documentation tests requested, no 3dsx will be built"); + eprintln!("Documentation tests requested, no ndsx will be built"); false } else { true @@ -219,8 +219,8 @@ impl CargoCmd { } } - /// Whether or not the resulting executable should be sent to the 3DS with - /// `3dslink`. + /// Whether or not the resulting executable should be sent to the nds with + /// `ndslink`. pub fn should_link_to_device(&self) -> bool { match self { Self::Test(Test { no_run: true, .. }) => false, @@ -247,7 +247,7 @@ impl CargoCmd { if let Self::Test(Test { doc: true, .. }) = self { // We don't care about JSON output for doctests since we're not - // building any 3dsx etc. Just use the default output as it's more + // building any ndsx etc. Just use the default output as it's more // readable compared to DEFAULT_MESSAGE_FORMAT Ok(Some(String::from("human"))) } else { @@ -293,11 +293,11 @@ impl CargoCmd { /// /// # Examples /// - /// - `cargo 3ds build` and other "build" commands will use their callbacks to build the final `.3dsx` file and link it. - /// - `cargo 3ds new` and other generic commands will use their callbacks to make 3ds-specific changes to the environment. + /// - `cargo nds build` and other "build" commands will use their callbacks to build the final `.ndsx` file and link it. + /// - `cargo nds new` and other generic commands will use their callbacks to make nds-specific changes to the environment. pub fn run_callback(&self, messages: &[Message]) { // Process the metadata only for commands that have it/use it - let config = if self.should_build_3dsx() { + let config = if self.should_build_ndsx() { eprintln!("Getting metadata"); Some(get_metadata(messages)) @@ -343,78 +343,45 @@ impl RemainingArgs { } impl Build { - /// Callback for `cargo 3ds build`. + /// Callback for `cargo nds build`. /// - /// This callback handles building the application as a `.3dsx` file. - fn callback(&self, config: &Option) { + /// This callback handles building the application as a `.ndsx` file. + fn callback(&self, config: &Option) { if let Some(config) = config { - eprintln!("Building smdh: {}", config.path_smdh().display()); - build_smdh(config, self.verbose); - - eprintln!("Building 3dsx: {}", config.path_3dsx().display()); - build_3dsx(config, self.verbose); + eprintln!("Building nds: {}", config.path_nds().display()); + build_nds(config, self.verbose); } } } impl Run { - /// Get the args to pass to `3dslink` based on these options. - pub fn get_3dslink_args(&self) -> Vec { + /// Get the args to pass to `ndslink` based on these options. + pub fn get_dslink_args(&self) -> Vec { let mut args = Vec::new(); if let Some(address) = self.address { - args.extend(["--address".to_string(), address.to_string()]); - } - - if let Some(argv0) = &self.argv0 { - args.extend(["--arg0".to_string(), argv0.clone()]); - } - - if let Some(retries) = self.retries { - args.extend(["--retries".to_string(), retries.to_string()]); - } - - if self.server { - args.push("--server".to_string()); - } - - let exe_args = self.build_args.passthrough.exe_args(); - if !exe_args.is_empty() { - // For some reason 3dslink seems to want 2 instances of `--`, one - // in front of all of the args like this... - args.extend(["--args".to_string(), "--".to_string()]); - - let mut escaped = false; - for arg in exe_args.iter().cloned() { - if arg.starts_with('-') && !escaped { - // And one before the first `-` arg that is passed in. - args.extend(["--".to_string(), arg]); - escaped = true; - } else { - args.push(arg); - } - } + args.extend(["-a".to_string(), address.to_string()]); } args } - /// Callback for `cargo 3ds run`. + /// Callback for `cargo nds run`. /// - /// This callback handles launching the application via `3dslink`. - fn callback(&self, config: &Option) { + /// This callback handles launching the application via `dslink`. + fn callback(&self, config: &Option) { // Run the normal "build" callback self.build_args.callback(config); if !self.use_custom_runner() { if let Some(cfg) = config { - eprintln!("Running 3dslink"); + eprintln!("Running dslink"); link(cfg, self, self.build_args.verbose); } } } - /// Returns whether the cargo environment has `target.armv6k-nintendo-3ds.runner` + /// Returns whether the cargo environment has `target.armv6k-nintendo-nds.runner` /// configured. This will only be checked once during the lifetime of the program, /// and takes into account the usual ways Cargo looks for its /// [configuration](https://doc.rust-lang.org/cargo/reference/config.html): @@ -426,14 +393,16 @@ impl Run { static HAS_RUNNER: OnceLock = OnceLock::new(); let &custom_runner_configured = HAS_RUNNER.get_or_init(|| { + let blocksds = env::var("BLOCKSDS").unwrap_or("/opt/wonderful/thirdparty/blocksds/core".to_owned()); + env::set_var("RUSTFLAGS", format!("-C link-args=-specs={blocksds}/sys/crts/ds_arm9.specs")); + let mut cmd = cargo(&self.config); cmd.args([ // https://github.com/rust-lang/cargo/issues/9301 "-Z", - "unstable-options", - "config", - "get", - "target.armv6k-nintendo-3ds.runner", + "build-std=core,alloc", + "--target", + "./armv5te-nintendo-ds.json" ]) .stdout(Stdio::null()) .stderr(Stdio::null()); @@ -458,10 +427,10 @@ impl Run { } impl Test { - /// Callback for `cargo 3ds test`. + /// Callback for `cargo nds test`. /// - /// This callback handles launching the application via `3dslink`. - fn callback(&self, config: &Option) { + /// This callback handles launching the application via `ndslink`. + fn callback(&self, config: &Option) { if self.no_run { // If the tests don't have to run, use the "build" callback self.run_args.build_args.callback(config); @@ -479,7 +448,7 @@ impl Test { fn cargo_args(&self) -> Vec { let mut cargo_args = self.run_args.build_args.passthrough.cargo_args(); - // We can't run 3DS executables on the host, but we want to respect + // We can't run nds executables on the host, but we want to respect // the user's "runner" configuration if set. // // If doctests were requested, `--no-run` will be rejected on the @@ -512,9 +481,9 @@ impl Test { } } -const TOML_CHANGES: &str = r#"ctru-rs = { git = "https://github.com/rust3ds/ctru-rs" } +const TOML_CHANGES: &str = r#"ctru-rs = { git = "https://github.com/rustnds/ctru-rs" } -[package.metadata.cargo-3ds] +[package.metadata.cargo-nds] romfs_dir = "romfs" "#; @@ -541,9 +510,9 @@ fn main() { "#; impl New { - /// Callback for `cargo 3ds new`. + /// Callback for `cargo nds new`. /// - /// This callback handles the custom environment modifications when creating a new 3DS project. + /// This callback handles the custom environment modifications when creating a new nds project. fn callback(&self) { // Commmit changes to the project only if is meant to be a binary if self.cargo_args.args.contains(&"--lib".to_string()) { @@ -672,7 +641,7 @@ mod tests { expected_exe: &["bar"], }, ] { - let input: Vec<&str> = ["cargo", "3ds", "run"] + let input: Vec<&str> = ["cargo", "nds", "run"] .iter() .chain(param.input) .copied() diff --git a/src/lib.rs b/src/lib.rs index 4d5b47a..8f017f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ use crate::graph::UnitGraph; /// parsing and returning the messages from the spawned process. /// /// For commands that produce an executable output, this function will build the -/// `.elf` binary that can be used to create other 3ds files. +/// `.elf` binary that can be used to create other nds files. pub fn run_cargo(input: &Input, message_format: Option) -> (ExitStatus, Vec) { let mut command = make_cargo_command(input, &message_format); @@ -57,7 +57,7 @@ pub fn run_cargo(input: &Input, message_format: Option) -> (ExitStatus, let buf_reader: &mut dyn BufRead = match (message_format, &input.cmd) { // The user presumably cares about the message format if set, so we should // copy stuff to stdout like they expect. We can still extract the executable - // information out of it that we need for 3dsxtool etc. + // information out of it that we need for ndstool etc. (Some(_), _) | // Rustdoc unfortunately prints to stdout for compile errors, so // we also use a tee when building doc tests too. @@ -104,14 +104,11 @@ fn should_use_ctru_debuginfo(cargo_cmd: &Command, verbose: bool) -> bool { /// Create a cargo command based on the context. /// -/// For "build" commands (which compile code, such as `cargo 3ds build` or `cargo 3ds clippy`), +/// For "build" commands (which compile code, such as `cargo nds build` or `cargo nds clippy`), /// if there is no pre-built std detected in the sysroot, `build-std` will be used instead. pub fn make_cargo_command(input: &Input, message_format: &Option) -> Command { - let devkitpro = - env::var("DEVKITPRO").expect("DEVKITPRO is not defined as an environment variable"); - // TODO: should we actually prepend the user's RUSTFLAGS for linking order? not sure - let rustflags = - env::var("RUSTFLAGS").unwrap_or_default() + &format!(" -L{devkitpro}/libctru/lib"); + let blocksds = env::var("BLOCKSDS").unwrap_or("/opt/wonderful/thirdparty/blocksds/core".to_owned()); + let rustflags = format!("-C link-args=-specs={blocksds}/sys/crts/ds_arm9.specs"); let cargo_cmd = &input.cmd; @@ -125,21 +122,15 @@ pub fn make_cargo_command(input: &Input, message_format: &Option) -> Com if cargo_cmd.should_compile() { command .arg("--target") - .arg("armv6k-nintendo-3ds") + .arg("armv5te-nintendo-ds.json") + .arg("-Z") + .arg("build-std=core,alloc") .arg("--message-format") .arg( message_format .as_deref() .unwrap_or(CargoCmd::DEFAULT_MESSAGE_FORMAT), ); - - let sysroot = find_sysroot(); - if !sysroot.join("lib/rustlib/armv6k-nintendo-3ds").exists() { - eprintln!("No pre-build std found, using build-std"); - // Always building the test crate is not ideal, but we don't know if the - // crate being built uses #![feature(test)], so we build it just in case. - command.arg("-Z").arg("build-std=std,test"); - } } if let CargoCmd::Test(test) = cargo_cmd { @@ -212,10 +203,10 @@ pub fn check_rust_version() { let rustc_version = rustc_version::version_meta().unwrap(); if rustc_version.channel > Channel::Nightly { - eprintln!("cargo-3ds requires a nightly rustc version."); + eprintln!("cargo-nds requires a nightly rustc version."); eprintln!( "Please run `rustup override set nightly` to use nightly in the \ - current directory, or use `cargo +nightly 3ds` to use it for a \ + current directory, or use `cargo +nightly nds` to use it for a \ single invocation." ); process::exit(1); @@ -237,17 +228,17 @@ pub fn check_rust_version() { }; if old_version || old_commit { - eprintln!("cargo-3ds requires rustc nightly version >= {MINIMUM_COMMIT_DATE}"); + eprintln!("cargo-nds requires rustc nightly version >= {MINIMUM_COMMIT_DATE}"); eprintln!("Please run `rustup update nightly` to upgrade your nightly version"); process::exit(1); } } -/// Parses messages returned by "build" cargo commands (such as `cargo 3ds build` or `cargo 3ds run`). +/// Parses messages returned by "build" cargo commands (such as `cargo nds build` or `cargo nds run`). /// The returned [`CTRConfig`] is then used for further building in and execution -/// in [`build_smdh`], [`build_3dsx`], and [`link`]. -pub fn get_metadata(messages: &[Message]) -> CTRConfig { +/// in [`build_nds`], and [`link`]. +pub fn get_metadata(messages: &[Message]) -> NDSConfig { let metadata = MetadataCommand::new() .no_deps() .exec() @@ -275,12 +266,12 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig { let (package, artifact) = (package.unwrap(), artifact.unwrap()); - let mut icon = String::from("./icon.png"); + let mut icon = String::from("./icon.bmp"); if !Path::new(&icon).exists() { icon = format!( - "{}/libctru/default_icon.png", - env::var("DEVKITPRO").unwrap() + "{}/sys/icon.bmp", + env::var("BLOCKSDS").unwrap() ); } @@ -300,63 +291,41 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig { [] => String::from("Unspecified Author"), // as standard with the devkitPRO toolchain }; - CTRConfig { + NDSConfig { name, author, description: package .description .clone() .unwrap_or_else(|| String::from("Homebrew Application")), - icon, + icon : icon, target_path: artifact.executable.unwrap().into(), cargo_manifest_path: package.manifest_path.into(), } } -/// Builds the smdh using `smdhtool`. -/// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH -pub fn build_smdh(config: &CTRConfig, verbose: bool) { - let mut command = Command::new("smdhtool"); +/// Builds the nds using `ndstool`. +/// This will fail if `ndstool` is not within the running directory or in a directory found in $PATH +pub fn build_nds(config: &NDSConfig, verbose: bool) { + let mut command = Command::new("ndstool"); + let banner_text = format!("\"{};{};{}\"", &config.name, &config.description, &config.author); command - .arg("--create") - .arg(&config.name) - .arg(&config.description) - .arg(&config.author) + .arg("-c") + .arg(config.path_nds()) + .arg("-9") + .arg(config.path_arm9()) + .arg("-7") + .arg(config.path_arm7()) + .arg("-b") .arg(&config.icon) - .arg(config.path_smdh()) - .stdin(Stdio::inherit()) - .stdout(Stdio::inherit()) - .stderr(Stdio::inherit()); - - if verbose { - print_command(&command); - } - - let mut process = command - .spawn() - .expect("smdhtool command failed, most likely due to 'smdhtool' not being in $PATH"); - - let status = process.wait().unwrap(); - - if !status.success() { - process::exit(status.code().unwrap_or(1)); - } -} - -/// Builds the 3dsx using `3dsxtool`. -/// This will fail if `3dsxtool` is not within the running directory or in a directory found in $PATH -pub fn build_3dsx(config: &CTRConfig, verbose: bool) { - let mut command = Command::new("3dsxtool"); - command - .arg(&config.target_path) - .arg(config.path_3dsx()) - .arg(format!("--smdh={}", config.path_smdh().to_string_lossy())); + .arg(banner_text); // If romfs directory exists, automatically include it let (romfs_path, is_default_romfs) = get_romfs_path(config); if romfs_path.is_dir() { eprintln!("Adding RomFS from {}", romfs_path.display()); - command.arg(format!("--romfs={}", romfs_path.to_string_lossy())); + command.arg("-d") + .arg(&romfs_path); } else if !is_default_romfs { eprintln!( "Could not find configured RomFS dir: {}", @@ -374,7 +343,7 @@ pub fn build_3dsx(config: &CTRConfig, verbose: bool) { .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn() - .expect("3dsxtool command failed, most likely due to '3dsxtool' not being in $PATH"); + .expect("ndstool command failed, most likely due to 'ndstool' not being in $PATH"); let status = process.wait().unwrap(); @@ -383,13 +352,13 @@ pub fn build_3dsx(config: &CTRConfig, verbose: bool) { } } -/// Link the generated 3dsx to a 3ds to execute and test using `3dslink`. -/// This will fail if `3dslink` is not within the running directory or in a directory found in $PATH -pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) { - let mut command = Command::new("3dslink"); +/// Link the generated nds to a ds to execute and test using `dslink`. +/// This will fail if `dslink` is not within the running directory or in a directory found in $PATH +pub fn link(config: &NDSConfig, run_args: &Run, verbose: bool) { + let mut command = Command::new("dslink"); command - .arg(config.path_3dsx()) - .args(run_args.get_3dslink_args()) + .args(run_args.get_dslink_args()) + .arg(config.path_nds()) .stdin(Stdio::inherit()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()); @@ -407,7 +376,7 @@ pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) { /// Read the `RomFS` path from the Cargo manifest. If it's unset, use the default. /// The returned boolean is true when the default is used. -pub fn get_romfs_path(config: &CTRConfig) -> (PathBuf, bool) { +pub fn get_romfs_path(config: &NDSConfig) -> (PathBuf, bool) { let manifest_path = &config.cargo_manifest_path; let manifest_str = std::fs::read_to_string(manifest_path) .unwrap_or_else(|e| panic!("Could not open {}: {e}", manifest_path.display())); @@ -422,9 +391,9 @@ pub fn get_romfs_path(config: &CTRConfig) -> (PathBuf, bool) { .and_then(toml::Value::as_table) .and_then(|table| table.get("metadata")) .and_then(toml::Value::as_table) - .and_then(|table| table.get("cargo-3ds")) + .and_then(|table| table.get("nds")) .and_then(toml::Value::as_table) - .and_then(|table| table.get("romfs_dir")) + .and_then(|table| table.get("romfs")) .and_then(toml::Value::as_str) .unwrap_or_else(|| { is_default = true; @@ -437,8 +406,41 @@ pub fn get_romfs_path(config: &CTRConfig) -> (PathBuf, bool) { (romfs_path, is_default) } +/// Read the `icon` path from the Cargo manifest. If it's unset, use the default. +/// The returned boolean is true when the default is used. +pub fn get_icon_path(config: &NDSConfig) -> (PathBuf, bool) { + let manifest_path = &config.cargo_manifest_path; + let manifest_str = std::fs::read_to_string(manifest_path) + .unwrap_or_else(|e| panic!("Could not open {}: {e}", manifest_path.display())); + let manifest_data: toml::Value = + toml::de::from_str(&manifest_str).expect("Could not parse Cargo manifest as TOML"); + + // Find the icon setting and compute the path + let mut is_default = false; + + let icon_setting = manifest_data + .as_table() + .and_then(|table| table.get("package")) + .and_then(toml::Value::as_table) + .and_then(|table| table.get("metadata")) + .and_then(toml::Value::as_table) + .and_then(|table| table.get("nds")) + .and_then(toml::Value::as_table) + .and_then(|table| table.get("icon")) + .and_then(toml::Value::as_str) + .unwrap_or_else(|| { + is_default = true; + "/opt/wonderful/thirdparty/blocksds/core/sys/icon.bmp" + }); + let mut icon_path = manifest_path.clone(); + icon_path.pop(); // Pop Cargo.toml + icon_path.push(icon_setting); + + (icon_path, is_default) +} + #[derive(Default)] -pub struct CTRConfig { +pub struct NDSConfig { name: String, author: String, description: String, @@ -447,13 +449,20 @@ pub struct CTRConfig { cargo_manifest_path: PathBuf, } -impl CTRConfig { - pub fn path_3dsx(&self) -> PathBuf { - self.target_path.with_extension("3dsx") +impl NDSConfig { + pub fn path_nds(&self) -> PathBuf { + self.target_path.with_extension("nds") } - - pub fn path_smdh(&self) -> PathBuf { - self.target_path.with_extension("smdh") + pub fn path_arm9(&self) -> PathBuf { + self.target_path.with_extension("arm9.elf") + } + pub fn path_arm7(&self) -> PathBuf { + let arm7 =self.target_path.with_extension("arm7.elf"); + if arm7.exists() { + return arm7; + } + let blocksds= env::var("BLOCKSDS").unwrap_or("/opt/wonderful/thirdparty/blocksds/core".to_owned()); + PathBuf::from(format!("{}/sys/default_arm7/arm7.elf",blocksds)) } } diff --git a/src/main.rs b/src/main.rs index 022e635..054abf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,11 @@ -use std::process; +use std::{env, process}; -use cargo_3ds::command::Cargo; -use cargo_3ds::{check_rust_version, run_cargo}; +use cargo_nds::command::Cargo; +use cargo_nds::{check_rust_version, run_cargo}; use clap::Parser; fn main() { check_rust_version(); - let Cargo::Input(mut input) = Cargo::parse(); let message_format = match input.cmd.extract_message_format() {