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

Automatically update Cargo.toml features when updating bindings #24

Merged
merged 1 commit into from
Feb 25, 2024
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
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ log-build = ["dep:env_logger"]

vitasdk-utils = []

# Stub libraries
# Automatically generated by build-util:
all-stubs = [
"SceAVConfig_stub",
"SceAppMgrForDriver_stub",
Expand Down Expand Up @@ -371,10 +371,12 @@ SceLibDbg_stub = []
SceLibG729_stub = []
SceLibJson_stub = []
SceLibKernel_stub = []
SceLibMonoBridge_stub = []
SceLibMono_stub = []
SceLibMp4Recorder_stub = []
SceLibMtp_stub = []
SceLibXml_stub = []
SceLibc_stub = []
SceLiveArea_stub = []
SceLocationExtension_stub = []
SceLocation_stub = []
Expand Down Expand Up @@ -441,6 +443,7 @@ SceRazorHud_stub = []
SceRegMgrForDriver_stub = []
SceRegMgrServiceForDriver_stub = []
SceRegistryMgr_stub = []
SceRtabi_stub = []
SceRtcForDriver_stub = []
SceRtc_stub = []
SceRudp_stub = []
Expand Down Expand Up @@ -471,6 +474,7 @@ SceSqlite_stub = []
SceSsl_stub = []
SceStdio_0931_stub = []
SceSulpha_stub = []
SceSysclibForDriver_stub = []
SceSysconForDriver_stub = []
SceSysmemForDriver_0990_stub = []
SceSysmemForDriver_stub = []
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Example: to find which stub is required to use `sceDisplaySetFrameBuf`, search
for it on docs.rs. You'll find `Available on crate feature SceDisplay_stub only.`
there, which means that you'll need to enable `SceDisplay_stub` to use it.

> ℹ️ **NOTE**: There are a few (currently 4) conflicting stubs, which are stubs
that define symbols that are also defined by compiler builtins or std. A list of
those features can be found [here](https://github.com/vita-rust/vitasdk-sys/blob/main/build-util/src/vita_headers_db.rs#L10).

### `vitasdk-utils`

This feature just enables some functions provided by vitasdk. Just like the
Expand Down Expand Up @@ -72,8 +76,6 @@ $ git pull
$ cd ..
```

Run `cargo run -p vitasdk-sys-build-util -- stub-libs --as-features --all-stubs-feature` and replace stub lib features in vitasdk-sys Cargo.toml with outputted ones.

Then run `cargo run -p vitasdk-sys-build-util -- bindgen`

> ℹ️ **NOTE**: The LLVM version currently used in CI is 16. Occasionally there may be slight differences in generated bindings depending on your LLVM version.
Expand Down
14 changes: 12 additions & 2 deletions build-util/src/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use std::{env, fs, io, path::Path, process};
use quote::ToTokens;
use syn::{self, visit_mut::VisitMut};

use crate::visitors::{Link, Sort};
use crate::{
visitors::{Link, Sort},
vita_headers_db::VitaDb,
};

pub fn generate(
vita_headers_include: &Path,
Expand All @@ -22,7 +25,14 @@ pub fn generate(
"Loading vita-headers metadata yaml files from \"{}\"",
db.to_string_lossy()
);
let link = Link::load(db, vitasdk_sys_manifest);
let db = VitaDb::load(db);
let link = Link::load(&db);

if is_build_rs {
db.check_missing_manifest_features(vitasdk_sys_manifest);
} else {
db.update_manifest_features(vitasdk_sys_manifest);
}

link.visit(&mut bindings);

Expand Down
35 changes: 3 additions & 32 deletions build-util/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,6 @@ Options:
-c, --conflicting Print only stub libs with conflicting symbols
--with-conflicting Include stub libs with conflicting symbols
--missing-features Print only undefined vitasdk-sys stub features
--as-features Print stub libs as cargo features
--all-stubs-feature Prepend `all-stubs` feature if `--as-features` specified
--missing-libs Print only stub libs which do not exist in `$VITASDK/arm-vita-eabi/lib`
--fail-if-any Fail if any stub lib is printed
"
Expand All @@ -99,8 +97,6 @@ Options:
Conflicting,
WithConflicting,
MissingFeatures,
AsFeatures,
AllStubsFeature,
MissingLibs,
FailIfAny,
}
Expand All @@ -119,8 +115,6 @@ Options:
"-c" | "--conflicting" => Ok(Flag::Conflicting),
"--with-conflicting" => Ok(Flag::WithConflicting),
"--missing-features" => Ok(Flag::MissingFeatures),
"--as-features" => Ok(Flag::AsFeatures),
"--all-stubs-feature" => Ok(Flag::AllStubsFeature),
"--missing-libs" => Ok(Flag::MissingLibs),
"--fail-if-any" => Ok(Flag::FailIfAny),
_ => Err(ParseFlagError),
Expand All @@ -135,7 +129,6 @@ Options:
.collect::<Result<HashSet<Flag>, ParseFlagError>>()
.ok()
.filter(|ops| !ops.contains(&Flag::Kernel) || !ops.contains(&Flag::User))
.filter(|ops| ops.contains(&Flag::AsFeatures) || !ops.contains(&Flag::AllStubsFeature))
else {
print_help();
return ExitCode::FAILURE;
Expand Down Expand Up @@ -183,31 +176,9 @@ Options:
use std::io::{self, Write};

let mut stdout = io::stdout().lock();
if options.contains(&Flag::AsFeatures) {
if options.contains(&Flag::AllStubsFeature) {
struct DisplayAsSequence<T>(T);

impl<T> std::fmt::Debug for DisplayAsSequence<T>
where
T: IntoIterator + Copy,
T::Item: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Strings are valid feature names, so debug representation only adds quotation marks
f.debug_list().entries(self.0).finish()
}
}

writeln!(stdout, "all-stubs = {:#?}", DisplayAsSequence(&stub_libs)).unwrap();
}
stub_libs
.iter()
.for_each(|stub_lib| writeln!(stdout, "{stub_lib} = []").unwrap());
} else {
stub_libs
.iter()
.for_each(|stub_lib| writeln!(stdout, "{stub_lib}").unwrap());
}
stub_libs
.iter()
.for_each(|stub_lib| writeln!(stdout, "{stub_lib}").unwrap());
}

if !stub_libs.is_empty() && options.contains(&Flag::FailIfAny) {
Expand Down
20 changes: 2 additions & 18 deletions build-util/src/visitors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{
collections::{BTreeMap, BTreeSet},
mem,
path::Path,
rc::Rc,
};

Expand All @@ -11,7 +10,7 @@ use syn::{
MacroDelimiter, Meta, MetaList,
};

use crate::vita_headers_db::{missing_features_filter, stub_lib_name, VitaDb};
use crate::vita_headers_db::{stub_lib_name, VitaDb};

type FeatureSet = BTreeSet<Rc<str>>;

Expand All @@ -32,7 +31,7 @@ pub struct Link {
}

impl Link {
pub fn load(db: &Path, vitasdk_sys_manifest: &Path) -> Self {
pub fn load(db: &VitaDb) -> Self {
let mut link = Link {
function: DEFINED_ELSEWHERE_FUNCTIONS
.into_iter()
Expand All @@ -45,10 +44,6 @@ impl Link {
stub_libs: BTreeSet::new(),
};

let mut db = VitaDb::load(db);

let mut predicate = missing_features_filter(vitasdk_sys_manifest);

for imports in db.imports_by_firmware.values() {
for (mod_name, mod_data) in &imports.modules {
for (lib_name, lib) in &mod_data.libraries {
Expand Down Expand Up @@ -85,20 +80,9 @@ impl Link {
}
}

let conflicting_db = db.split_conflicting();
conflicting_db.stub_lib_names().for_each(|lib_stub| {
link.stub_libs.remove(lib_stub.as_str());
});

if db.stub_lib_names().any(|s| predicate(&s)) {
panic!("Missing features in vitasdk-sys `Cargo.toml`. Please run `cargo run -p vitasdk-sys-build-util -- stub-libs --as-features --all-stubs-feature` and replace stub lib features in vitasdk-sys Cargo.toml with outputed ones.")
}

link
}
}

impl Link {
pub fn visit(&self, i: &mut syn::File) {
let mut items_by_features: BTreeMap<FeatureSet, Vec<ForeignItem>> = self
.stub_libs
Expand Down
71 changes: 69 additions & 2 deletions build-util/src/vita_headers_db.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{
collections::{btree_map, BTreeMap, HashSet},
fmt, fs, io, mem,
collections::{btree_map, BTreeMap, BTreeSet, HashSet},
fmt, fs,
io::{self, Read, Seek, Write},
mem,
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -102,6 +104,51 @@ impl VitaDb {
}
}
}

pub fn update_manifest_features(&self, vitasdk_sys_manifest: &Path) {
const FEATURES_MARKER: &str = "# Automatically generated by build-util:";

let mut manifest = fs::OpenOptions::new()
.read(true)
.write(true)
.open(vitasdk_sys_manifest)
.expect("unable to open manifest");

let marker_position = {
let mut manifest_string = String::new();
manifest
.read_to_string(&mut manifest_string)
.expect("unable to read manifest");

manifest_string
.find(FEATURES_MARKER)
.expect("features marker not found in manifest")
};

manifest
.seek(io::SeekFrom::Start(u64::try_from(marker_position).unwrap()))
.expect("unable to seek manifest");

writeln!(manifest, "{}", FEATURES_MARKER).expect("unable to write to manifest");

let stub_libs: BTreeSet<_> = self.stub_lib_names().collect();

write_all_stubs_feature(&mut manifest, &stub_libs).expect("unable to write to manifest");
write_stub_features(&mut manifest, &stub_libs).expect("unable to write to manifest");

let stream_position = manifest
.stream_position()
.expect("unable to get current stream position");
manifest
.set_len(stream_position)
.expect("unable update manifest length");
}

pub fn check_missing_manifest_features(&self, vitasdk_sys_manifest: &Path) {
let predicate = missing_features_filter(vitasdk_sys_manifest);
let missing_features: Vec<_> = self.stub_lib_names().filter(predicate).collect();
log::warn!("Missing features: {missing_features:#?}\nIf you need any of those features, please open an issue so we can update vitasdk-sys.");
}
}

pub fn missing_features_filter(vitasdk_sys_manifest: &Path) -> impl FnMut(&String) -> bool {
Expand Down Expand Up @@ -319,3 +366,23 @@ pub(crate) fn stub_lib_name<'a>(
}
}
}

fn write_all_stubs_feature(sink: &mut dyn Write, stub_libs: &BTreeSet<String>) -> io::Result<()> {
writeln!(sink, "all-stubs = [")?;

for stub_lib in stub_libs
.iter()
.filter(|stub_lib| !CONFLICTING_STUB_LIBS.contains(&stub_lib.as_str()))
{
writeln!(sink, " \"{stub_lib}\",")?;
}

writeln!(sink, "]")
}

fn write_stub_features(sink: &mut dyn Write, stub_libs: &BTreeSet<String>) -> io::Result<()> {
for stub_lib in stub_libs {
writeln!(sink, "{stub_lib} = []")?;
}
Ok(())
}
6 changes: 6 additions & 0 deletions src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14085,6 +14085,9 @@ extern "C" {}
#[link(name = "SceLedForDriver_stub", kind = "static")]
#[cfg(feature = "SceLedForDriver_stub")]
extern "C" {}
#[link(name = "SceLibc_stub", kind = "static")]
#[cfg(feature = "SceLibc_stub")]
extern "C" {}
#[cfg(any(feature = "SceLibc_stub", feature = "SceSysclibForDriver_stub"))]
extern "C" {
pub fn memchr(
Expand Down Expand Up @@ -17096,6 +17099,9 @@ extern "C" {
#[link(name = "SceRegMgrServiceForDriver_stub", kind = "static")]
#[cfg(feature = "SceRegMgrServiceForDriver_stub")]
extern "C" {}
#[link(name = "SceRtabi_stub", kind = "static")]
#[cfg(feature = "SceRtabi_stub")]
extern "C" {}
#[link(name = "SceRtcForDriver_stub", kind = "static")]
#[cfg(feature = "SceRtcForDriver_stub")]
extern "C" {
Expand Down
Loading