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:
Neil P 2021-02-20 14:49:40 -04:00 committed by GitHub
parent 263f7909de
commit 5114f89448
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 105 additions and 128 deletions

View file

@ -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"]

View file

@ -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:

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -1 +0,0 @@
status = ["continuous-integration/travis-ci/push"]

17
build.rs Normal file
View 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);
}

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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"
}