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

Support static inline functions in ctru-sys #133

Merged
merged 3 commits into from
Sep 24, 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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["ctru-rs", "ctru-sys", "ctru-sys/bindgen-ctru-sys"]
members = ["ctru-rs", "ctru-sys"]
default-members = ["ctru-rs", "ctru-sys"]
resolver = "2"

Expand Down
7 changes: 5 additions & 2 deletions ctru-sys/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "ctru-sys"
version = "22.2.0+2.2.2-1"
authors = [ "Rust3DS Org", "Ronald Kinard <[email protected]>" ]
authors = ["Rust3DS Org", "Ronald Kinard <[email protected]>"]
description = "Raw bindings to libctru"
repository = "https://github.com/rust3ds/ctru-rs"
keywords = ["3ds", "libctru"]
categories = ["os", "external-ffi-bindings", "no-std", "hardware-support"]
exclude = ["bindgen.sh", "src/.gitattributes"]
exclude = ["src/.gitattributes"]
license = "Zlib"
links = "ctru"
edition = "2021"
Expand All @@ -15,6 +15,9 @@ edition = "2021"
libc = { version = "0.2.121", default-features = false }

[build-dependencies]
bindgen = { version = "0.65.1", features = ["experimental"] }
cc = "1.0"
doxygen-rs = "0.4.2"
which = "4.4.0"

[package.metadata.docs.rs]
Expand Down
8 changes: 0 additions & 8 deletions ctru-sys/bindgen-ctru-sys/Cargo.toml

This file was deleted.

62 changes: 0 additions & 62 deletions ctru-sys/bindgen-ctru-sys/src/main.rs

This file was deleted.

29 changes: 0 additions & 29 deletions ctru-sys/bindgen.sh

This file was deleted.

111 changes: 107 additions & 4 deletions ctru-sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
use bindgen::callbacks::ParseCallbacks;
use bindgen::{Builder, RustTarget};

use std::env;
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};

#[derive(Debug)]
struct CustomCallbacks;

impl ParseCallbacks for CustomCallbacks {
fn process_comment(&self, comment: &str) -> Option<String> {
Some(doxygen_rs::transform(comment))
}
}

fn main() {
let dkp_path = env::var("DEVKITPRO").unwrap();
let devkitpro = env::var("DEVKITPRO").unwrap();
let devkitarm = env::var("DEVKITARM").unwrap();
let profile = env::var("PROFILE").unwrap();
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-env-changed=DEVKITPRO");
println!("cargo:rustc-link-search=native={dkp_path}/libctru/lib");
println!("cargo:rustc-link-search=native={devkitpro}/libctru/lib");
println!(
"cargo:rustc-link-lib=static={}",
match profile.as_str() {
Expand All @@ -30,9 +45,97 @@ fn main() {
}
Err(err) => println!("cargo:warning=failed to check libctru version: {err}"),
}

let gcc_version = get_gcc_version(PathBuf::from(&devkitarm).join("bin/arm-none-eabi-gcc"));

let include_path = PathBuf::from_iter([devkitpro.as_str(), "libctru", "include"]);
let ctru_header = include_path.join("3ds.h");

let sysroot = Path::new(&devkitarm).join("arm-none-eabi");
let system_include = sysroot.join("include");
let gcc_include = PathBuf::from(format!(
"{devkitarm}/lib/gcc/arm-none-eabi/{gcc_version}/include"
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could get gcc to list these flags for us, but it doesn't seem like there's a standard way to to do it so this seems fine.

let errno_header = system_include.join("errno.h");

// Build libctru bindings
let bindings = Builder::default()
.header(ctru_header.to_str().unwrap())
.header(errno_header.to_str().unwrap())
Meziu marked this conversation as resolved.
Show resolved Hide resolved
.rust_target(RustTarget::Nightly)
.use_core()
.trust_clang_mangling(false)
.must_use_type("Result")
.layout_tests(false)
.ctypes_prefix("::libc")
.prepend_enum_name(false)
.blocklist_type("u(8|16|32|64)")
.blocklist_type("__builtin_va_list")
.blocklist_type("__va_list")
.opaque_type("MiiData")
.derive_default(true)
.wrap_static_fns(true)
.wrap_static_fns_path(out_dir.join("libctru_statics_wrapper"))
.clang_args([
"--target=arm-none-eabi",
"--sysroot",
sysroot.to_str().unwrap(),
"-isystem",
system_include.to_str().unwrap(),
"-isystem",
gcc_include.to_str().unwrap(),
"-I",
include_path.to_str().unwrap(),
"-mfloat-abi=hard",
"-march=armv6k",
"-mtune=mpcore",
"-mfpu=vfp",
"-DARM11",
"-D__3DS__",
])
.parse_callbacks(Box::new(CustomCallbacks))
.generate()
.expect("unable to generate bindings");

bindings
.write_to_file(out_dir.join("bindings.rs"))
.expect("Couldn't write bindings!");

// Compile static inline fns wrapper
let cc = Path::new(devkitarm.as_str()).join("bin/arm-none-eabi-gcc");
let ar = Path::new(devkitarm.as_str()).join("bin/arm-none-eabi-ar");

cc::Build::new()
.compiler(cc)
.archiver(ar)
.include(&include_path)
.file(out_dir.join("libctru_statics_wrapper.c"))
.flag("-march=armv6k")
.flag("-mtune=mpcore")
.flag("-mfloat-abi=hard")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have a common (function or array or something) definition for these flags, at least where they overlap between clang_args and cc::Build::flags

.flag("-mfpu=vfp")
.flag("-mtp=soft")
.flag("-Wno-deprecated-declarations")
.compile("ctru_statics_wrapper");
}

fn get_gcc_version(path_to_gcc: PathBuf) -> String {
let Output { stdout, .. } = Command::new(path_to_gcc)
.arg("--version")
.stderr(Stdio::inherit())
.output()
.unwrap();

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

stdout_str
.split(|c: char| c.is_whitespace())
.nth(4)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like gcc also has -dumpversion/-dumpfullversion flags to make this even simpler if you want

.unwrap()
.to_string()
}

fn parse_version(version: &str) -> Result<(String, String, String), &str> {
fn parse_libctru_version(version: &str) -> Result<(String, String, String), &str> {
let versions: Vec<_> = version
.split(|c| c == '.' || c == '-')
.map(String::from)
Expand Down Expand Up @@ -84,6 +187,6 @@ fn check_libctru_version() -> Result<(String, String, String), Box<dyn Error>> {
println!("cargo:rerun-if-changed={file}");
}

let (lib_major, lib_minor, lib_patch) = parse_version(lib_version)?;
let (lib_major, lib_minor, lib_patch) = parse_libctru_version(lib_version)?;
Ok((lib_major, lib_minor, lib_patch))
}
Loading
Loading