Megaton Documentation
Table of Contents
Having an issue?
Please provide feedback, bug reports and feature requests on GitHub.
Installation
Prerequisites
-
Megaton requires
DevKitA64from DevKitPro. (Select theswitch-devgroup) -
For Rust support (building mods written in Rust), a Rust toolchain for the host system (i.e. the system used to build the mod) and
gitare required to clone and build the Rust compiler for theaarch64-unknown-hermittarget.
Install Megaton
The megaton CLI is a single binary, which can be installed in 3 ways:
- (Recommended) Install from prebuilt binary with
cargo-binstallcargo binstall megaton-cmd --git https://github.com/Pistonite/megaton - Install from source with
cargocargo install megaton-cmd --git https://github.com/Pistonite/megaton - Download the binary from the latest release on GitHub
Install Megaton Rust Toolchain
Megaton implements the Hermit ABI to bind Rust
Standard Library to NNSDK. This requires a custom Rust toolchain. Megaton will install
this toolchain at ~/.cache/megaton/rust-toolchain.
This toolchain is locked at a commit for every Megaton version. This will be bumped approximately in line with Rust’s stable release. If you need Rust feature in a higher version of Rust than what is included with Megaton, please open an issue on GitHub.
Run the following command to install the toolchain, or upgrade the toolchain in the future
megaton toolchain install
This compiles LLVM and bootstraps the Rust compiler, which will take a while.
To keep the build artifact, use the -k/--keep flag: megaton toolchain install -k.
This will make it faster to rebuild the toolchain in the future when upgrading. However,
this will consume 10-20GB of disk spaces.
You can check if the toolchain is installed with
megaton toolchain check
Or directly with rustc (megaton is the name of the toolchain)
rustc +megaton -vV
Upgrading
To upgrade megaton, simply reinstall the latest version with cargo/cargo-binstall,
or replace the binary with the latest release on GitHub if you installed it manually.
To upgrade the custom Rust toolchain, run megaton toolchain install after upgrading megaton.
TUTORIAL - TODO
Profiles
The profile system allows you to have different configurations/targets for your project. An example is having different build flags and dependencies when targeting different versions of a game.
The [build]
and [check]
sections supports profiles using the profiles key in the section.
For example, [build.profiles.foo] has the same
schema as [build], and should contain configuration for
the foo profile.
[build]
sources = ["src"]
[build.profiles.foo]
sources = ["src_foo"]
Profiles can be selected when building by using
megaton build --profile PROFILE.
For the example above, running megaton build -p foo
will include both src and src_foo as source directories,
while running megaton build will only include src as the source directory.
Nested map properties like build.flags are recursively merged,
and should be specified like [build.profiles.foo.flags], NOT [build.flags.profiles.foo]
Base Profile
The base profile will be called "none", as described in this documentation.
However in the current development, it’s coded as "base". This will be changed
in the stable release, and is tracked by Issue #80
The configs without any explicit profiles is known as the “base profile”, and
has the name "none". (This word is reserved you cannot name your custom profile "none").
Inheriting the Base Profile
Each config option specified on a custom profile inherits from the base profile. The inheritance uses one of two inheritance behaviors.
- Override: The value for this key will override that of its parent.
- This is always the case for scalar (non-array) values
- If the value is array type, it can still optionally extend the base by including
"<default>"in the array.
- Append: Only applies to arrays. The value for this key is the appended to that of its parent. This means that a profile will always extend the default behavior but cannot disable it.
See the reference for Build
and Check sections for the behavior of each config option.
Configure Defaults
You can customize the profile selection behavior of the CLI with the
[profile] section of the config,
for example, select a profile by default if nothing is specified on the CLI, or disallow
the "none" profile (i.e. the base profile) from the CLI (useful if only using the base profile)
for inheritance.
See the reference for Profile section for
more information.
References
This section covers the behavior of Megaton in detail.
- Configuration: Specification of
Megaton.toml - Paths:
- Environment Variables:
Megaton TOML Config Spec
This config allows the user to set several options which change how the mod is built by the build tool.
The root of a particular project is the directory that contains the config (Megaton.toml). For all values that determine a path, unless otherwise specified, the path is relative to the project root.
For each key, if a default value/behavior is not specified, the entry is required in the config.
The expected type for each key is listed in its heading. Additional restrictions may be specified in the description if a specific form is expected.
Profile enabled keys/sections
Profile enabled keys are options which can have a unique value for different profiles. To set a value for a specific profile, use the key format {section}.profiles.{profile-name}.{key-name}. If a profile enabled key is set without specifying a profile, i.e. {section}.{key-name}, the value will be set for the base profile. If a section is marked as profile enabled, all keys under that section are profile enabled.
Profile inheritance behavior
Each config options set for a profile uses one of two inheritance behaviors. The parent of a user-specified profile is the base profile. The “parent” of the base profile is the base profile’s default value. If a profile enabled key is not an array type, it will always override its parent.
- Append: The value for this key is the appended to that of its parent. This means that a profile will always extend the default behavior but cannot disable it.
- Override: The value for this key will override that of its parent. These values can still optionally extend their parent by including “
” in their value. If the values is specified as [], the parent value will be completely disabled.
Configuration for the Megaton build tool and library.
Example:
[megaton]
version = "1"
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
Key: megaton.version
Type: string
Version of Megaton the project is supposed to use. Megaton will abort if its minor version does not
match this value. (i.e. "2" will match 0.2.x). For future-proof, this value is a string
rather than an integer.
Key: megaton.custom-entry
Type: string
The entry point (main function) symbol passed to the linker.
If non-empty, Megaton library will NOT be compiled or linked when running megaton build.
Use this option to use Megaton as a standalone build tool, without the Megaton library.
When using Megaton library, the megaton_main function is not the real “main function”; instead,
it is wrapped with a function that initializes Megaton and calls megaton_main.
Megaton library is required to use Rust. If megaton.custom-entry is true, Rust is also
disabled.
Default: "" (use Megaton library)
In a Megaton project, the module is the NSO object that is ultimately produced and loaded alongside the game. It is also sometimes synonymus with project.
Example:
[module]
name = "my-mod"
title-id = 0x01007ef00011e000
The root of a particular project is the directory that contains the config (Megaton.toml). For all values that determine a path, unless otherwise specified, the path is relative to the project root.
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
Key: module.name
Type: string
The name of the module, i.e., your mod’s name. The final binary will use this name.
Restrictions: Cannot be "" or "lib". Only alphanumeric characters, -, and _ are allowed.
Key: module.title-id
Type: integer
The title ID for the targeted game. Needed to generate the NPDM file. (Note this needs to be an integer in the config, not a hex string)
Key: module.target
Type: string
The path to the directory for the Megaton build tool to emit build artifacts.
All the library and generated artifacts will be placed here under a subdirectory megaton.
(For example if module.target = "foo/bar", then all megaton’s output will be at foo/bar/megaton/.)
See Output Directory for the structure of the directory.
Default: "target"
Key: module.compdb
Type: string
A database of compiler commands to be used for clangd integration.
Megaton will work with existing compile_commands.json (included ones generated from another Megaton project). This allows multiple Megaton projects in the same monorepo to share the same compile_commands.json
to make LSP integration easier. However, other tools like CMake could still override megaton’s entries
Default: "compile_commands.json"
Megaton allows multiple different config profiles to coexist. You can set up profiles for different build configurations like release and debug, or different versions of a game. See the tutorial for Profile for more info.
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
Key: profile.allow-base
Type: bool
Determines if the base profile profile is allowed to be built.
Default: true
Key: profile.default
Type: string
The profile that will be built if the -p PROFILE flag is omitted from the CLI.
If set to "" (the empty string), the profile must be set via CLI flag on every call.
Default: "none"
Examples:
- Set to empty string
[module] name = "example" [profile] default = "" # Must run with `megaton build -p PROFILE` - Set to non-empty string
[module] name = "example" [profile] default = "foo" # Run with `megaton build` -> use foo # Run with `megaton build -p none` -> use none (base profile) - Set with
allow-base = false[module] name = "example" default = "foo" allow-base = false # Run with `megaton build` -> use foo # Run with `megaton build -p none` -> error
The [build] section is where to change compilation settings.
Example:
[build]
sources = ["src"]
includes = ["include", "some_lib/include"]
[build.flags]
c = ["<default>", "-DMY_DEFINE=1"]
rust = ["<default>", "-Zub-checks=yes"]
cargo = ["<default>", "--features", "my-feature"]
The root of a particular project is the directory that contains the config (Megaton.toml). For all values that determine a path, unless otherwise specified, the path is relative to the project root.
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
This section can be extended with profiles.
Key: build.sources
Type: string[] (array of strings)
Paths to source directories to recursively scan for C/C++/Assembly source files. Sources generated by Megaton are automatically included and do not need to be specified. If the mod contains only Rust code, this can be omitted. Sources will be detected and matched based on file extension. The following extensions will be detected:
- C:
.c - C++:
.cc,.c++,.cpp - Assembly:
.s,.asm
Inheritance: Append
Default: []
Key: build.includes
Type: string[] (array of strings)
Paths to include directories to be passed to the compiler as -I flags. Headers generated by Megaton (including headers from the Megaton library) are automatically included and do not need to be specified.
Inheritance: Append
Default: []
Key: build.libpaths
Type: string[] (array of strings)
Paths to library directories to be passed to the compiler as -L flags.
Inheritance: Append
Default: []
Key: build.libraries
Type: string[] (array of strings)
Libraries to be linked. These will be passed as -l flags to the linker. The names of libraries here must be discoverable in the directories specified in build.libpaths. For example, to link the library “foo”, add “foo” to this array and place the file libfoo.so in one of the library paths.
Inheritance: Append
Default: []
Key: build.objects
Type: string[] (array of strings)
Additional .o and .a objects to link with, i.e. compiled objects that are not generated by Megaton.
Inheritance: Append
Default: []
Key: build.flags
Build flags to pass to the different tools on the build toolchain. All flags keys have the same inheritance behavior of Override.
In order to add a build flag, specify the value like this: [<"default">, -DDEBUG]. If the value is specified as [], The default flags will be disabled for that profile.
The default flags can be found here, and the flag extension behavior is detailed below.
| Property | <default> includes |
|---|---|
common | None |
c | common |
cxx | c |
as | cxx |
ld | common |
rust | None |
cargo | None |
For this flag config:
[build.flags]
c = ["<default>", "-DDEBUG"]
-DDEBUG will be added to the flags when invoking gcc
(using C flags), g++ (using CXX flags, extended from C flags), and as (using AS flags, extended from CXX flags).
Inheritance: Override
Default: ["<default>"]
Key: build.flags.common
Flags for all tools except rust and cargo.
Key: build.flags.c
Flags for the C compiler.
Key: build.flags.cxx
Flags for the C++ compiler.
Key: build.flags.as
Flags for the assembler to use with assembly sources.
Key: build.flags.ld
Flags for the linker.
C++ compiler is used for linking. Flags for ld
should be specified as -Wl,--flag instead of --flag.
Key: build.flags.rust
Flags for rust. Corresponds to the RUSTFLAGS environment variable. Rust flags can also be specified in Cargo.toml, but placing them here allows them to be dynamically enabled using Megaton’s profile system.
Restrictions: Can only be specified if cargo.enabled = true
Key: build.flags.cargo
Flags to be passed to cargo, such as feature flags.
Restrictions: Can only be specified if cargo.enabled = true
Megaton can be used to build mods that contain both C++ and Rust code. Internally Megaton uses Cargo to compile Rust sources. It also provides support for the cxx crate to handle interop between C++ and Rust (if needed). Rust crates should be configured, as usual, in the Cargo.toml file. This sections controls Megaton options for Cargo and CXX.
The root of a particular project is the directory that contains the config (Megaton.toml). For all values that determine a path, unless otherwise specified, the path is relative to the project root.
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
Key: cargo.enabled
Type: bool
Determines if Rust support is enabled. Megaton will only try to do Rust stuff like cargo build if this is true.
Restrictions: May not be true if megaton.custom-entry is not "".
See [megaton] config section.
Default: Megaton will try to determine if Rust support should be enabled using the following checks, in order:
- If
cargo.manifestis specified ->true- It will error if the specified path cannot be found.
- If the file
Cargo.tomlexists in project root ->true - Else ->
false
Key: cargo.manifest
Type: string
The manifest file path for cargo. This will be passed to --manifest-path when cargo is run.
Default: "Cargo.toml" if it exists, cargo.enabled will be false if it does not exist.
Key: cargo.sources
Type: string[] (array of strings)
The Rust source directories to scan for .rs files. These files will be scanned for cxx::bridge attributes to generate FFI code.
Default: ["src"]
Key: cargo.header-suffix
Type: string
Suffix to generated headers. The user can put the empty string here so they can do #include <foo/lib.rs> instead of <foo/lib.rs.h>
Default: ".h"
Megaton performs a check step after linking the module into an ELF and before converting it to a .nso file. This check allows Megaton to blacklist certain symbols and instructions, preventing an unstable binary from being created to catch bugs earlier.
The root of a particular project is the directory that contains the config (Megaton.toml). For all values that determine a path, unless otherwise specified, the path is relative to the project root.
For each key, if a default value/behavior is not specified, it is required in the config. Otherwise it is optional.
This section can be extended with profiles.
Key: check.ignore (array of strings)
A list of symbols that the checker will ignore when checking the built binary.
Inheritance: Override
Default: ["<default>"]
Key: check.symbols (array of strings)
Type: string[] (array of strings)
Paths to symbol files generated by objdump -T.
Inheritance: Append
Default: []
Key: check.disallowed-instructions
Type: string[] (array of strings)
Instructions that are disallowed in the final binary. Place instructions that are known to crash here. (Mostly needed for Megaton library development).
Inheritance: Override
Default: ["<default>"]