Skip to content

Commit 6b4fd53

Browse files
Cleanup and add some more comments
Minor tweaks like fn names, refactoring a little etc. Also update README to include an install command, with `--locked` as well.
1 parent 0db0ad3 commit 6b4fd53

File tree

3 files changed

+94
-75
lines changed

3 files changed

+94
-75
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
Cargo command to work with Nintendo 3DS project binaries. Based on cargo-psp.
44

5+
## Installation
6+
7+
To install the latest release on <https://crates.io>:
8+
9+
```sh
10+
cargo install --locked cargo-3ds
11+
```
12+
13+
To install the current `master` version of `cargo-3ds`:
14+
15+
```sh
16+
cargo install --locked --git https://github.com/rust3ds/cargo-3ds
17+
```
18+
519
## Usage
620

721
Use the nightly toolchain to build 3DS apps (either by using `rustup override nightly` for the project directory or by adding `+nightly` in the `cargo` invocation).

src/command.rs

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::sync::OnceLock;
66
use cargo_metadata::Message;
77
use clap::{Args, Parser, Subcommand};
88

9-
use crate::{build_3dsx, build_smdh, find_cargo, get_metadata, link, print_command, CTRConfig};
9+
use crate::{build_3dsx, build_smdh, cargo, get_metadata, link, print_command, CTRConfig};
1010

1111
#[derive(Parser, Debug)]
1212
#[command(name = "cargo", bin_name = "cargo")]
@@ -22,7 +22,7 @@ pub struct Input {
2222
pub cmd: CargoCmd,
2323

2424
/// Print the exact commands `cargo-3ds` is running. Note that this does not
25-
/// set the verbose flag for cargo itself. To set cargo's verbose flag, add
25+
/// set the verbose flag for cargo itself. To set cargo's verbosity flag, add
2626
/// `-- -v` to the end of the command line.
2727
#[arg(long, short = 'v', global = true)]
2828
pub verbose: bool,
@@ -165,21 +165,21 @@ impl CargoCmd {
165165

166166
// We can't run 3DS executables on the host, but we want to respect
167167
// the user's "runner" configuration if set.
168-
if test.doc {
169-
eprintln!("Documentation tests requested, no 3dsx will be built");
168+
//
169+
// If doctests were requested, `--no-run` will be rejected on the
170+
// command line and must be set with RUSTDOCFLAGS instead:
171+
// https://github.com/rust-lang/rust/issues/87022
172+
if !test.run_args.use_custom_runner() && !test.doc {
173+
cargo_args.push("--no-run".to_string());
174+
}
170175

171-
// https://github.com/rust-lang/cargo/issues/7040
172-
cargo_args.append(&mut vec![
173-
"--doc".to_string(),
174-
"-Z".to_string(),
175-
"doctest-xcompile".to_string(),
176-
// doctests don't automatically build the `test` crate,
177-
// so we manually specify it on the command line
178-
"-Z".to_string(),
179-
"build-std=std,test".to_string(),
176+
if test.doc {
177+
cargo_args.extend([
178+
"--doc".into(),
179+
// https://github.com/rust-lang/cargo/issues/7040
180+
"-Z".into(),
181+
"doctest-xcompile".into(),
180182
]);
181-
} else if !test.run_args.is_runner_configured() {
182-
cargo_args.push("--no-run".to_string());
183183
}
184184

185185
cargo_args
@@ -206,7 +206,7 @@ impl CargoCmd {
206206
match self {
207207
CargoCmd::Build(_) => "build",
208208
CargoCmd::Run(run) => {
209-
if run.is_runner_configured() {
209+
if run.use_custom_runner() {
210210
"run"
211211
} else {
212212
"build"
@@ -228,23 +228,31 @@ impl CargoCmd {
228228

229229
/// Whether or not this command should build a 3DSX executable file.
230230
pub fn should_build_3dsx(&self) -> bool {
231-
matches!(
232-
self,
233-
Self::Build(_) | Self::Run(_) | Self::Test(Test { doc: false, .. })
234-
)
231+
match self {
232+
Self::Build(_) | CargoCmd::Run(_) => true,
233+
&Self::Test(Test { doc, .. }) => {
234+
if doc {
235+
eprintln!("Documentation tests requested, no 3dsx will be built");
236+
false
237+
} else {
238+
true
239+
}
240+
}
241+
_ => false,
242+
}
235243
}
236244

237245
/// Whether or not the resulting executable should be sent to the 3DS with
238246
/// `3dslink`.
239247
pub fn should_link_to_device(&self) -> bool {
240248
match self {
241-
Self::Test(test) => !(test.no_run || test.run_args.is_runner_configured()),
242-
Self::Run(run) => !run.is_runner_configured(),
249+
Self::Test(Test { no_run: true, .. }) => false,
250+
Self::Run(run) | Self::Test(Test { run_args: run, .. }) => !run.use_custom_runner(),
243251
_ => false,
244252
}
245253
}
246254

247-
pub const DEFAULT_MESSAGE_FORMAT: &str = "json-render-diagnostics";
255+
pub const DEFAULT_MESSAGE_FORMAT: &'static str = "json-render-diagnostics";
248256

249257
pub fn extract_message_format(&mut self) -> Result<Option<String>, String> {
250258
let cargo_args = match self {
@@ -347,7 +355,7 @@ impl RemainingArgs {
347355

348356
if let Some(split) = args.iter().position(|s| s == "--") {
349357
let second_half = args.split_off(split + 1);
350-
// take off the "--" arg we found
358+
// take off the "--" arg we found, we'll add one later if needed
351359
args.pop();
352360

353361
(args, second_half)
@@ -421,7 +429,7 @@ impl Run {
421429
// Run the normal "build" callback
422430
self.build_args.callback(config);
423431

424-
if !self.is_runner_configured() {
432+
if !self.use_custom_runner() {
425433
if let Some(cfg) = config {
426434
eprintln!("Running 3dslink");
427435
link(cfg, self, self.build_args.verbose);
@@ -431,45 +439,44 @@ impl Run {
431439

432440
/// Returns whether the cargo environment has `target.armv6k-nintendo-3ds.runner`
433441
/// configured. This will only be checked once during the lifetime of the program,
434-
/// and takes into account the usual ways Cargo looks for
442+
/// and takes into account the usual ways Cargo looks for its
435443
/// [configuration](https://doc.rust-lang.org/cargo/reference/config.html):
436444
///
437445
/// - `.cargo/config.toml`
438446
/// - Environment variables
439447
/// - Command-line `--config` overrides
440-
pub fn is_runner_configured(&self) -> bool {
448+
pub fn use_custom_runner(&self) -> bool {
441449
static HAS_RUNNER: OnceLock<bool> = OnceLock::new();
442450

443-
let has_runner = HAS_RUNNER.get_or_init(|| {
444-
let mut cmd = find_cargo();
445-
446-
let config_args = self.config.iter().map(|cfg| format!("--config={cfg}"));
447-
448-
cmd.args(config_args)
449-
.args([
450-
"config",
451-
"-Zunstable-options",
452-
"get",
453-
"target.armv6k-nintendo-3ds.runner",
454-
])
455-
.stdout(Stdio::null())
456-
.stderr(Stdio::null());
451+
let &custom_runner_configured = HAS_RUNNER.get_or_init(|| {
452+
let mut cmd = cargo(&self.config);
453+
cmd.args([
454+
// https://github.com/rust-lang/cargo/issues/9301
455+
"-Z",
456+
"unstable-options",
457+
"config",
458+
"get",
459+
"target.armv6k-nintendo-3ds.runner",
460+
])
461+
.stdout(Stdio::null())
462+
.stderr(Stdio::null());
457463

458464
if self.build_args.verbose {
459465
print_command(&cmd);
460466
}
461467

468+
// `cargo config get` exits zero if the config exists, or nonzero otherwise
462469
cmd.status().map_or(false, |status| status.success())
463470
});
464471

465472
if self.build_args.verbose {
466473
eprintln!(
467474
"Custom runner is {}configured",
468-
if *has_runner { "" } else { "not " }
475+
if custom_runner_configured { "" } else { "not " }
469476
);
470477
}
471478

472-
*has_runner
479+
custom_runner_configured
473480
}
474481
}
475482

@@ -488,13 +495,13 @@ impl Test {
488495
}
489496
}
490497

491-
const TOML_CHANGES: &str = "ctru-rs = { git = \"https://github.com/rust3ds/ctru-rs\" }
498+
const TOML_CHANGES: &str = r#"ctru-rs = { git = "https://github.com/rust3ds/ctru-rs" }
492499
493500
[package.metadata.cargo-3ds]
494-
romfs_dir = \"romfs\"
495-
";
501+
romfs_dir = "romfs"
502+
"#;
496503

497-
const CUSTOM_MAIN_RS: &str = "use ctru::prelude::*;
504+
const CUSTOM_MAIN_RS: &str = r#"use ctru::prelude::*;
498505
499506
fn main() {
500507
ctru::use_panic_handler();
@@ -504,8 +511,8 @@ fn main() {
504511
let gfx = Gfx::new().unwrap();
505512
let _console = Console::new(gfx.top_screen.borrow_mut());
506513
507-
println!(\"Hello, World!\");
508-
println!(\"\\x1b[29;16HPress Start to exit\");
514+
println!("Hello, World!");
515+
println!("\x1b[29;16HPress Start to exit");
509516
510517
while apt.main_loop() {
511518
gfx.wait_for_vblank();
@@ -516,7 +523,7 @@ fn main() {
516523
}
517524
}
518525
}
519-
";
526+
"#;
520527

521528
impl New {
522529
/// Callback for `cargo 3ds new`.

src/lib.rs

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,14 @@ pub fn run_cargo(input: &Input, message_format: Option<String>) -> (ExitStatus,
6363
/// For "build" commands (which compile code, such as `cargo 3ds build` or `cargo 3ds clippy`),
6464
/// if there is no pre-built std detected in the sysroot, `build-std` will be used instead.
6565
pub fn make_cargo_command(input: &Input, message_format: &Option<String>) -> Command {
66-
let cmd = &input.cmd;
66+
let cargo_cmd = &input.cmd;
6767

68-
let mut command = find_cargo();
69-
command
70-
.args(input.config.iter().map(|cfg| format!("--config={cfg}")))
71-
.arg(cmd.subcommand_name());
68+
let mut command = cargo(&input.config);
69+
command.arg(cargo_cmd.subcommand_name());
7270

7371
// Any command that needs to compile code will run under this environment.
7472
// Even `clippy` and `check` need this kind of context, so we'll just assume any other `Passthrough` command uses it too.
75-
if cmd.should_compile() {
73+
if cargo_cmd.should_compile() {
7674
let rust_flags = env::var("RUSTFLAGS").unwrap_or_default()
7775
+ &format!(
7876
" -L{}/libctru/lib -lctru",
@@ -93,33 +91,30 @@ pub fn make_cargo_command(input: &Input, message_format: &Option<String>) -> Com
9391
let sysroot = find_sysroot();
9492
if !sysroot.join("lib/rustlib/armv6k-nintendo-3ds").exists() {
9593
eprintln!("No pre-build std found, using build-std");
96-
// TODO: should we consider always building `test` ? It's always needed
97-
// if e.g. `test-runner` is a dependency, but not necessarily needed for
98-
// production code.
99-
command.arg("-Z").arg("build-std");
94+
// Always building the test crate is not ideal, but we don't know if the
95+
// crate being built uses #![feature(test)], so we build it just in case.
96+
command.arg("-Z").arg("build-std=std,test");
10097
}
10198
}
10299

103-
let cargo_args = cmd.cargo_args();
104-
command.args(cargo_args);
105-
106-
if let CargoCmd::Test(test) = cmd {
107-
let no_run_flag = if test.run_args.is_runner_configured() {
108-
// TODO: should we persist here as well? Or maybe just let the user
109-
// add that to RUSTDOCFLAGS if they want it...
100+
if let CargoCmd::Test(test) = cargo_cmd {
101+
let no_run_flag = if test.run_args.use_custom_runner() {
110102
""
111103
} else {
104+
// We don't support running doctests by default, but cargo doesn't like
105+
// --no-run for doctests, so we have to plumb it in via RUSTDOCFLAGS
112106
" --no-run"
113107
};
114108

115-
// Cargo doesn't like --no-run for doctests, so we have to plumb it in here
116-
// https://github.com/rust-lang/rust/issues/87022
109+
// RUSTDOCFLAGS is simply ignored if --doc wasn't passed, so we always set it.
117110
let rustdoc_flags = std::env::var("RUSTDOCFLAGS").unwrap_or_default() + no_run_flag;
118111
command.env("RUSTDOCFLAGS", rustdoc_flags);
119112
}
120113

121-
if let CargoCmd::Run(run) | CargoCmd::Test(Test { run_args: run, .. }) = &cmd {
122-
if run.is_runner_configured() {
114+
command.args(cargo_cmd.cargo_args());
115+
116+
if let CargoCmd::Run(run) | CargoCmd::Test(Test { run_args: run, .. }) = &cargo_cmd {
117+
if run.use_custom_runner() {
123118
command
124119
.arg("--")
125120
.args(run.build_args.passthrough.exe_args());
@@ -134,10 +129,12 @@ pub fn make_cargo_command(input: &Input, message_format: &Option<String>) -> Com
134129
command
135130
}
136131

137-
/// Get the environment's version of cargo
138-
fn find_cargo() -> Command {
132+
/// Build a `cargo` command with the given `--config` flags.
133+
fn cargo(config: &[String]) -> Command {
139134
let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
140-
Command::new(cargo)
135+
let mut cmd = Command::new(cargo);
136+
cmd.args(config.iter().map(|cfg| format!("--config={cfg}")));
137+
cmd
141138
}
142139

143140
fn print_command(command: &Command) {
@@ -181,7 +178,8 @@ pub fn check_rust_version() {
181178
eprintln!("cargo-3ds requires a nightly rustc version.");
182179
eprintln!(
183180
"Please run `rustup override set nightly` to use nightly in the \
184-
current directory."
181+
current directory, or use `cargo +nightly 3ds` to use it for a \
182+
single invocation."
185183
);
186184
process::exit(1);
187185
}

0 commit comments

Comments
 (0)