rust3ds / cargo-3ds

Cargo command to work with Nintendo 3DS project binaries.
Apache License 2.0
59 stars 10 forks source link

Build 3dsx for *all* executables built by a given command #44

Closed ian-h-chamberlain closed 5 months ago

ian-h-chamberlain commented 1 year ago

This might be tricky to solve, but it would be nice if we could generate a .3dsx for every binary artifact generated by a given command. Otherwise, it's kinda weird that you might get a different .3dsx depending on which one built first, since we just take the last one currently (which I think is non-deterministic order as binaries can be built in parallel).

Potential use cases:

Part of what will make this hard to implement is figuring out how to specify the metadata for each binary. Most of the fields can probably still be pulled from cargo_metadata like author, name etc., but some things might be useful to specify per-executable, especially icon and RomFS.

Side note: should we call it romfs-dir instead? Most other Cargo.toml keys seem to be kebab-case rather than snake_case

In the case of lib tests, we can probably just use what we already have, but for bins, integration tests and examples I think we might need a new scheme. Initially I'd propose something like this:

[[example]]
name = "ex1"
# I think "description" is non-standard here as it's not documented in
# https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target 
# We could still look for it, but we'd have to manually read in from Cargo.toml 

# examples/ex2.rs may exist but not be defined explicitly in Cargo.toml

[[bin]]
name = "mybin"

# etc. for tests, benches if need be

[package.metadata.cargo-3ds]
romfs_dir = "examples/romfs" # still optional

# should we call these "example", "bin" etc. to match the top-level key?
examples.ex1.romfs_dir = "examples/ex1_romfs"
examples.ex2.romfs_dir = "examples/ex2_romfs"

tests.integration.romfs_dir = "tests/romfs"

# mybin falls back to using "examples/romfs"

# if we needed something else for lib tests we could also do something like this
# but probably it should just use the top level one if we can manage that
lib.romfs_dir = "..."

As a further enhancement, we could allow setting .icon to specify a custom path to an icon, instead of always looking for ./icon.png, or really any of the CTRConfig fields could be overridden on a per-target basis if we want. I think the important ones would probably just be


Overall, I think the flow would look something like this:

  1. Collect package metadata with cargo_metadata::MetadataCommand. This gives us a list of all possible targets (bin, example, etc. including auto-discovered ones), as well as the contents of package.metadata.cargo-3ds.
  2. Construct a CTRConfig for each target (either now or on the fly later, if we store the metadata, doesn't matter too much)
  3. Run the underlying cargo build for whatever command, collecting the output with cargo_metadata::Message
  4. For each artifact found in the build output:
    1. lookup/construct its CTRConfig from earlier by kind and name (e.g. (Example, "foobar"))
    2. generate SMDH
    3. Generate 3dsx

Obviously, this is a pretty big change so I thought I'd start by proposing it and see if there's any discussion to be had before an implementation. This isn't really a super important thing to have since it can always be worked around by building one thing at a time, but it would be nice if it basically Just Worked the way cargo does.

Curious to hear other people's thoughts on this!