From 5114f894481f702ebab9a4ef601092b35ff018c0 Mon Sep 17 00:00:00 2001 From: Neil P Date: Sat, 20 Feb 2021 14:49:40 -0400 Subject: [PATCH] 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 --- .cargo/config.toml | 8 +++--- .github/workflows/ci.yaml | 26 ++++++++---------- Cargo.toml | 6 +++++ Makefile.toml | 57 ++++++++++++++++++++++++--------------- README.md | 25 ++++++++++++++++- bors.toml | 1 - build.rs | 17 ++++++++++++ linker.ld | 2 +- src/io/irq.rs | 10 +++---- crt0.s => src/rsrt0.S | 42 ++--------------------------- thumbv4-none-agb.json | 39 --------------------------- 11 files changed, 105 insertions(+), 128 deletions(-) delete mode 100644 bors.toml create mode 100644 build.rs rename crt0.s => src/rsrt0.S (59%) delete mode 100644 thumbv4-none-agb.json diff --git a/.cargo/config.toml b/.cargo/config.toml index a64d5bd..03b1d63 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,3 @@ -[build] -target = "thumbv4-none-agb.json" - -[unstable] -build-std = ["core"] +[target.thumbv4t-none-eabi] +rustflags = ["-Clink-arg=-Tlinker.ld"] +runner = "mgba" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 785f5ae..4827387 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,44 +6,40 @@ on: jobs: build: - runs-on: ubuntu-latest - container: devkitpro/devkitarm:latest + runs-on: ubuntu-20.04 strategy: matrix: rust: - { toolchain: nightly } steps: - - uses: actions/checkout@v2 - - name: Add devkitARM bin to PATH - run: echo "/opt/devkitpro/devkitARM/bin" >> $GITHUB_PATH - 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 with: profile: minimal toolchain: ${{ matrix.rust.toolchain }} default: true - - uses: Swatinem/rust-cache@v1 - name: Install Rust Source 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 uses: actions-rs/install@v0.1 with: crate: cargo-make version: latest 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 with: toolchain: ${{ matrix.rust.toolchain }} command: make - args: test linux + args: test - name: Make Release uses: actions-rs/cargo@v1 with: diff --git a/Cargo.toml b/Cargo.toml index e08658e..76cf1ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,12 @@ gba-proc-macro = "0.5" embedded-hal = { version = "0.2.4", optional = true } nb = { version = "1.0.0", optional = true } +[profile.dev] +lto = false +panic = "abort" +incremental = false +codegen-units = 1 + [profile.release] lto = true panic = "abort" diff --git a/Makefile.toml b/Makefile.toml index db6222d..ddfea61 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -1,55 +1,70 @@ [config] skip_core_tasks = true -[tasks.create-target-dir] +[tasks.verify-toolchain] 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] -dependencies = ["assemble"] +dependencies = ["verify-toolchain"] command = "cargo" -args = ["build", "--examples"] +args = ["build", "--examples", "--target=thumbv4t-none-eabi", "-Zbuild-std=core"] [tasks.build-examples-release] -dependencies = ["assemble"] +dependencies = ["verify-toolchain"] command = "cargo" -args = ["build", "--examples", "--release"] +args = ["build", "--examples", "--release", "--target=thumbv4t-none-eabi", "-Zbuild-std=core"] [tasks.pack-roms] script_runner = "@duckscript" script = [ ''' +release_target = get_env RELEASE_TARGET +examples_path = set ./target/thumbv4t-none-eabi/${release_target}/examples examples = glob_array ./examples/*.rs for example in ${examples} example = substring ${example} -3 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 ''' ] -[tasks.test.linux] -command = "cargo" -args = ["test", "--lib", "--target", "x86_64-unknown-linux-gnu", "-Z", "build-std"] +[tasks.pack-roms-release] +dependencies = ["build-examples-release"] +env = { RELEASE_TARGET = "release" } +run_task = "pack-roms" -[tasks.test.windows] -command = "cargo" -args = ["test", "--lib", "--target", "x86_64-pc-windows-msvc", "-Z", "build-std"] +[tasks.pack-roms-debug] +dependencies = ["build-examples-debug"] +env = { RELEASE_TARGET = "debug" } +run_task = "pack-roms" -[tasks.test.mac] +[tasks.test] +dependencies = ["verify-toolchain"] command = "cargo" -args = ["test", "--lib", "--target", "x86_64-apple-darwin", "-Z", "build-std"] +args = ["test", "--lib"] [tasks.justrelease] -dependencies = ["build-examples-release", "pack-roms"] +dependencies = ["pack-roms-release"] [tasks.build-all] -dependencies = ["build-examples-debug", "build-examples-release", "pack-roms"] +dependencies = ["pack-roms-debug", "pack-roms-release"] [tasks.default] alias = "build-all" diff --git a/README.md b/README.md index 412808c..2d4461e 100644 --- a/README.md +++ b/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) -[![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) [![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 * 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 Writing a Rust program for the GBA requires a fair amount of special setup. All diff --git a/bors.toml b/bors.toml deleted file mode 100644 index 359f894..0000000 --- a/bors.toml +++ /dev/null @@ -1 +0,0 @@ -status = ["continuous-integration/travis-ci/push"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..9424dba --- /dev/null +++ b/build.rs @@ -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); +} \ No newline at end of file diff --git a/linker.ld b/linker.ld index 0be97b2..47bdfab 100644 --- a/linker.ld +++ b/linker.ld @@ -8,7 +8,7 @@ MEMORY { SECTIONS { .text : { - KEEP(target/crt0.o(.text)); + KEEP(rsrt0.o(.text)); *(.text .text.*); . = ALIGN(4); } >rom = 0xff diff --git a/src/io/irq.rs b/src/io/irq.rs index 533099d..f225629 100644 --- a/src/io/irq.rs +++ b/src/io/irq.rs @@ -6,7 +6,7 @@ //! pointer and execution will jump to the user interrupt handler starting at //! `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. //! 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). @@ -27,7 +27,7 @@ //! This is done by setting the corresponding IRQ flag on //! [`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 -//! 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 //! 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 @@ -78,7 +78,7 @@ //! //! ## 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 //! User Interrupt Handling_ portion of the GBATEK reference. //! @@ -136,7 +136,7 @@ pub const IE: VolAddress = unsafe { VolAddress::new(0x400_0200) }; /// /// 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. -/// 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 /// when it is called. pub const IF: VolAddress = unsafe { VolAddress::new(0x400_0202) }; @@ -185,7 +185,7 @@ pub fn set_irq_handler(handler: IrqHandler) { 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)] #[no_mangle] static mut __IRQ_HANDLER: IrqHandler = default_handler; diff --git a/crt0.s b/src/rsrt0.S similarity index 59% rename from crt0.s rename to src/rsrt0.S index 06aceb4..b45e64f 100644 --- a/crt0.s +++ b/src/rsrt0.S @@ -2,46 +2,8 @@ __start: b .Linit - @ ROM header - .byte 0x24,0xff,0xae,0x51,0x69,0x9a,0xa2,0x21,0x3d,0x84,0x82,0x0a,0x84,0xe4,0x09,0xad - .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 + @ this is replaced with correct header info by `gbafix` + .space 188 .Linit: @ Set address of user IRQ handler diff --git a/thumbv4-none-agb.json b/thumbv4-none-agb.json deleted file mode 100644 index d1de486..0000000 --- a/thumbv4-none-agb.json +++ /dev/null @@ -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" -}