abigen: Some more experiments
This commit is contained in:
parent
1084402c28
commit
8f3c2cad6a
105
Cargo.lock
generated
105
Cargo.lock
generated
|
@ -137,6 +137,26 @@ version = "1.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
|
@ -191,22 +211,21 @@ dependencies = [
|
|||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clang"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c044c781163c001b913cd018fc95a628c50d0d2dfea8bca77dad71edb16e37"
|
||||
dependencies = [
|
||||
"clang-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
|
@ -215,6 +234,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
|||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -763,6 +783,15 @@ version = "1.70.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
|
@ -815,6 +844,16 @@ version = "0.2.158"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.8"
|
||||
|
@ -845,6 +884,12 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
|
@ -875,6 +920,16 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint-dig"
|
||||
version = "0.8.4"
|
||||
|
@ -1089,6 +1144,16 @@ version = "0.2.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.2.0"
|
||||
|
@ -1477,18 +1542,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.209"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.209"
|
||||
version = "1.0.210"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1497,9 +1562,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.127"
|
||||
version = "1.0.128"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -1642,9 +1707,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
version = "2.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1985,11 +2050,13 @@ dependencies = [
|
|||
name = "vapore-abigen"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clang",
|
||||
"bindgen",
|
||||
"color-eyre",
|
||||
"env_logger",
|
||||
"log",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -4,8 +4,10 @@ edition = "2021"
|
|||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
clang = { version = "2.0.0", features = ["clang_10_0"] }
|
||||
bindgen = "0.70.1"
|
||||
color-eyre.workspace = true
|
||||
env_logger.workspace = true
|
||||
log.workspace = true
|
||||
regex = "1.10.6"
|
||||
serde = { version = "1.0.209", features = ["derive"] }
|
||||
serde_json = "1.0.128"
|
||||
|
|
79
abigen/src/apidesc.rs
Normal file
79
abigen/src/apidesc.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
use color_eyre::eyre;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct ApiDescription {
|
||||
pub callback_structs: Vec<CallbackStruct>,
|
||||
pub consts: Vec<Const>,
|
||||
pub enums: Vec<Enum>,
|
||||
pub interfaces: Vec<Interface>,
|
||||
pub structs: Vec<Struct>,
|
||||
pub typedefs: Vec<Typedef>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct CallbackStruct {
|
||||
pub callback_id: u64,
|
||||
#[serde(rename = "struct")]
|
||||
pub _struct: String,
|
||||
pub fields: Vec<StructField>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct StructField {
|
||||
#[serde(rename = "fieldname")]
|
||||
pub field_name: String,
|
||||
#[serde(rename = "fieldtype")]
|
||||
pub field_type: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Const {
|
||||
#[serde(rename = "constname")]
|
||||
pub const_name: String,
|
||||
#[serde(rename = "consttype")]
|
||||
pub const_type: String,
|
||||
#[serde(rename = "constval")]
|
||||
pub const_val: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Enum {
|
||||
#[serde(rename = "enumname")]
|
||||
pub enum_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Interface {
|
||||
#[serde(rename = "classname")]
|
||||
pub class_name: String,
|
||||
pub version_string: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Struct {
|
||||
#[serde(rename = "struct")]
|
||||
pub _struct: String,
|
||||
}
|
||||
#[derive(Debug, serde::Deserialize)]
|
||||
pub struct Typedef {
|
||||
pub typedef: String,
|
||||
}
|
||||
|
||||
impl ApiDescription {
|
||||
pub fn read(sdk_path: &Path) -> eyre::Result<ApiDescription> {
|
||||
let content = fs::read(sdk_path.join("steam_api.json"))?;
|
||||
Ok(serde_json::from_slice(&content)?)
|
||||
}
|
||||
|
||||
pub fn non_interface_names(&self) -> Vec<&str> {
|
||||
self.callback_structs
|
||||
.iter()
|
||||
.map(|item| item._struct.as_str())
|
||||
.chain(self.consts.iter().map(|item| item.const_name.as_str()))
|
||||
.chain(self.enums.iter().map(|item| item.enum_name.as_str()))
|
||||
.chain(self.structs.iter().map(|item| item._struct.as_str()))
|
||||
.chain(self.typedefs.iter().map(|item| item.typedef.as_str()))
|
||||
.collect()
|
||||
}
|
||||
}
|
|
@ -6,9 +6,12 @@ use std::{
|
|||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use color_eyre::eyre;
|
||||
use color_eyre::eyre::{self, OptionExt};
|
||||
use regex::Regex;
|
||||
|
||||
mod apidesc;
|
||||
mod rename;
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
env_logger::init();
|
||||
color_eyre::install()?;
|
||||
|
@ -17,23 +20,70 @@ fn main() -> eyre::Result<()> {
|
|||
PathBuf::from(env::var_os("PROTON_SOURCE").unwrap_or_else(|| "proton".into()))
|
||||
.join("lsteamclient");
|
||||
|
||||
let mut versions = BTreeMap::new();
|
||||
let mut interface_versions = BTreeMap::new();
|
||||
|
||||
for maybe_sdk in fs::read_dir(lsteamclient_path)? {
|
||||
for maybe_sdk in fs::read_dir(&lsteamclient_path)? {
|
||||
let sdk = maybe_sdk?;
|
||||
if !sdk.file_type()?.is_dir() {
|
||||
continue;
|
||||
}
|
||||
let this_versions = interface_versions(&sdk.path())?;
|
||||
versions.insert(sdk.file_name(), this_versions);
|
||||
let this_versions = parse_interface_versions(&sdk.path())?;
|
||||
|
||||
interface_versions.insert(sdk.file_name(), this_versions);
|
||||
}
|
||||
|
||||
println!("{:#?}", versions);
|
||||
let greatest_sdk_version = interface_versions
|
||||
.keys()
|
||||
.next_back()
|
||||
.ok_or_eyre("No SDKs found")?
|
||||
.clone();
|
||||
log::info!("Last SDK found is {:?}", greatest_sdk_version);
|
||||
|
||||
let mut sdk_by_iface = BTreeMap::new();
|
||||
|
||||
for (sdk, sdk_versions) in interface_versions.iter() {
|
||||
for iface_version in sdk_versions.values() {
|
||||
sdk_by_iface.insert(iface_version.to_string(), sdk.clone());
|
||||
}
|
||||
}
|
||||
|
||||
println!("{:#?}", sdk_by_iface);
|
||||
|
||||
let api_desc = apidesc::ApiDescription::read(&lsteamclient_path.join(&greatest_sdk_version))?;
|
||||
|
||||
let mut latest_builder = bindgen::builder()
|
||||
.header(
|
||||
lsteamclient_path
|
||||
.join(&greatest_sdk_version)
|
||||
.join("steam_api.h")
|
||||
.to_str()
|
||||
.ok_or_eyre("Invalid path")?,
|
||||
)
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||
.parse_callbacks(Box::new(rename::RenameEnumCallbacks))
|
||||
.ignore_methods()
|
||||
.ignore_functions()
|
||||
.clang_args(["-x", "c++"])
|
||||
.default_enum_style(bindgen::EnumVariation::NewType {
|
||||
is_bitfield: false,
|
||||
is_global: false,
|
||||
})
|
||||
.bitfield_enum(".*Flags")
|
||||
.vtable_generation(true);
|
||||
|
||||
// We only need the public API, steam_api.h implementation details aren't super useful
|
||||
for item in api_desc.non_interface_names() {
|
||||
latest_builder = latest_builder.allowlist_item(item);
|
||||
log::trace!("Allowing item `{}`", item);
|
||||
}
|
||||
|
||||
let latest_bindings = latest_builder.generate()?;
|
||||
latest_bindings.write_to_file("target/src/deps.rs")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn interface_versions(path: &Path) -> eyre::Result<BTreeMap<String, String>> {
|
||||
fn parse_interface_versions(path: &Path) -> eyre::Result<BTreeMap<String, String>> {
|
||||
let re = Regex::new(r#"#define\s*(STEAM[A-Z]*)_INTERFACE_VERSION\s*"([a-zA-Z0-9_]*)""#)?;
|
||||
|
||||
let mut versions = BTreeMap::new();
|
||||
|
|
56
abigen/src/rename.rs
Normal file
56
abigen/src/rename.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use bindgen::callbacks::ParseCallbacks;
|
||||
use regex::Regex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenameEnumCallbacks;
|
||||
|
||||
impl ParseCallbacks for RenameEnumCallbacks {
|
||||
fn enum_variant_name(
|
||||
&self,
|
||||
enum_name: Option<&str>,
|
||||
original_variant_name: &str,
|
||||
_variant_value: bindgen::callbacks::EnumVariantValue,
|
||||
) -> Option<String> {
|
||||
let base_name = enum_name?;
|
||||
let name = if base_name.ends_with("Flags") {
|
||||
base_name.split_at(base_name.len() - 1).0
|
||||
} else {
|
||||
base_name
|
||||
};
|
||||
let re = Regex::new(&format!("^k_{}_?(.*)$", regex::escape(name))).unwrap();
|
||||
let c = re.captures(original_variant_name)?;
|
||||
let new_name = c.get(1)?.as_str();
|
||||
if new_name.chars().next()?.is_ascii_digit() {
|
||||
Some(format!("_{}", new_name))
|
||||
} else {
|
||||
Some(new_name.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenameInterfaceCallbacks {
|
||||
interface_versions: BTreeMap<String, String>,
|
||||
re: Regex,
|
||||
}
|
||||
|
||||
impl RenameInterfaceCallbacks {
|
||||
pub fn new(interface_versions: BTreeMap<String, String>) -> Self {
|
||||
Self {
|
||||
interface_versions,
|
||||
re: Regex::new("^I(Steam[a-zA-Z]+)$").unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ParseCallbacks for RenameInterfaceCallbacks {
|
||||
fn item_name(&self, original_item_name: &str) -> Option<String> {
|
||||
let c = self.re.captures(original_item_name)?;
|
||||
let full_version = self.interface_versions.get(c.get(1)?.as_str())?;
|
||||
let (_, short_version) = full_version.split_at(full_version.len() - 3);
|
||||
|
||||
Some(format!("{}{}", original_item_name, short_version))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue