mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
Simplify build process (#106)
* Simplify build process - Remove dependencies on DevkitPro - Use linker similarly to min-gba - Update cargo.toml so that dev builds will build - Update cargo config so that std builds can run without the linker for testing purposes - Update CI flow to remove xbuild dependency * Add windows toolchain install * Add windows section to toolchain install instructions
This commit is contained in:
parent
263f7909de
commit
5114f89448
|
@ -1,5 +1,3 @@
|
||||||
[build]
|
[target.thumbv4t-none-eabi]
|
||||||
target = "thumbv4-none-agb.json"
|
rustflags = ["-Clink-arg=-Tlinker.ld"]
|
||||||
|
runner = "mgba"
|
||||||
[unstable]
|
|
||||||
build-std = ["core"]
|
|
||||||
|
|
26
.github/workflows/ci.yaml
vendored
26
.github/workflows/ci.yaml
vendored
|
@ -6,44 +6,40 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-20.04
|
||||||
container: devkitpro/devkitarm:latest
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
rust:
|
rust:
|
||||||
- { toolchain: nightly }
|
- { toolchain: nightly }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Add devkitARM bin to PATH
|
|
||||||
run: echo "/opt/devkitpro/devkitARM/bin" >> $GITHUB_PATH
|
|
||||||
- name: Install Apt Dependencies
|
- name: Install Apt Dependencies
|
||||||
run: apt-get update && apt-get install -y --no-install-recommends build-essential libssl-dev
|
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends build-essential libssl-dev binutils-arm-none-eabi
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: ${{ matrix.rust.toolchain }}
|
toolchain: ${{ matrix.rust.toolchain }}
|
||||||
default: true
|
default: true
|
||||||
- uses: Swatinem/rust-cache@v1
|
|
||||||
- name: Install Rust Source
|
- name: Install Rust Source
|
||||||
run: rustup component add rust-src
|
run: rustup component add rust-src
|
||||||
- name: Install cargo-xbuild crate
|
|
||||||
uses: actions-rs/install@v0.1
|
|
||||||
with:
|
|
||||||
crate: cargo-xbuild
|
|
||||||
version: latest
|
|
||||||
use-tool-cache: true
|
|
||||||
- name: Install cargo-make crate
|
- name: Install cargo-make crate
|
||||||
uses: actions-rs/install@v0.1
|
uses: actions-rs/install@v0.1
|
||||||
with:
|
with:
|
||||||
crate: cargo-make
|
crate: cargo-make
|
||||||
version: latest
|
version: latest
|
||||||
use-tool-cache: true
|
use-tool-cache: true
|
||||||
- name: Make Test Linux
|
- name: Install gbafix crate
|
||||||
|
uses: actions-rs/install@v0.1
|
||||||
|
with:
|
||||||
|
crate: gbafix
|
||||||
|
version: latest
|
||||||
|
use-tool-cache: true
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Make Test
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ matrix.rust.toolchain }}
|
toolchain: ${{ matrix.rust.toolchain }}
|
||||||
command: make
|
command: make
|
||||||
args: test linux
|
args: test
|
||||||
- name: Make Release
|
- name: Make Release
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -22,6 +22,12 @@ gba-proc-macro = "0.5"
|
||||||
embedded-hal = { version = "0.2.4", optional = true }
|
embedded-hal = { version = "0.2.4", optional = true }
|
||||||
nb = { version = "1.0.0", optional = true }
|
nb = { version = "1.0.0", optional = true }
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
lto = false
|
||||||
|
panic = "abort"
|
||||||
|
incremental = false
|
||||||
|
codegen-units = 1
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
|
@ -1,55 +1,70 @@
|
||||||
[config]
|
[config]
|
||||||
skip_core_tasks = true
|
skip_core_tasks = true
|
||||||
|
|
||||||
[tasks.create-target-dir]
|
[tasks.verify-toolchain]
|
||||||
script_runner = "@duckscript"
|
script_runner = "@duckscript"
|
||||||
script = [ "mkdir ./target/" ]
|
script = [
|
||||||
|
'''
|
||||||
|
channel = get_env CARGO_MAKE_RUST_CHANNEL
|
||||||
|
assert_eq ${channel} nightly "Rust toolchain must be set to nightly"
|
||||||
|
'''
|
||||||
|
]
|
||||||
|
|
||||||
[tasks.assemble]
|
|
||||||
dependencies = ["create-target-dir"]
|
|
||||||
command = "arm-none-eabi-as"
|
|
||||||
args = ["crt0.s", "-o", "target/crt0.o"]
|
|
||||||
|
|
||||||
[tasks.build-examples-debug]
|
[tasks.build-examples-debug]
|
||||||
dependencies = ["assemble"]
|
dependencies = ["verify-toolchain"]
|
||||||
command = "cargo"
|
command = "cargo"
|
||||||
args = ["build", "--examples"]
|
args = ["build", "--examples", "--target=thumbv4t-none-eabi", "-Zbuild-std=core"]
|
||||||
|
|
||||||
[tasks.build-examples-release]
|
[tasks.build-examples-release]
|
||||||
dependencies = ["assemble"]
|
dependencies = ["verify-toolchain"]
|
||||||
command = "cargo"
|
command = "cargo"
|
||||||
args = ["build", "--examples", "--release"]
|
args = ["build", "--examples", "--release", "--target=thumbv4t-none-eabi", "-Zbuild-std=core"]
|
||||||
|
|
||||||
[tasks.pack-roms]
|
[tasks.pack-roms]
|
||||||
script_runner = "@duckscript"
|
script_runner = "@duckscript"
|
||||||
script = [
|
script = [
|
||||||
'''
|
'''
|
||||||
|
release_target = get_env RELEASE_TARGET
|
||||||
|
examples_path = set ./target/thumbv4t-none-eabi/${release_target}/examples
|
||||||
examples = glob_array ./examples/*.rs
|
examples = glob_array ./examples/*.rs
|
||||||
for example in ${examples}
|
for example in ${examples}
|
||||||
example = substring ${example} -3
|
example = substring ${example} -3
|
||||||
example = basename ${example}
|
example = basename ${example}
|
||||||
exec arm-none-eabi-objcopy -O binary ./target/thumbv4-none-agb/release/examples/${example} ./target/${example}.gba
|
binary_exists = is_path_exists ${examples_path}/${example}
|
||||||
|
|
||||||
|
if ${binary_exists}
|
||||||
|
echo "Packing: ${examples_path}/${example} to ${examples_path}/${example}.gba"
|
||||||
|
exec arm-none-eabi-objcopy -O binary ${examples_path}/${example} ${examples_path}/${example}.gba
|
||||||
|
echo "Fixing headers: ${examples_path}/${example}.gba"
|
||||||
|
exec gbafix ${examples_path}/${example}.gba
|
||||||
|
else
|
||||||
|
echo "Binary does not exist: ${examples_path}/${example}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
'''
|
'''
|
||||||
]
|
]
|
||||||
|
|
||||||
[tasks.test.linux]
|
[tasks.pack-roms-release]
|
||||||
command = "cargo"
|
dependencies = ["build-examples-release"]
|
||||||
args = ["test", "--lib", "--target", "x86_64-unknown-linux-gnu", "-Z", "build-std"]
|
env = { RELEASE_TARGET = "release" }
|
||||||
|
run_task = "pack-roms"
|
||||||
|
|
||||||
[tasks.test.windows]
|
[tasks.pack-roms-debug]
|
||||||
command = "cargo"
|
dependencies = ["build-examples-debug"]
|
||||||
args = ["test", "--lib", "--target", "x86_64-pc-windows-msvc", "-Z", "build-std"]
|
env = { RELEASE_TARGET = "debug" }
|
||||||
|
run_task = "pack-roms"
|
||||||
|
|
||||||
[tasks.test.mac]
|
[tasks.test]
|
||||||
|
dependencies = ["verify-toolchain"]
|
||||||
command = "cargo"
|
command = "cargo"
|
||||||
args = ["test", "--lib", "--target", "x86_64-apple-darwin", "-Z", "build-std"]
|
args = ["test", "--lib"]
|
||||||
|
|
||||||
[tasks.justrelease]
|
[tasks.justrelease]
|
||||||
dependencies = ["build-examples-release", "pack-roms"]
|
dependencies = ["pack-roms-release"]
|
||||||
|
|
||||||
[tasks.build-all]
|
[tasks.build-all]
|
||||||
dependencies = ["build-examples-debug", "build-examples-release", "pack-roms"]
|
dependencies = ["pack-roms-debug", "pack-roms-release"]
|
||||||
|
|
||||||
[tasks.default]
|
[tasks.default]
|
||||||
alias = "build-all"
|
alias = "build-all"
|
||||||
|
|
25
README.md
25
README.md
|
@ -1,5 +1,5 @@
|
||||||
[![License:Apache2](https://img.shields.io/badge/License-Apache2-green.svg)](https://www.apache.org/licenses/LICENSE-2.0)
|
[![License:Apache2](https://img.shields.io/badge/License-Apache2-green.svg)](https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
[![travis.ci](https://travis-ci.org/rust-console/gba.svg?branch=master)](https://travis-ci.org/rust-console/gba)
|
[![ci](https://github.com/rust-console/gba/workflows/ci/badge.svg?branch=master)](https://github.com/rust-console/gba/actions?query=workflow%3Aci)
|
||||||
[![crates.io](https://img.shields.io/crates/v/gba.svg)](https://crates.io/crates/gba)
|
[![crates.io](https://img.shields.io/crates/v/gba.svg)](https://crates.io/crates/gba)
|
||||||
[![docs.rs](https://docs.rs/gba/badge.svg)](https://docs.rs/gba/latest/gba/)
|
[![docs.rs](https://docs.rs/gba/badge.svg)](https://docs.rs/gba/latest/gba/)
|
||||||
|
|
||||||
|
@ -22,6 +22,29 @@ The following major GBA features are still missing from the crate:
|
||||||
* Interrupt Handling
|
* Interrupt Handling
|
||||||
* Serial Communication
|
* Serial Communication
|
||||||
|
|
||||||
|
## Build Dependencies
|
||||||
|
|
||||||
|
Install required cargo packages
|
||||||
|
```sh
|
||||||
|
rustup install nightly
|
||||||
|
rustup +nightly component add rust-src
|
||||||
|
cargo install cargo-make
|
||||||
|
cargo install gbafix
|
||||||
|
```
|
||||||
|
|
||||||
|
Install arm build tools
|
||||||
|
* Ubuntu
|
||||||
|
```shell
|
||||||
|
sudo apt-get install binutils-arm-none-eabi
|
||||||
|
```
|
||||||
|
* OSX
|
||||||
|
```shell
|
||||||
|
brew install --cask gcc-arm-embedded
|
||||||
|
```
|
||||||
|
* Windows
|
||||||
|
* Download the [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads)
|
||||||
|
* Install the toolchain, make sure to select "Add path to environment variable" during install
|
||||||
|
|
||||||
## First Time Setup
|
## First Time Setup
|
||||||
|
|
||||||
Writing a Rust program for the GBA requires a fair amount of special setup. All
|
Writing a Rust program for the GBA requires a fair amount of special setup. All
|
||||||
|
|
17
build.rs
Normal file
17
build.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
fn main() {
|
||||||
|
let out_file = "rsrt0.o";
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
let out_dir_file = format!("{}/{}", out_dir, out_file);
|
||||||
|
let as_output = std::process::Command::new("arm-none-eabi-as")
|
||||||
|
.args(&["-o", out_dir_file.as_str()])
|
||||||
|
.arg("-mthumb-interwork")
|
||||||
|
.arg("-mcpu=arm7tdmi")
|
||||||
|
.arg("src/rsrt0.S")
|
||||||
|
.output()
|
||||||
|
.expect("failed to run arm-none-eabi-as");
|
||||||
|
if !as_output.status.success() {
|
||||||
|
panic!("{}", String::from_utf8_lossy(&as_output.stderr));
|
||||||
|
}
|
||||||
|
//
|
||||||
|
println!("cargo:rustc-link-search={}", out_dir);
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ MEMORY {
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
.text : {
|
.text : {
|
||||||
KEEP(target/crt0.o(.text));
|
KEEP(rsrt0.o(.text));
|
||||||
*(.text .text.*);
|
*(.text .text.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} >rom = 0xff
|
} >rom = 0xff
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! pointer and execution will jump to the user interrupt handler starting at
|
//! pointer and execution will jump to the user interrupt handler starting at
|
||||||
//! `0x0300_7FFC`, in ARM mode.
|
//! `0x0300_7FFC`, in ARM mode.
|
||||||
//!
|
//!
|
||||||
//! Currently, the user interrupt handler is defined in `crt0.s`. It is set up
|
//! Currently, the user interrupt handler is defined in `rsrt0.S`. It is set up
|
||||||
//! to execute a user-specified interrupt handler after saving some registers.
|
//! to execute a user-specified interrupt handler after saving some registers.
|
||||||
//! This handler is declared as a static function pointer on the Rust side, and
|
//! This handler is declared as a static function pointer on the Rust side, and
|
||||||
//! can be set by using [`set_irq_handler`](irq::set_irq_handler).
|
//! can be set by using [`set_irq_handler`](irq::set_irq_handler).
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
//! This is done by setting the corresponding IRQ flag on
|
//! This is done by setting the corresponding IRQ flag on
|
||||||
//! [`BIOS_IF`](irq::BIOS_IF) at the end of the interrupt handler.
|
//! [`BIOS_IF`](irq::BIOS_IF) at the end of the interrupt handler.
|
||||||
//! * You can change the low-level details of the interrupt handler by editing
|
//! * You can change the low-level details of the interrupt handler by editing
|
||||||
//! the `MainIrqHandler` routine in `crt0.s`. For example, you could declare
|
//! the `MainIrqHandler` routine in `rsrt0.S`. For example, you could declare
|
||||||
//! an external static variable in Rust holding a table of interrupt function
|
//! an external static variable in Rust holding a table of interrupt function
|
||||||
//! pointers and jump directly into one of them in assembly, without the need
|
//! pointers and jump directly into one of them in assembly, without the need
|
||||||
//! to write the branching logic in Rust. However, note that the main
|
//! to write the branching logic in Rust. However, note that the main
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
//!
|
//!
|
||||||
//! ## Implementation Details
|
//! ## Implementation Details
|
||||||
//!
|
//!
|
||||||
//! This is the setup the provided user interrupt handler in `crt0.s` will do
|
//! This is the setup the provided user interrupt handler in `rsrt0.S` will do
|
||||||
//! when an interrupt is received, in order. It is based on the _Recommended
|
//! when an interrupt is received, in order. It is based on the _Recommended
|
||||||
//! User Interrupt Handling_ portion of the GBATEK reference.
|
//! User Interrupt Handling_ portion of the GBATEK reference.
|
||||||
//!
|
//!
|
||||||
|
@ -136,7 +136,7 @@ pub const IE: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0200) };
|
||||||
///
|
///
|
||||||
/// The main user interrupt handler will acknowledge the interrupt that was set
|
/// The main user interrupt handler will acknowledge the interrupt that was set
|
||||||
/// by writing to this register, so there is usually no need to modify it.
|
/// by writing to this register, so there is usually no need to modify it.
|
||||||
/// However, if the main interrupt handler in `crt0.s` is changed, then the
|
/// However, if the main interrupt handler in `rsrt0.S` is changed, then the
|
||||||
/// handler must write a `1` bit to all bits that are enabled on this register
|
/// handler must write a `1` bit to all bits that are enabled on this register
|
||||||
/// when it is called.
|
/// when it is called.
|
||||||
pub const IF: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0202) };
|
pub const IF: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0202) };
|
||||||
|
@ -185,7 +185,7 @@ pub fn set_irq_handler(handler: IrqHandler) {
|
||||||
|
|
||||||
extern "C" fn default_handler(_flags: IrqFlags) {}
|
extern "C" fn default_handler(_flags: IrqFlags) {}
|
||||||
|
|
||||||
// Inner definition of the interrupt handler. It is referenced in `crt0.s`.
|
// Inner definition of the interrupt handler. It is referenced in `rsrt0.S`.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
static mut __IRQ_HANDLER: IrqHandler = default_handler;
|
static mut __IRQ_HANDLER: IrqHandler = default_handler;
|
||||||
|
|
|
@ -2,46 +2,8 @@
|
||||||
__start:
|
__start:
|
||||||
b .Linit
|
b .Linit
|
||||||
|
|
||||||
@ ROM header
|
@ this is replaced with correct header info by `gbafix`
|
||||||
.byte 0x24,0xff,0xae,0x51,0x69,0x9a,0xa2,0x21,0x3d,0x84,0x82,0x0a,0x84,0xe4,0x09,0xad
|
.space 188
|
||||||
.byte 0x11,0x24,0x8b,0x98,0xc0,0x81,0x7f,0x21,0xa3,0x52,0xbe,0x19,0x93,0x09,0xce,0x20
|
|
||||||
.byte 0x10,0x46,0x4a,0x4a,0xf8,0x27,0x31,0xec,0x58,0xc7,0xe8,0x33,0x82,0xe3,0xce,0xbf
|
|
||||||
.byte 0x85,0xf4,0xdf,0x94,0xce,0x4b,0x09,0xc1,0x94,0x56,0x8a,0xc0,0x13,0x72,0xa7,0xfc
|
|
||||||
.byte 0x9f,0x84,0x4d,0x73,0xa3,0xca,0x9a,0x61,0x58,0x97,0xa3,0x27,0xfc,0x03,0x98,0x76
|
|
||||||
.byte 0x23,0x1d,0xc7,0x61,0x03,0x04,0xae,0x56,0xbf,0x38,0x84,0x00,0x40,0xa7,0x0e,0xfd
|
|
||||||
.byte 0xff,0x52,0xfe,0x03,0x6f,0x95,0x30,0xf1,0x97,0xfb,0xc0,0x85,0x60,0xd6,0x80,0x25
|
|
||||||
.byte 0xa9,0x63,0xbe,0x03,0x01,0x4e,0x38,0xe2,0xf9,0xa2,0x34,0xff,0xbb,0x3e,0x03,0x44
|
|
||||||
.byte 0x78,0x00,0x90,0xcb,0x88,0x11,0x3a,0x94,0x65,0xc0,0x7c,0x63,0x87,0xf0,0x3c,0xaf
|
|
||||||
.byte 0xd6,0x25,0xe4,0x8b,0x38,0x0a,0xac,0x72,0x21,0xd4,0xf8,0x07
|
|
||||||
|
|
||||||
@ game title
|
|
||||||
.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
|
||||||
|
|
||||||
@ game code
|
|
||||||
.byte 0x00,0x00,0x00,0x00
|
|
||||||
|
|
||||||
@ maker code
|
|
||||||
.byte 0x00,0x00
|
|
||||||
|
|
||||||
.byte 0x96
|
|
||||||
|
|
||||||
@ main unit code
|
|
||||||
.byte 0x00
|
|
||||||
|
|
||||||
@ device type (0x00 retail, 0x80 debug)
|
|
||||||
.byte 0x00
|
|
||||||
|
|
||||||
@ reserved
|
|
||||||
.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
|
||||||
|
|
||||||
@ software version
|
|
||||||
.byte 0x00
|
|
||||||
|
|
||||||
@ complement check
|
|
||||||
.byte 0x51
|
|
||||||
|
|
||||||
@ reserved area
|
|
||||||
.space 2
|
|
||||||
|
|
||||||
.Linit:
|
.Linit:
|
||||||
@ Set address of user IRQ handler
|
@ Set address of user IRQ handler
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
"abi-blacklist": [
|
|
||||||
"stdcall",
|
|
||||||
"fastcall",
|
|
||||||
"vectorcall",
|
|
||||||
"thiscall",
|
|
||||||
"win64",
|
|
||||||
"sysv64"
|
|
||||||
],
|
|
||||||
"arch": "arm",
|
|
||||||
"atomic-cas": false,
|
|
||||||
"cpu": "arm7tdmi",
|
|
||||||
"data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
|
|
||||||
"emit-debug-gdb-scripts": false,
|
|
||||||
"env": "agb",
|
|
||||||
"executables": true,
|
|
||||||
"features": "+soft-float,+strict-align",
|
|
||||||
"linker": "arm-none-eabi-ld",
|
|
||||||
"linker-flavor": "ld",
|
|
||||||
"linker-is-gnu": true,
|
|
||||||
"llvm-target": "thumbv4-none-agb",
|
|
||||||
"os": "none",
|
|
||||||
"panic-strategy": "abort",
|
|
||||||
"pre-link-args-crt": {
|
|
||||||
"ld": [
|
|
||||||
"crt0.o"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pre-link-args": {
|
|
||||||
"ld": [
|
|
||||||
"-Tlinker.ld"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"relocation-model": "static",
|
|
||||||
"target-c-int-width": "32",
|
|
||||||
"target-endian": "little",
|
|
||||||
"target-pointer-width": "32",
|
|
||||||
"vendor": "nintendo"
|
|
||||||
}
|
|
Loading…
Reference in a new issue