45 个版本

新版本 0.4.5 2024年8月24日
0.4.3 2024年7月13日
0.3.3 2024年3月25日
0.2.11 2023年11月16日
0.0.0 2021年6月9日

#1242游戏开发

Download history 208/week @ 2024-05-03 146/week @ 2024-05-10 73/week @ 2024-05-17 272/week @ 2024-05-24 176/week @ 2024-05-31 70/week @ 2024-06-07 38/week @ 2024-06-14 13/week @ 2024-06-21 5/week @ 2024-06-28 22/week @ 2024-07-05 151/week @ 2024-07-12 13/week @ 2024-07-19 17/week @ 2024-07-26 15/week @ 2024-08-02 137/week @ 2024-08-09 54/week @ 2024-08-16

每月224 次下载
17 个crate中 使用

MIT/Apache 和可能 GPL-3.0+

5MB
112K SLoC

模块化低级Playdate API

低级绑定到Playdate API,可选适配官方文档和可选lang-items。

论文陈述中的主要概念

  1. 当我们遇到错误且无法恢复时必须panic。例如,当我们在api中遇到空指针时,这是致命的。
  2. 当API返回错误时,我们必须返回错误。

这看起来相当硬核。这就是为什么有四种以上的方式可以访问API端点,其中包括返回 OptionResult

我已经在将整个API包装在结果中的每个步骤中进行了足够的实验,然后痛苦地优化了它们的展开。最终,我得出结论,在这个特定的项目中,错误/结果的数量应该最小化。

内容

  • cffi绑定
  • 预生成的cffi绑定
  • 最小必需部分,如lang-items
  • 简单的入口点
  • 额外的工具,如println

先决条件

MNRV1.81.0 from 2024-06-30

  1. Rust nightly 工具链 (rustup是可选的)
  2. Playdate SDK
    • 确保环境变量 PLAYDATE_SDK_PATH 指向SDK根目录
  3. 遵循 官方文档
    • 确保在您的 PATH 中有 arm-none-eabi-gccgcc-arm-none-eabi

用法

应用程序的最小示例
  1. 使用crate-type设置库
  2. 添加playdate-sys依赖项

Cargo.toml

[lib]
name = "example"
path = "src/lib.rs"
crate-type = [
	"dylib",     # for simulator
	"staticlib", # for hardware
]

[dependencies.pd]
package = "playdate-sys"
git = "this/repo/path.git"
  1. 接下来是初始化代码和打印所有接收事件代码的最小要求

src/lib.rs

#![no_std]
use core::ffi::*;

#[macro_use]
extern crate alloc;

#[macro_use]
extern crate pd;
use pd::ffi::*;


#[no_mangle]
// Note: `_arg` is a key-code in simulator, otherwise it's just zero.
pub extern "C" fn eventHandlerShim(api: *const PlaydateAPI, event: PDSystemEvent, _arg: u32) -> c_int {
	match event {
		PDSystemEvent::kEventInit => unsafe {
			// register the API entry point
			pd::API = api;
			// get `setUpdateCallback` fn
			let f = (*(*api).system).setUpdateCallback.unwrap();
			// register update callback
			f(Some(on_update), core::ptr::null_mut());

			// `println` uses `API` internally, that set above
			println!("Init, Hello world!");
		},

		PDSystemEvent::kEventLock => println!("Lock"),
		PDSystemEvent::kEventUnlock => println!("Unlock"),
		PDSystemEvent::kEventPause => println!("Pause"),
		PDSystemEvent::kEventResume => println!("Resume"),
		PDSystemEvent::kEventLowPower => println!("LowPower"),
		PDSystemEvent::kEventTerminate => println!("Terminate"),
		PDSystemEvent::kEventInitLua => println!("InitLua"),
		// simulator only, keyboard events:
		PDSystemEvent::kEventKeyPressed => println!("KeyPressed"),
		PDSystemEvent::kEventKeyReleased => println!("KeyReleased"),
	}

	0 // zero means "OK, no error, continue please"
}

unsafe extern "C" fn on_update(_: *mut c_void) -> i32 { 1 /* `1` means "OK, continue updates" */ }
  1. 还要添加以下必要的配置

.cargo/config.toml

[target.thumbv7em-none-eabihf]
rustflags = [
	"-Ctarget-cpu=cortex-m7",
	"-Ctarget-feature=-fp64",
	"-Clink-args=--emit-relocs",
	"-Crelocation-model=pic",
	"-Csoft-float=no",
	"-Clink-arg=--cref",
	"-Clink-arg=--gc-sections",
	"-Clink-arg=--entry=eventHandlerShim"
]

# Also I recommend to allow unstable options here:
[unstable]
unstable-options = true
  1. 现在构建它
cargo build --lib --release --target=thumbv7em-none-eabihf -Zbuild-std=core,alloc -Zunstable-options
# Note: on windows use gcc-arm-none-eabi instead
arm-none-eabi-gcc ./target/thumbv7em-none-eabihf/release/libexample.a \
			-nostartfiles -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 \
			-Wl,--cref,--gc-sections,--no-warn-mismatch,--emit-relocs -mword-relocations \
			-fno-common -fno-exceptions \
			-T$PLAYDATE_SDK_PATH/C_API/buildsupport/link_map.ld \
			-o ./target/thumbv7em-none-eabihf/release/example.elf \
			--entry eventHandlerShim
# Then prepare package with manifest and assets, place into it example.elf and call
# `$PLAYDATE_SDK_PATH/bin/pdc` with path of prepared package.
  1. 然后准备带有清单和资产的包,将其中的example.elf放入其中,然后使用准备好的包的路径调用$PLAYDATE_SDK_PATH/bin/pdc
  2. 在设备上安装并运行。

⚠️ 注意,cargo-playdate 可以轻松完成所有操作。它还可以构建可执行二进制文件。


请参阅 示例

配置配置文件

一个小建议是将以下内容添加到您的Cargo.toml中

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"
opt-level = "s"         # optimize for binary size (or use `3`, play with it)
overflow-checks = false # runtime integer overflow checks. (optionally, as you wish)
lto = "fat"
incremental = false
codegen-units = 1

debug = 0
strip = "symbols"        # or debuginfo
debug-assertions = false

这只是建议,因为这是完全可选的,包括例如 panic = "abort"(撤销在这里具有挑战性但并非不可能)。

配置

您可以控制的一些主要功能类型

  • bindgen-... 控制绑定生成器和额外的代码生成功能
  • bindings-... 用于为类型启用 derive 以及一些代码生成,如文档
  • lang-items 和其他手工制作的事物。

控制包含的部分

此包包含构建您的应用程序所需的一些最小“部分”。

您可以禁用功能以防止它们被启用,这样您就可以使用其他分配器或 panic-handler 等。

  • allocator:全局分配器
  • panic-handler:全局 panic 处理器
  • eh-personality:模拟器目标的 eh_personality,空,无操作

非默认功能

  • entry-point:简单的最小代理入口点,在应用程序初始化时缓存 API 端点。

控制绑定生成

默认情况下,如果为您的配置(目标、配置文件、派生等)预生成了绑定,则使用它而不是构建新的。

⚠️ 环境变量 PLAYDATE_SDK_PATH 必须指向 PlayDate SDK 目录,如官方文档中所述

要防止这种行为,请仅使用 预构建 绑定设置环境变量 IGNORE_EXISTING_PLAYDATE_SDK=1

这里使用 bindgen 生成绑定,并重新导出一些功能

  • 使用 bindgen-runtime 开启/关闭使用 libclang 的运行时链接(dlopen)。同样适用于 bindgen-static。有关更多信息,请参阅bindgen 文档
  • 使用类似 bindings-derive-{name} 的功能来请求 bindgen 将 {name} 派生到所有实体(如果可能的话)
    • 派生功能的完整列表
      • bindings-derive-default
      • bindings-derive-eq
      • bindings-derive-copy
      • bindings-derive-debug
      • bindings-derive-hash
      • bindings-derive-ord
      • bindings-derive-partialeq
      • bindings-derive-partialord

开发

此包应尽可能保持低级。

只有在它是

  • 绝对必要的小东西的情况下
  • 才有可能添加额外的东西
  • 为 api 类型实现第三方 traits(包括核心的其他包)
  • 功能门控,如果该事物有依赖项或不是如此之小。

扩展开发

您可以根据此包添加功能。只需创建一个新的您自己的包并重新导出所有功能即可。

我必须重复一遍,我为打扰您表示歉意。

⚠️ 如果您想创建一个基于此库的库,请分享以下该包的功能,以便每个人都能正确配置整个依赖树

  • bindgen-runtime
  • bindgen-static

如果用户使用这些扩展中的多个,这一点尤为重要。如果它们指定不同的配置,可能会造成混乱。

  • cargo创建一个新的扩展名称
  • cargo添加 playdate-sys
  • 将上述所有功能复制并粘贴到您的 Cargo.toml 中,如下所示
    [features]
    default = ["playdate-sys/default"]
    bindgen-runtime = ["playdate-sys/bindgen-runtime"]
    bindgen-static = ["playdate-sys/bindgen-static"]
    bindings-derive-debug = ["playdate-sys/bindings-derive-debug"]
    

例如,请参阅 repo/api 中现有的 crates。

如何生成预构建绑定?

这是一个完整的示例,展示如何生成带有文档注释的绑定,但文档是可选的,因此您可以省略它 - 只需删除所有关于文档的内容

  • bindings-documentation 功能
  • 执行 playdate-docs-parser
  • 执行 rustfmt
mk dir -p ./api/sys/gen

export PD_BUILD_PREBUILT=1

# all features excluding static- or runtime- linking bingen with libclang:
DERIVES_ALL=bindings-derive-default,bindings-derive-eq,bindings-derive-copy,bindings-derive-debug,bindings-derive-hash,bindings-derive-ord,bindings-derive-partialeq,bindings-derive-partialord
DERIVES_DEF=bindings-derive-debug

FEATURES_DEF=--features=bindings-documentation,$DERIVES_DEF
FEATURES_ALL=--features=bindings-documentation,$DERIVES_ALL

cargo build -p=playdate-sys $FEATURES_DEF
cargo build -p=playdate-sys $FEATURES_DEF --target=thumbv7em-none-eabihf

cargo build -p=playdate-sys $FEATURES_ALL
cargo build -p=playdate-sys $FEATURES_ALL --target=thumbv7em-none-eabihf

# optionally format bindings:
rustfmt ./api/sys/gen/*.rs

重要提示: 要触发预构建绑定的更改,您需要设置环境变量:PD_BUILD_PREBUILT,这允许在 OUT_DIR 之外进行更改。


本软件未获得 Panic 的赞助或支持。

依赖项