Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial pass of libctru version checking in ctru-sys #101

Merged
merged 5 commits into from
Apr 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,24 @@ A Rust wrapper library for smealum's [ctrulib](https://github.com/smealum/ctruli
## Structure

This repository is organized as follows:
* `ctru-rs`: Safe, idiomatic wrapper around `ctru-sys`.
* `ctru-sys`: Low-level, unsafe bindings to ctrulib

* `ctru-rs`: Safe, idiomatic wrapper around `ctru-sys`

* `ctru-sys`: Low-level, unsafe bindings to ctrulib.

This crate's version changes according to the version of `libctru`
used to generate the bindings, with the following convention:

* `libctru` version `X.Y.Z-W`
* `ctru-sys` version `XY.Z.P+X.Y.Z-W`

where `P` is usually 0 but may be incremented for fixes in e.g.
binding generation, `libc` dependency bump, etc.

It may be possible to build this crate against a different version of `libctru`,
but you may encounter linker errors or ABI issues. A build-time Cargo warning
(displayed when built with `-vv`) will be issued if the build script detects
a mismatch or is unable to check the installed `libctru` version.

## License

Expand Down Expand Up @@ -37,3 +53,4 @@ applies to every file in the tree, unless otherwise noted.
Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.

See [LICENSE-APACHE](https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE), [LICENSE-MIT](https://github.com/rust-lang/rust/blob/master/LICENSE-MIT), and [COPYRIGHT](https://github.com/rust-lang/rust/blob/master/COPYRIGHT) for details.

4 changes: 2 additions & 2 deletions ctru-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
authors = ["Ronald Kinard <[email protected]>"]
description = "A safe wrapper around smealum's ctrulib."
license = "https://en.wikipedia.org/wiki/Zlib_License"
license = "Zlib"
name = "ctru-rs"
version = "0.7.1"
edition = "2021"
Expand All @@ -13,7 +13,7 @@ name = "ctru"

[dependencies]
cfg-if = "1.0"
ctru-sys = { path = "../ctru-sys", version = "0.4" }
ctru-sys = { path = "../ctru-sys", version = "21.2" }
const-zero = "0.1.0"
linker-fix-3ds = { git = "https://github.com/rust3ds/rust-linker-fix-3ds.git" }
pthread-3ds = { git = "https://github.com/rust3ds/pthread-3ds.git" }
Expand Down
7 changes: 5 additions & 2 deletions ctru-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
[package]
name = "ctru-sys"
version = "0.4.1"
version = "21.2.0+2.1.2-1"
authors = ["Ronald Kinard <[email protected]>"]
license = "https://en.wikipedia.org/wiki/Zlib_License"
license = "Zlib"
links = "ctru"
edition = "2021"

[dependencies]
libc = { version = "0.2.121", default-features = false }

[build-dependencies]
which = "4.4.0"
33 changes: 28 additions & 5 deletions ctru-sys/bindgen.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
#!/usr/bin/env bash

set -euxo pipefail
set -euo pipefail

echo "Determining libctru version..."
pacman=dkp-pacman
if ! command -v $pacman &>/dev/null; then
pacman=pacman
if ! command -v $pacman &>/dev/null; then
echo >&2 "ERROR: Unable to automatically determine libctru version!"
exit 1
fi
fi

LIBCTRU_VERSION="$($pacman -Qi libctru | grep Version | cut -d: -f 2 | tr -d ' ')"

CTRU_SYS_VERSION="$(
printf '%s' "$LIBCTRU_VERSION" |
cut -d- -f1 |
sed -E 's/^([0-9]+)\.([0-9.]+)$/\1\2/'
)"

echo "Generating bindings.rs..."
bindgen "$DEVKITPRO/libctru/include/3ds.h" \
--rust-target nightly \
--use-core \
Expand All @@ -18,9 +37,9 @@ bindgen "$DEVKITPRO/libctru/include/3ds.h" \
--with-derive-default \
-- \
--target=arm-none-eabi \
--sysroot=$DEVKITARM/arm-none-eabi \
-isystem$DEVKITARM/arm-none-eabi/include \
-I$DEVKITPRO/libctru/include \
--sysroot="$DEVKITARM/arm-none-eabi" \
-isystem"$DEVKITARM/arm-none-eabi/include" \
-I"$DEVKITPRO/libctru/include" \
-mfloat-abi=hard \
-march=armv6k \
-mtune=mpcore \
Expand All @@ -29,6 +48,10 @@ bindgen "$DEVKITPRO/libctru/include/3ds.h" \
-D__3DS__ \
> src/bindings.rs

cargo run --package docstring-to-rustdoc -- src/bindings.rs
echo "Updating docstrings in bindings.rs..."
cargo run --quiet --package docstring-to-rustdoc -- src/bindings.rs

echo "Formatting generated files..."
cargo fmt --all

echo "Generated bindings for ctru-sys version \"${CTRU_SYS_VERSION}.x+${LIBCTRU_VERSION}\""
71 changes: 71 additions & 0 deletions ctru-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::env;
use std::error::Error;
use std::process::{Command, Output, Stdio};

fn main() {
let dkp_path = env::var("DEVKITPRO").unwrap();
Expand All @@ -14,4 +16,73 @@ fn main() {
_ => "ctru",
}
);

match check_libctru_version() {
Ok((maj, min, patch)) => {
eprintln!("using libctru version {maj}.{min}.{patch}");

// These are accessible by the crate during build with `env!()`.
// We might consider exporting some public constants or something.
println!("cargo:rustc-env=LIBCTRU_VERSION={maj}.{min}.{patch}");
println!("cargo:rustc-env=LIBCTRU_MAJOR={maj}");
println!("cargo:rustc-env=LIBCTRU_MINOR={min}");
println!("cargo:rustc-env=LIBCTRU_PATCH={patch}");
}
Err(err) => println!("cargo:warning=failed to check libctru version: {err}"),
}
}

fn parse_version(version: &str) -> Result<(String, String, String), &str> {
let versions: Vec<_> = version
.split(|c| c == '.' || c == '-')
.map(String::from)
.collect();

match &versions[..] {
[major, minor, patch, _build] => Ok((major.clone(), minor.clone(), patch.clone())),
_ => Err("unexpected number of version segments"),
}
}

fn check_libctru_version() -> Result<(String, String, String), Box<dyn Error>> {
let pacman = which::which("dkp-pacman").or_else(|_| which::which("pacman"))?;

let Output { stdout, .. } = Command::new(&pacman)
.args(["--query", "libctru"])
.stderr(Stdio::inherit())
.output()?;

let output_str = String::from_utf8_lossy(&stdout);

let (_pkg, lib_version) = output_str
.split_once(char::is_whitespace)
.ok_or("unexpected pacman output format")?;

let lib_version = lib_version.trim();

let cargo_pkg_version = env::var("CARGO_PKG_VERSION").unwrap();
let (_, crate_built_version) = cargo_pkg_version
.split_once('+')
.expect("crate version should have '+' delimeter");

if lib_version != crate_built_version {
return Err(format!(
"libctru version is {lib_version} but this crate was built for {crate_built_version}"
))?;
}

let Output { stdout, .. } = Command::new(pacman)
.args(["--query", "--list", "libctru"])
.stderr(Stdio::inherit())
.output()?;

for line in String::from_utf8_lossy(&stdout).split('\n') {
let Some((_pkg, file)) = line.split_once(char::is_whitespace)
else { continue };

println!("cargo:rerun-if-changed={file}");
}

let (lib_major, lib_minor, lib_patch) = parse_version(lib_version)?;
Ok((lib_major, lib_minor, lib_patch))
}
2 changes: 1 addition & 1 deletion ctru-sys/docstring-to-rustdoc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
doxygen-rs = { git = "https://github.com/Techie-Pi/doxygen-rs.git", version = "0.2.2", rev = "573f483ad63ab4662650961998d3ed093a703983" }
doxygen-rs = "0.3.1"
1 change: 1 addition & 0 deletions ctru-sys/src/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bindings.rs linguist-generated=true
Loading