rust3ds/cargo-3ds

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

ian-h-chamberlain opened this issue · 0 comments

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:

  • cargo 3ds test (can build lib tests and possibly multiple integration tests. Doc tests are separate due to needing doctest-xcompile currently)
  • Any cargo 3ds build command with multiple binaries explicitly requested, e.g. --examples, --bin foo --bin bar, etc.

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

  • romfs dir
  • icon
  • description

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!