mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 22:31:14 +00:00
Remove some duplication in the documentation of API that's shared between Rust and C++
This change makes the start of sharing the docs for the `TimerMode` enum between Rust and C++. The reference to Timer::start in there works as both doxygen and rustdoc find the right reference, but this needs careful editing in the future and double-checking! Another "caveat" is that the docs for the TimerMode enum say that the enum is defined in the file "sixtyfps_generated_public.h", which is correct as-is but not as pretty as "sixtyfps.h". I tried various ways with \file and \includedoc, but couldn't get it working differently. To implement this, the cppdocs steps now also runs cbindgen and cbindgen generates a new sixtyfps_generated_public.h file that contains types we do want to have in the public sixtyfps namespace.
This commit is contained in:
parent
81602353e2
commit
174fd2659f
6 changed files with 72 additions and 36 deletions
|
@ -20,5 +20,9 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
|
|
||||||
println!("cargo:GENERATED_INCLUDE_DIR={}", output_dir.display());
|
println!("cargo:GENERATED_INCLUDE_DIR={}", output_dir.display());
|
||||||
|
|
||||||
cbindgen::gen_all(&root_dir, &output_dir)
|
let dependencies = cbindgen::gen_all(&root_dir, &output_dir)?;
|
||||||
|
for path in dependencies {
|
||||||
|
println!("cargo:rerun-if-changed={}", path.display());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,19 @@
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use std::iter::Extend;
|
use std::iter::Extend;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
// cspell::ignore compat constexpr corelib sharedvector pathdata
|
// cspell::ignore compat constexpr corelib sharedvector pathdata
|
||||||
|
|
||||||
fn ensure_cargo_rerun_for_crate(crate_dir: &Path) -> anyhow::Result<()> {
|
fn ensure_cargo_rerun_for_crate(
|
||||||
println!("cargo:rerun-if-changed={}", crate_dir.display());
|
crate_dir: &Path,
|
||||||
|
dependencies: &mut Vec<PathBuf>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
dependencies.push(crate_dir.to_path_buf());
|
||||||
for entry in std::fs::read_dir(crate_dir)? {
|
for entry in std::fs::read_dir(crate_dir)? {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
if entry.path().extension().map_or(false, |e| e == "rs") {
|
if entry.path().extension().map_or(false, |e| e == "rs") {
|
||||||
println!("cargo:rerun-if-changed={}", entry.path().display());
|
dependencies.push(entry.path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -76,7 +79,11 @@ extern "C" {{
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
fn gen_corelib(
|
||||||
|
root_dir: &Path,
|
||||||
|
include_dir: &Path,
|
||||||
|
dependencies: &mut Vec<PathBuf>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut config = default_config();
|
let mut config = default_config();
|
||||||
|
|
||||||
let items = [
|
let items = [
|
||||||
|
@ -150,6 +157,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
"sixtyfps_color_darker",
|
"sixtyfps_color_darker",
|
||||||
"sixtyfps_image_size",
|
"sixtyfps_image_size",
|
||||||
"sixtyfps_image_path",
|
"sixtyfps_image_path",
|
||||||
|
"TimerMode", // included in generated_public.h
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
|
@ -158,7 +166,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
let mut crate_dir = root_dir.to_owned();
|
let mut crate_dir = root_dir.to_owned();
|
||||||
crate_dir.extend(["sixtyfps_runtime", "corelib"].iter());
|
crate_dir.extend(["sixtyfps_runtime", "corelib"].iter());
|
||||||
|
|
||||||
ensure_cargo_rerun_for_crate(&crate_dir)?;
|
ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;
|
||||||
|
|
||||||
let mut string_config = config.clone();
|
let mut string_config = config.clone();
|
||||||
string_config.export.exclude = vec!["SharedString".into()];
|
string_config.export.exclude = vec!["SharedString".into()];
|
||||||
|
@ -296,6 +304,20 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
.write_to_file(include_dir.join(internal_header));
|
.write_to_file(include_dir.join(internal_header));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a header file with some public API (enums, etc.)
|
||||||
|
let mut public_config = config.clone();
|
||||||
|
public_config.namespaces = Some(vec!["sixtyfps".into()]);
|
||||||
|
public_config.export.item_types = vec![cbindgen::ItemType::Enums];
|
||||||
|
public_config.export.include = vec!["TimerMode".into()];
|
||||||
|
public_config.export.exclude.clear();
|
||||||
|
|
||||||
|
cbindgen::Builder::new()
|
||||||
|
.with_config(public_config)
|
||||||
|
.with_src(crate_dir.join("timers.rs"))
|
||||||
|
.generate()
|
||||||
|
.context("Unable to generate bindings for sixtyfps_generated_public.h")?
|
||||||
|
.write_to_file(include_dir.join("sixtyfps_generated_public.h"));
|
||||||
|
|
||||||
config.export.body.insert(
|
config.export.body.insert(
|
||||||
"ItemTreeNode".to_owned(),
|
"ItemTreeNode".to_owned(),
|
||||||
" constexpr ItemTreeNode(Item_Body x) : item {x} {}
|
" constexpr ItemTreeNode(Item_Body x) : item {x} {}
|
||||||
|
@ -335,6 +357,7 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
.with_include("sixtyfps_image.h")
|
.with_include("sixtyfps_image.h")
|
||||||
.with_include("sixtyfps_pathdata.h")
|
.with_include("sixtyfps_pathdata.h")
|
||||||
.with_include("sixtyfps_brush.h")
|
.with_include("sixtyfps_brush.h")
|
||||||
|
.with_include("sixtyfps_generated_public.h")
|
||||||
.with_header(format!(
|
.with_header(format!(
|
||||||
r"
|
r"
|
||||||
#define SIXTYFPS_VERSION_MAJOR {}
|
#define SIXTYFPS_VERSION_MAJOR {}
|
||||||
|
@ -367,7 +390,11 @@ namespace sixtyfps {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_backend_qt(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
fn gen_backend_qt(
|
||||||
|
root_dir: &Path,
|
||||||
|
include_dir: &Path,
|
||||||
|
dependencies: &mut Vec<PathBuf>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut config = default_config();
|
let mut config = default_config();
|
||||||
|
|
||||||
let items = [
|
let items = [
|
||||||
|
@ -395,7 +422,7 @@ fn gen_backend_qt(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
let mut crate_dir = root_dir.to_owned();
|
let mut crate_dir = root_dir.to_owned();
|
||||||
crate_dir.extend(["sixtyfps_runtime", "rendering_backends", "qt"].iter());
|
crate_dir.extend(["sixtyfps_runtime", "rendering_backends", "qt"].iter());
|
||||||
|
|
||||||
ensure_cargo_rerun_for_crate(&crate_dir)?;
|
ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;
|
||||||
|
|
||||||
cbindgen::Builder::new()
|
cbindgen::Builder::new()
|
||||||
.with_config(config)
|
.with_config(config)
|
||||||
|
@ -409,12 +436,16 @@ fn gen_backend_qt(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_backend(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
fn gen_backend(
|
||||||
|
root_dir: &Path,
|
||||||
|
include_dir: &Path,
|
||||||
|
dependencies: &mut Vec<PathBuf>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let config = default_config();
|
let config = default_config();
|
||||||
let mut crate_dir = root_dir.to_owned();
|
let mut crate_dir = root_dir.to_owned();
|
||||||
crate_dir.extend(["api", "sixtyfps-cpp"].iter());
|
crate_dir.extend(["api", "sixtyfps-cpp"].iter());
|
||||||
|
|
||||||
ensure_cargo_rerun_for_crate(&crate_dir)?;
|
ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;
|
||||||
|
|
||||||
cbindgen::Builder::new()
|
cbindgen::Builder::new()
|
||||||
.with_config(config)
|
.with_config(config)
|
||||||
|
@ -427,14 +458,18 @@ fn gen_backend(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_interpreter(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
fn gen_interpreter(
|
||||||
|
root_dir: &Path,
|
||||||
|
include_dir: &Path,
|
||||||
|
dependencies: &mut Vec<PathBuf>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let mut config = default_config();
|
let mut config = default_config();
|
||||||
// Avoid Value, just export ValueOpaque.
|
// Avoid Value, just export ValueOpaque.
|
||||||
config.export.exclude.push("Value".into());
|
config.export.exclude.push("Value".into());
|
||||||
let mut crate_dir = root_dir.to_owned();
|
let mut crate_dir = root_dir.to_owned();
|
||||||
|
|
||||||
crate_dir.extend(["sixtyfps_runtime", "interpreter"].iter());
|
crate_dir.extend(["sixtyfps_runtime", "interpreter"].iter());
|
||||||
ensure_cargo_rerun_for_crate(&crate_dir)?;
|
ensure_cargo_rerun_for_crate(&crate_dir, dependencies)?;
|
||||||
|
|
||||||
cbindgen::Builder::new()
|
cbindgen::Builder::new()
|
||||||
.with_config(config)
|
.with_config(config)
|
||||||
|
@ -451,12 +486,15 @@ fn gen_interpreter(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
||||||
/// Generate the headers.
|
/// Generate the headers.
|
||||||
/// `root_dir` is the root directory of the sixtyfps git repo
|
/// `root_dir` is the root directory of the sixtyfps git repo
|
||||||
/// `include_dir` is the output directory
|
/// `include_dir` is the output directory
|
||||||
pub fn gen_all(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
/// Returns the list of all paths that contain dependencies to the generated output. If you call this
|
||||||
|
/// function from build.rs, feed each entry to stdout prefixed with `cargo:rerun-if-changed=`.
|
||||||
|
pub fn gen_all(root_dir: &Path, include_dir: &Path) -> anyhow::Result<Vec<PathBuf>> {
|
||||||
proc_macro2::fallback::force(); // avoid a abort if panic=abort is set
|
proc_macro2::fallback::force(); // avoid a abort if panic=abort is set
|
||||||
std::fs::create_dir_all(include_dir).context("Could not create the include directory")?;
|
std::fs::create_dir_all(include_dir).context("Could not create the include directory")?;
|
||||||
gen_corelib(root_dir, include_dir)?;
|
let mut deps = Vec::new();
|
||||||
gen_backend_qt(root_dir, include_dir)?;
|
gen_corelib(root_dir, include_dir, &mut deps)?;
|
||||||
gen_backend(root_dir, include_dir)?;
|
gen_backend_qt(root_dir, include_dir, &mut deps)?;
|
||||||
gen_interpreter(root_dir, include_dir)?;
|
gen_backend(root_dir, include_dir, &mut deps)?;
|
||||||
Ok(())
|
gen_interpreter(root_dir, include_dir, &mut deps)?;
|
||||||
|
Ok(deps)
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,8 @@ exhale_args = {
|
||||||
"doxygenStripFromPath": "..",
|
"doxygenStripFromPath": "..",
|
||||||
"createTreeView": True,
|
"createTreeView": True,
|
||||||
"exhaleExecutesDoxygen": True,
|
"exhaleExecutesDoxygen": True,
|
||||||
"exhaleDoxygenStdin": """INPUT = ../../api/sixtyfps-cpp/include
|
"exhaleDoxygenStdin": """INPUT = ../../api/sixtyfps-cpp/include generated_include
|
||||||
EXCLUDE_SYMBOLS = sixtyfps::cbindgen_private* sixtyfps::private_api* vtable*
|
EXCLUDE_SYMBOLS = sixtyfps::cbindgen_private* sixtyfps::private_api* vtable* SIXTYFPS_DECL_ITEM
|
||||||
EXCLUDE = ../../api/sixtyfps-cpp/include/vtable.h ../../api/sixtyfps-cpp/include/sixtyfps_testing.h
|
EXCLUDE = ../../api/sixtyfps-cpp/include/vtable.h ../../api/sixtyfps-cpp/include/sixtyfps_testing.h
|
||||||
ENABLE_PREPROCESSING = YES
|
ENABLE_PREPROCESSING = YES
|
||||||
PREDEFINED += DOXYGEN
|
PREDEFINED += DOXYGEN
|
||||||
|
|
|
@ -337,20 +337,6 @@ private:
|
||||||
private_api::WindowRc inner;
|
private_api::WindowRc inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(DOXYGEN)
|
|
||||||
using cbindgen_private::TimerMode;
|
|
||||||
#else
|
|
||||||
/// The TimerMode specifies what should happen after the timer fired.
|
|
||||||
///
|
|
||||||
/// Used by the sixtyfps::Timer::start() function.
|
|
||||||
enum class TimerMode {
|
|
||||||
/// A SingleShot timer is fired only once.
|
|
||||||
SingleShot,
|
|
||||||
/// A Repeated timer is fired repeatedly until it is stopped or dropped.
|
|
||||||
Repeated,
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// A Timer that can call a callback at repeated interval
|
/// A Timer that can call a callback at repeated interval
|
||||||
///
|
///
|
||||||
/// Use the static single_shot function to make a single shot timer
|
/// Use the static single_shot function to make a single shot timer
|
||||||
|
@ -367,7 +353,7 @@ struct Timer
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Timer(std::chrono::milliseconds interval, F callback)
|
Timer(std::chrono::milliseconds interval, F callback)
|
||||||
: id(cbindgen_private::sixtyfps_timer_start(
|
: id(cbindgen_private::sixtyfps_timer_start(
|
||||||
-1, cbindgen_private::TimerMode::Repeated, interval.count(),
|
-1, TimerMode::Repeated, interval.count(),
|
||||||
[](void *data) { (*reinterpret_cast<F *>(data))(); }, new F(std::move(callback)),
|
[](void *data) { (*reinterpret_cast<F *>(data))(); }, new F(std::move(callback)),
|
||||||
[](void *data) { delete reinterpret_cast<F *>(data); }))
|
[](void *data) { delete reinterpret_cast<F *>(data); }))
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,3 +16,5 @@ regex = "1.4"
|
||||||
toml_edit = "0.6.0"
|
toml_edit = "0.6.0"
|
||||||
xshell = "0.1.6"
|
xshell = "0.1.6"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
cbindgen = "0.20"
|
||||||
|
proc-macro2 = "1.0.11"
|
||||||
|
|
|
@ -7,6 +7,9 @@ use anyhow::{Context, Result};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[path = "../../api/sixtyfps-cpp/cbindgen.rs"]
|
||||||
|
mod cbindgen;
|
||||||
|
|
||||||
fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
|
fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
|
||||||
if dst.as_ref().exists() {
|
if dst.as_ref().exists() {
|
||||||
std::fs::remove_file(dst.as_ref()).context("Error removing old symlink")?;
|
std::fs::remove_file(dst.as_ref()).context("Error removing old symlink")?;
|
||||||
|
@ -80,6 +83,9 @@ pub fn generate(show_warnings: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
docs_build_dir.join("README.md"),
|
docs_build_dir.join("README.md"),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let generated_headers_dir = docs_build_dir.join("generated_include");
|
||||||
|
cbindgen::gen_all(&root, &generated_headers_dir)?;
|
||||||
|
|
||||||
let pip_env = vec![(OsString::from("PIPENV_PIPFILE"), docs_source_dir.join("docs/Pipfile"))];
|
let pip_env = vec![(OsString::from("PIPENV_PIPFILE"), docs_source_dir.join("docs/Pipfile"))];
|
||||||
|
|
||||||
println!("Running pipenv install");
|
println!("Running pipenv install");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue