Skip to content

Commit

Permalink
Merge pull request #292 from boozook/linking-for-pdc
Browse files Browse the repository at this point in the history
Add linker-script to produce efls that acceptable for PDC, allow to use it in `cargo-playdate` with `--no-gcc`
  • Loading branch information
boozook authored Apr 12, 2024
2 parents a618faf + 3527113 commit dbb9e1b
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 48 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ sys = { version = "0.3", path = "api/sys", package = "playdate-sys", default-fea

tool = { version = "0.1", path = "support/tool", package = "playdate-tool" }
build = { version = "0.2", path = "support/build", package = "playdate-build", default-features = false }
utils = { version = "0.2", path = "support/utils", package = "playdate-build-utils", default-features = false }
utils = { version = "0.3", path = "support/utils", package = "playdate-build-utils", default-features = false }
device = { version = "0.2", path = "support/device", package = "playdate-device" }
simulator = { version = "0.1", path = "support/sim-ctrl", package = "playdate-simulator-utils", default-features = false }
bindgen = { version = "0.1", path = "support/bindgen", package = "playdate-bindgen", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion cargo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cargo-playdate"
version = "0.4.2"
version = "0.4.3"
readme = "README.md"
description = "Build tool for neat yellow console."
keywords = ["playdate", "build", "cargo", "plugin", "cargo-subcommand"]
Expand Down
9 changes: 5 additions & 4 deletions cargo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ Cargo-playdate is a cross-platform plugin for cargo that can build programs for

It can build programs written in Rust, manage assets, build package for Playdate and run on sim or device.
Usually it builds static or dynamic libraries for sim and hardware,
but also it can build executable binaries for hardware and this method produces highly optimized output with dramatically minimized size (thanks to DCE & LTO).
_\* But for binaries you're need also patched pdc from [dev-forum][]._
but also it can build executable binaries for hardware and this method produces highly optimized output with dramatically minimized size (thanks to DCE & LTO)\*.

\* For executable binaries use `--no-gcc` argument._

[dev-forum]: https://devforum.play.date/t/sdk-2-0-b2-pdc-produces-pdx-with-broken-binary/11345/28


## Prerequisites
Expand All @@ -28,7 +27,7 @@ To build programs using `cargo-playdate` you need:
To run on sim or dev with `cargo-playdate`:
1. Linux only:
- `libudev`, follow [instructions for udev crate][udev-crate-deps].
2. Windows only:
1. Windows only:
- `powershell` (used as fallback)

[sdk]: https://play.date/dev/#cardSDK
Expand All @@ -39,6 +38,8 @@ To run on sim or dev with `cargo-playdate`:
## Installation

```bash
cargo install cargo-playdate
# or
cargo install --git="https://github.com/boozook/playdate.git" --bin=cargo-playdate
```

Expand Down
51 changes: 37 additions & 14 deletions cargo/src/build/rustflags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::ops::Add;
use anyhow::Context;
use cargo::core::compiler::CompileKind;
use cargo::core::compiler::CompileTarget;
use cargo::util;
use playdate::compile::RUSTFLAGS_BIN_PLAYDATE;
use playdate::compile::RUSTFLAGS_LIB_HOST;
use playdate::compile::RUSTFLAGS_LIB_PLAYDATE;
Expand Down Expand Up @@ -46,21 +47,43 @@ impl Rustflags {
let sdk = config.sdk()
.log_err_cargo(config)
.with_context(|| "Playdate Sdk needed to build binaries")?;
let arm = config.gcc()
.log_err_cargo(config)
.with_context(|| "ARM GNU toolchain needed to build binaries")?;

let link_map = format!("-Clink-arg=-T{}", sdk.build_support().link_map().display());
let lib_search_paths = arm.lib_search_paths_for_playdate()
.or_else(|_| arm.lib_search_paths_default())?;
Self::rustflags_bin_playdate().into_iter()
.map(|s| Cow::from(*s))
.chain([link_map.into()])
.chain(lib_search_paths.into_iter().map(|s| {
"-L".to_owned().add(s.to_string_lossy().as_ref()).into()
}))
.chain(prevent_unwinding().into_iter())
.collect()
if config.no_gcc {
// export LINK MAP:
let target_dir = config.workspace
.config()
.target_dir()
.unwrap_or_default()
.unwrap_or_else(|| util::Filesystem::new("target".into()))
.into_path_unlocked()
.canonicalize()?;
let map = target_dir.join("pd.x");
if !map.exists() {
std::fs::write(&map, build::compile::LINK_MAP_BIN_SRC)?;
}
let link_map = format!("-Clink-arg=-T{}", map.display());
Self::rustflags_bin_playdate().into_iter()
.map(|s| Cow::from(*s))
.chain([link_map.into()])
.chain(prevent_unwinding().into_iter())
.collect()
} else {
let arm = config.gcc()
.log_err_cargo(config)
.with_context(|| "ARM GNU toolchain needed to build binaries")?;

let link_map = format!("-Clink-arg=-T{}", sdk.build_support().link_map().display());
let lib_search_paths = arm.lib_search_paths_for_playdate()
.or_else(|_| arm.lib_search_paths_default())?;
Self::rustflags_bin_playdate().into_iter()
.map(|s| Cow::from(*s))
.chain([link_map.into()])
.chain(lib_search_paths.into_iter().map(|s| {
"-L".to_owned().add(s.to_string_lossy().as_ref()).into()
}))
.chain(prevent_unwinding().into_iter())
.collect()
}
};


Expand Down
45 changes: 23 additions & 22 deletions cargo/src/cli/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,27 @@ use super::target::PlaydateTarget;

pub fn special_args_global() -> Vec<Arg> {
vec![
Arg::new("sdk").help("Path to Playdate SDK")
.long("sdk")
.env(SDK_ENV_VAR)
.conflicts_with("no-sdk")
.value_name("DIRECTORY")
.value_hint(clap::ValueHint::DirPath)
.value_parser(clap::builder::ValueParser::path_buf())
.num_args(1)
.global(true),
Arg::new("gcc").help("Path to GCC in ARM GNU toolchain, usually named 'arm-none-eabi-gcc'.")
.long("gcc")
.env(ARM_GCC_PATH_ENV_VAR)
.conflicts_with("no-gcc")
.value_name("EXECUTABLE")
.value_parser(clap::builder::ValueParser::path_buf())
.num_args(1)
.global(true),
// XXX: no-sdk & no-gcc are hidden because not supported yet:
flag("no-sdk", "Do not use Playdate SDK").global(true).hide(true),
flag("no-gcc", "Do not use ARM GNU toolchain, but Rust & LLVM only.").global(true)
.hide(true)
Arg::new("sdk").help("Path to Playdate SDK")
.long("sdk")
.env(SDK_ENV_VAR)
.conflicts_with("no-sdk")
.value_name("DIRECTORY")
.value_hint(clap::ValueHint::DirPath)
.value_parser(clap::builder::ValueParser::path_buf())
.num_args(1)
.global(true),
Arg::new("gcc").help("Path to GCC in ARM GNU toolchain, usually named 'arm-none-eabi-gcc'.")
.long("gcc")
.env(ARM_GCC_PATH_ENV_VAR)
.conflicts_with("no-gcc")
.value_name("EXECUTABLE")
.value_parser(clap::builder::ValueParser::path_buf())
.num_args(1)
.global(true),
// XXX: no-sdk are hidden because not supported yet:
flag("no-sdk", "Do not use Playdate SDK").global(true).hide(true),
flag("no-gcc", "Do not use ARM GNU toolchain, but Rust only.").global(true)
.long_help("Do not use ARM GNU toolchain, but Rust only. Only for executable bins for device target.")
]
}

Expand Down Expand Up @@ -475,7 +475,8 @@ fn add_globals(cmd: Command) -> Command {
.alias("dir")
.short_alias('D')
.value_hint(clap::ValueHint::DirPath)
.value_parser(clap::builder::ValueParser::path_buf()))
.value_parser(clap::builder::ValueParser::os_string())
)
.arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true))
.arg(flag("locked", "Require Cargo.lock is up to date").global(true))
.arg(flag("offline", "Run without accessing the network").global(true))
Expand Down
2 changes: 1 addition & 1 deletion support/utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-build-utils"
version = "0.2.1"
version = "0.3.0"
readme = "README.md"
description = "Utils that help to build program with Rust and Playdate API"
keywords = ["playdate", "utility"]
Expand Down
2 changes: 1 addition & 1 deletion support/utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Mainly there are utils to find existing (means already installed) Playdate SDK and GNU-ARM toolchain.

Also there are some constants such as hardcoded compilation flags.
Also there are some constants such as hardcoded compilation flags and linker-script.



Expand Down
17 changes: 15 additions & 2 deletions support/utils/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@


/// Do not forget
/// - fist positional - artifact path
/// - first positional - artifact path
/// - _this args_
/// - output path `-o`
pub const GCC_ARGS_LIB: &[&str] = &["-nostartfiles",
Expand Down Expand Up @@ -41,12 +41,15 @@ pub const RUSTFLAGS_BIN_PLAYDATE: &[&str] = &["-Ctarget-cpu=cortex-m7",
"-Clink-arg=--gc-sections",
"-Clink-arg=--entry=eventHandlerShim"];


/// Bin that we giving to PDC.
pub const PDX_BIN_NAME_ELF: &str = "pdex.elf";
/// Bin that is product of PDC.
pub const PDX_BIN_NAME_BIN: &str = "pdex.bin";
/// File-stem for bin, elf, and dylib files.
pub const PDX_BIN_NAME_STEM: &str = "pdex";
/// Extension of Playdate package (dir).
pub const PDX_PKG_EXT: &str = "pdx";
/// Playdate package manifest filename.
pub const PDX_PKG_MANIFEST_FILENAME: &str = "pdxinfo";


Expand Down Expand Up @@ -88,3 +91,13 @@ pub fn dylib_suffix_for_opt(target_family: &str, target_os: &str) -> Option<&'st
}

pub const fn static_lib_suffix() -> &'static str { "a" }


/// Compile-time path to the linker-script [LINK_MAP_BIN_SRC].
/// __Do note resolve, it contains file as dir.__
/// Path is relative to crate root by default, it depends on your rustc configuration.
pub const LINK_MAP_BIN_PATH: &str = concat!(file!(), "/../", "layout.x");

/// Linker-script for elf that built with rustc,
/// without arm-gcc and its std lib.
pub const LINK_MAP_BIN_SRC: &str = include_str!("layout.x");
102 changes: 102 additions & 0 deletions support/utils/src/layout.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* Elf layout that acceptable for PDC */

ENTRY(eventHandlerShim)

MEMORY
{
/*
Stack: 61800
Heap: 8388208
*/
ram (rwx) : ORIGIN = 0, LENGTH = 61800
}
PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);

PHDRS {
text PT_LOAD FLAGS(7); /* 7 == RWX */
}

SECTIONS
{
.text :
{
*(.text)
*(.text.*)

KEEP(*(.init))
KEEP(*(.fini))

/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)

/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)

*(.rodata*)

KEEP(*(.eh_frame*))
} :text /* PUT IT IN THE text SEGMENT */

.data :
{
__etext = .;

__data_start__ = .;
*(vtable)
*(.data*)

. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);

. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);

. = ALIGN(4);
/* fini data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);

. = ALIGN(4);
/* All data end */
__data_end__ = .;
} :text /* PUT IT IN THE text SEGMENT */

.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
*(COM)
. = ALIGN(4);
__bss_end__ = .;
} :text /* PUT IT IN THE text SEGMENT */

.reloc : {
. = ALIGN(4);
/* . = RELOC_TABLE_START; */
*(.rel*.*) /* might need to include other sections based on compiler output */
} :text /* PUT IT IN THE text SEGMENT */

/DISCARD/ :
{
*(.ARM.exidx)
}
}

0 comments on commit dbb9e1b

Please sign in to comment.