Skip to content

Commit dbb9e1b

Browse files
authored
Merge pull request #292 from boozook/linking-for-pdc
Add linker-script to produce efls that acceptable for PDC, allow to use it in `cargo-playdate` with `--no-gcc`
2 parents a618faf + 3527113 commit dbb9e1b

File tree

10 files changed

+188
-48
lines changed

10 files changed

+188
-48
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ sys = { version = "0.3", path = "api/sys", package = "playdate-sys", default-fea
2828

2929
tool = { version = "0.1", path = "support/tool", package = "playdate-tool" }
3030
build = { version = "0.2", path = "support/build", package = "playdate-build", default-features = false }
31-
utils = { version = "0.2", path = "support/utils", package = "playdate-build-utils", default-features = false }
31+
utils = { version = "0.3", path = "support/utils", package = "playdate-build-utils", default-features = false }
3232
device = { version = "0.2", path = "support/device", package = "playdate-device" }
3333
simulator = { version = "0.1", path = "support/sim-ctrl", package = "playdate-simulator-utils", default-features = false }
3434
bindgen = { version = "0.1", path = "support/bindgen", package = "playdate-bindgen", default-features = false }

cargo/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cargo-playdate"
3-
version = "0.4.2"
3+
version = "0.4.3"
44
readme = "README.md"
55
description = "Build tool for neat yellow console."
66
keywords = ["playdate", "build", "cargo", "plugin", "cargo-subcommand"]

cargo/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ Cargo-playdate is a cross-platform plugin for cargo that can build programs for
44

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

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

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

1312

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

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

4140
```bash
41+
cargo install cargo-playdate
42+
# or
4243
cargo install --git="https://github.com/boozook/playdate.git" --bin=cargo-playdate
4344
```
4445

cargo/src/build/rustflags.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::ops::Add;
55
use anyhow::Context;
66
use cargo::core::compiler::CompileKind;
77
use cargo::core::compiler::CompileTarget;
8+
use cargo::util;
89
use playdate::compile::RUSTFLAGS_BIN_PLAYDATE;
910
use playdate::compile::RUSTFLAGS_LIB_HOST;
1011
use playdate::compile::RUSTFLAGS_LIB_PLAYDATE;
@@ -46,21 +47,43 @@ impl Rustflags {
4647
let sdk = config.sdk()
4748
.log_err_cargo(config)
4849
.with_context(|| "Playdate Sdk needed to build binaries")?;
49-
let arm = config.gcc()
50-
.log_err_cargo(config)
51-
.with_context(|| "ARM GNU toolchain needed to build binaries")?;
5250

53-
let link_map = format!("-Clink-arg=-T{}", sdk.build_support().link_map().display());
54-
let lib_search_paths = arm.lib_search_paths_for_playdate()
55-
.or_else(|_| arm.lib_search_paths_default())?;
56-
Self::rustflags_bin_playdate().into_iter()
57-
.map(|s| Cow::from(*s))
58-
.chain([link_map.into()])
59-
.chain(lib_search_paths.into_iter().map(|s| {
60-
"-L".to_owned().add(s.to_string_lossy().as_ref()).into()
61-
}))
62-
.chain(prevent_unwinding().into_iter())
63-
.collect()
51+
if config.no_gcc {
52+
// export LINK MAP:
53+
let target_dir = config.workspace
54+
.config()
55+
.target_dir()
56+
.unwrap_or_default()
57+
.unwrap_or_else(|| util::Filesystem::new("target".into()))
58+
.into_path_unlocked()
59+
.canonicalize()?;
60+
let map = target_dir.join("pd.x");
61+
if !map.exists() {
62+
std::fs::write(&map, build::compile::LINK_MAP_BIN_SRC)?;
63+
}
64+
let link_map = format!("-Clink-arg=-T{}", map.display());
65+
Self::rustflags_bin_playdate().into_iter()
66+
.map(|s| Cow::from(*s))
67+
.chain([link_map.into()])
68+
.chain(prevent_unwinding().into_iter())
69+
.collect()
70+
} else {
71+
let arm = config.gcc()
72+
.log_err_cargo(config)
73+
.with_context(|| "ARM GNU toolchain needed to build binaries")?;
74+
75+
let link_map = format!("-Clink-arg=-T{}", sdk.build_support().link_map().display());
76+
let lib_search_paths = arm.lib_search_paths_for_playdate()
77+
.or_else(|_| arm.lib_search_paths_default())?;
78+
Self::rustflags_bin_playdate().into_iter()
79+
.map(|s| Cow::from(*s))
80+
.chain([link_map.into()])
81+
.chain(lib_search_paths.into_iter().map(|s| {
82+
"-L".to_owned().add(s.to_string_lossy().as_ref()).into()
83+
}))
84+
.chain(prevent_unwinding().into_iter())
85+
.collect()
86+
}
6487
};
6588

6689

cargo/src/cli/opts.rs

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,27 @@ use super::target::PlaydateTarget;
1717

1818
pub fn special_args_global() -> Vec<Arg> {
1919
vec![
20-
Arg::new("sdk").help("Path to Playdate SDK")
21-
.long("sdk")
22-
.env(SDK_ENV_VAR)
23-
.conflicts_with("no-sdk")
24-
.value_name("DIRECTORY")
25-
.value_hint(clap::ValueHint::DirPath)
26-
.value_parser(clap::builder::ValueParser::path_buf())
27-
.num_args(1)
28-
.global(true),
29-
Arg::new("gcc").help("Path to GCC in ARM GNU toolchain, usually named 'arm-none-eabi-gcc'.")
30-
.long("gcc")
31-
.env(ARM_GCC_PATH_ENV_VAR)
32-
.conflicts_with("no-gcc")
33-
.value_name("EXECUTABLE")
34-
.value_parser(clap::builder::ValueParser::path_buf())
35-
.num_args(1)
36-
.global(true),
37-
// XXX: no-sdk & no-gcc are hidden because not supported yet:
38-
flag("no-sdk", "Do not use Playdate SDK").global(true).hide(true),
39-
flag("no-gcc", "Do not use ARM GNU toolchain, but Rust & LLVM only.").global(true)
40-
.hide(true)
20+
Arg::new("sdk").help("Path to Playdate SDK")
21+
.long("sdk")
22+
.env(SDK_ENV_VAR)
23+
.conflicts_with("no-sdk")
24+
.value_name("DIRECTORY")
25+
.value_hint(clap::ValueHint::DirPath)
26+
.value_parser(clap::builder::ValueParser::path_buf())
27+
.num_args(1)
28+
.global(true),
29+
Arg::new("gcc").help("Path to GCC in ARM GNU toolchain, usually named 'arm-none-eabi-gcc'.")
30+
.long("gcc")
31+
.env(ARM_GCC_PATH_ENV_VAR)
32+
.conflicts_with("no-gcc")
33+
.value_name("EXECUTABLE")
34+
.value_parser(clap::builder::ValueParser::path_buf())
35+
.num_args(1)
36+
.global(true),
37+
// XXX: no-sdk are hidden because not supported yet:
38+
flag("no-sdk", "Do not use Playdate SDK").global(true).hide(true),
39+
flag("no-gcc", "Do not use ARM GNU toolchain, but Rust only.").global(true)
40+
.long_help("Do not use ARM GNU toolchain, but Rust only. Only for executable bins for device target.")
4141
]
4242
}
4343

@@ -475,7 +475,8 @@ fn add_globals(cmd: Command) -> Command {
475475
.alias("dir")
476476
.short_alias('D')
477477
.value_hint(clap::ValueHint::DirPath)
478-
.value_parser(clap::builder::ValueParser::path_buf()))
478+
.value_parser(clap::builder::ValueParser::os_string())
479+
)
479480
.arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true))
480481
.arg(flag("locked", "Require Cargo.lock is up to date").global(true))
481482
.arg(flag("offline", "Run without accessing the network").global(true))

support/utils/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "playdate-build-utils"
3-
version = "0.2.1"
3+
version = "0.3.0"
44
readme = "README.md"
55
description = "Utils that help to build program with Rust and Playdate API"
66
keywords = ["playdate", "utility"]

support/utils/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

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

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

77

88

support/utils/src/compile.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

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

44-
44+
/// Bin that we giving to PDC.
4545
pub const PDX_BIN_NAME_ELF: &str = "pdex.elf";
46+
/// Bin that is product of PDC.
4647
pub const PDX_BIN_NAME_BIN: &str = "pdex.bin";
4748
/// File-stem for bin, elf, and dylib files.
4849
pub const PDX_BIN_NAME_STEM: &str = "pdex";
50+
/// Extension of Playdate package (dir).
4951
pub const PDX_PKG_EXT: &str = "pdx";
52+
/// Playdate package manifest filename.
5053
pub const PDX_PKG_MANIFEST_FILENAME: &str = "pdxinfo";
5154

5255

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

9093
pub const fn static_lib_suffix() -> &'static str { "a" }
94+
95+
96+
/// Compile-time path to the linker-script [LINK_MAP_BIN_SRC].
97+
/// __Do note resolve, it contains file as dir.__
98+
/// Path is relative to crate root by default, it depends on your rustc configuration.
99+
pub const LINK_MAP_BIN_PATH: &str = concat!(file!(), "/../", "layout.x");
100+
101+
/// Linker-script for elf that built with rustc,
102+
/// without arm-gcc and its std lib.
103+
pub const LINK_MAP_BIN_SRC: &str = include_str!("layout.x");

support/utils/src/layout.x

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/* Elf layout that acceptable for PDC */
2+
3+
ENTRY(eventHandlerShim)
4+
5+
MEMORY
6+
{
7+
/*
8+
Stack: 61800
9+
Heap: 8388208
10+
*/
11+
ram (rwx) : ORIGIN = 0, LENGTH = 61800
12+
}
13+
PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
14+
15+
PHDRS {
16+
text PT_LOAD FLAGS(7); /* 7 == RWX */
17+
}
18+
19+
SECTIONS
20+
{
21+
.text :
22+
{
23+
*(.text)
24+
*(.text.*)
25+
26+
KEEP(*(.init))
27+
KEEP(*(.fini))
28+
29+
/* .ctors */
30+
*crtbegin.o(.ctors)
31+
*crtbegin?.o(.ctors)
32+
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
33+
*(SORT(.ctors.*))
34+
*(.ctors)
35+
36+
/* .dtors */
37+
*crtbegin.o(.dtors)
38+
*crtbegin?.o(.dtors)
39+
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
40+
*(SORT(.dtors.*))
41+
*(.dtors)
42+
43+
*(.rodata*)
44+
45+
KEEP(*(.eh_frame*))
46+
} :text /* PUT IT IN THE text SEGMENT */
47+
48+
.data :
49+
{
50+
__etext = .;
51+
52+
__data_start__ = .;
53+
*(vtable)
54+
*(.data*)
55+
56+
. = ALIGN(4);
57+
/* preinit data */
58+
PROVIDE_HIDDEN (__preinit_array_start = .);
59+
KEEP(*(.preinit_array))
60+
PROVIDE_HIDDEN (__preinit_array_end = .);
61+
62+
. = ALIGN(4);
63+
/* init data */
64+
PROVIDE_HIDDEN (__init_array_start = .);
65+
KEEP(*(SORT(.init_array.*)))
66+
KEEP(*(.init_array))
67+
PROVIDE_HIDDEN (__init_array_end = .);
68+
69+
. = ALIGN(4);
70+
/* fini data */
71+
PROVIDE_HIDDEN (__fini_array_start = .);
72+
KEEP(*(SORT(.fini_array.*)))
73+
KEEP(*(.fini_array))
74+
PROVIDE_HIDDEN (__fini_array_end = .);
75+
76+
. = ALIGN(4);
77+
/* All data end */
78+
__data_end__ = .;
79+
} :text /* PUT IT IN THE text SEGMENT */
80+
81+
.bss :
82+
{
83+
. = ALIGN(4);
84+
__bss_start__ = .;
85+
*(.bss*)
86+
*(COMMON)
87+
*(COM)
88+
. = ALIGN(4);
89+
__bss_end__ = .;
90+
} :text /* PUT IT IN THE text SEGMENT */
91+
92+
.reloc : {
93+
. = ALIGN(4);
94+
/* . = RELOC_TABLE_START; */
95+
*(.rel*.*) /* might need to include other sections based on compiler output */
96+
} :text /* PUT IT IN THE text SEGMENT */
97+
98+
/DISCARD/ :
99+
{
100+
*(.ARM.exidx)
101+
}
102+
}

0 commit comments

Comments
 (0)