Implemented prebuilt view. Same-process mode not working due to static variable not unifying after static link.

This commit is contained in:
Samuel Guerra 2021-10-25 22:59:32 -03:00
parent 7e500558b2
commit 6b45f54a2e
15 changed files with 159 additions and 8 deletions

3
.gitignore vendored
View File

@ -9,4 +9,5 @@ screenshot.*
wip
cargo-timing*
large-image.*
examples/_*.rs
examples/_*.rs
zero-ui-view-prebuilt/lib/zero_ui_view.*

View File

@ -47,9 +47,10 @@ image = "0.23"
# enable test util
zero-ui-core = { path = "zero-ui-core", features = ["test_util"] }
zero-ui-view = { path = "zero-ui-view" }
zero-ui-view-prebuilt = { path = "zero-ui-view-prebuilt" }
[workspace]
members = ["zero-ui-view-api", "zero-ui-view", "zero-ui-proc-macros", "zero-ui-core"]
members = ["zero-ui-view-api", "zero-ui-view", "zero-ui-view-prebuilt", "zero-ui-proc-macros", "zero-ui-core"]
exclude = ["dependencies/webrender"]
[package.metadata.docs.rs]

View File

@ -1,6 +1,8 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use zero_ui::prelude::*;
use zero_ui_view_prebuilt as zero_ui_view;
fn main() {
// zero_ui_view::run_same_process(app_main);

View File

@ -3,6 +3,8 @@ use zero_ui::core::{image::ImageLimits, timer::Timers};
use zero_ui::prelude::*;
use zero_ui::widgets::image::properties::{image_error_view, image_loading_view, ImageErrorArgs, ImageLoadingArgs};
use zero_ui_view_prebuilt as zero_ui_view;
fn main() {
// zero_ui_view::run_same_process(app_main);

View File

@ -1,15 +1,17 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use zero_ui::core::{
units::{DipPoint, DipSize},
window::WindowStateChangedArgs,
};
use zero_ui::prelude::*;
fn main() {
// zero_ui_view::run_same_process(app_main);
//use zero_ui_view_prebuilt as zero_ui_view;
zero_ui_view::init();
app_main();
fn main() {
zero_ui_view::run_same_process(app_main);
//zero_ui_view::init();
//app_main();
}
fn app_main() {

View File

@ -13,6 +13,7 @@ fn main() {
"doc" => doc(args),
"expand" => expand(args),
"build" | "b" => build(args),
"prebuild" => prebuild(args),
"clean" => clean(args),
"asm" => asm(args),
"help" | "--help" => help(args),
@ -389,6 +390,29 @@ fn release_rust_flags(is_release: bool) -> (&'static str, String) {
rust_flags
}
// do prebuild
// Compile the pre-build `zero-ui-view` release.
fn prebuild(args: Vec<&str>) {
cmd("cargo", &["build", "-p", "zero-ui-view", "--release"], &args);
let files = staticlib_files("target/release/zero_ui_view");
if files.is_empty() {
error("no `staticlib` output found");
return;
}
for file in files {
let target = format!("zero-ui-view-prebuilt/lib/{}", file_name(&file));
if let Err(e) = std::fs::copy(&file, &target) {
error(f!("failed to copy pre-build lib `{}` to `{}`, {}", file, target, e))
}
}
// test build
cmd("cargo", &["build", "-p", "zero-ui-view-prebuilt", "--release"], &[]);
}
// do clean [--test-crates] [--tools] [--workspace] [<cargo-clean-args>]
// Remove workspace, test-crates and tools target directories.
// USAGE:

View File

@ -265,6 +265,27 @@ pub fn build_test_cases() -> Vec<(String, String)> {
}
}
// Get "staticlib" crate output.
pub fn staticlib_files(path: &str) -> Vec<String> {
let unix = format!("{}.a", path);
let windows = format!("{}.lib", path);
let mut r = vec![];
if std::path::PathBuf::from(&unix).exists() {
r.push(unix);
}
if std::path::PathBuf::from(&windows).exists() {
r.push(windows);
}
r
}
// Extracts the file name from path, or panics.
pub fn file_name(path: &str) -> String {
std::path::PathBuf::from(path).file_name().unwrap().to_str().unwrap().to_owned()
}
fn glob(pattern: &str) -> Vec<String> {
match glob::glob(pattern) {
Ok(iter) => iter

View File

@ -207,7 +207,7 @@ macro_rules! context_var {
$(#[$outer])*
///
/// # ContextVar
///
///
/// This `struct` is a [`ContextVar`](crate::var::ContextVar).
#[derive(Debug, Clone, Copy)]
$vis struct $ident;

View File

@ -32,6 +32,7 @@ impl ViewConfig {
/// Returns `true` if the current process is awaiting for the config to start the
/// view process in the same process.
pub(crate) fn waiting_same_process() -> bool {
println!("[2]SAME_PROCESS_CONFIG@0x{:x}", (&SAME_PROCESS_CONFIG) as *const _ as usize);
SAME_PROCESS_CONFIG.lock().is_some()
}
@ -51,6 +52,7 @@ impl ViewConfig {
/// Wait for config from same-process.
pub fn wait_same_process() -> ViewConfig {
println!("[1]SAME_PROCESS_CONFIG@0x{:x}", (&SAME_PROCESS_CONFIG) as *const _ as usize);
let mut config = SAME_PROCESS_CONFIG.lock();
let waiter = Arc::new(Condvar::new());
*config = Some(SameProcessConfig {

View File

@ -0,0 +1,8 @@
[package]
name = "zero-ui-view-prebuilt"
version = "0.1.0"
authors = ["Samuel Guerra <sam.rodr.g@gmail.com>", "Well <well-r@hotmail.com>"]
edition = "2021"
license = "Apache-2.0"
[dependencies]

View File

@ -0,0 +1,8 @@
use std::{env, path::Path};
fn main() {
let dir = env::var("CARGO_MANIFEST_DIR").unwrap();
println!("cargo:rerun-if-changed=lib/*.lib");
println!("cargo:rerun-if-changed=lib/*.a");
println!("cargo:rustc-link-search={}", Path::new(&dir).join("lib").display());
}

View File

@ -0,0 +1,3 @@
# Build
Run `do prebuild` to compile the binaries used in this crate.

View File

@ -0,0 +1,61 @@
//! Pre-built [`zero-ui-view`].
//!
//! [`zero-ui-view`]: https://docs.rs/zero-ui-view
use std::sync::atomic::{AtomicU8, Ordering};
#[cfg(not(doc))]
#[link(name = "zero_ui_view", kind = "static")]
extern "C" {
fn extern_init();
fn extern_run_same_process(run_app: extern "C" fn()) -> !;
}
/// Call the pre-built [`init`].
///
/// [`init`]: https://docs.rs/zero-ui-view/fn.init.html
pub fn init() {
// SAFETY: this is safe.
#[cfg(not(doc))]
unsafe {
extern_init()
}
}
/// Call the pre-build [`run_same_process`].
///
/// [`run_same_process`]: https://docs.rs/zero-ui-view/fn.run_same_process.html
pub fn run_same_process(run_app: impl FnOnce() + Send + 'static) -> ! {
// SAFETY: access to `RUN` is atomic.
#[cfg(not(doc))]
unsafe {
static STATE: AtomicU8 = AtomicU8::new(ST_NONE);
const ST_NONE: u8 = 0;
const ST_SOME: u8 = 1;
const ST_TAKEN: u8 = 2;
static mut RUN: Option<Box<dyn FnOnce() + Send>> = None;
if STATE.swap(ST_SOME, Ordering::SeqCst) != ST_NONE {
panic!("expected only one call to `run_same_process`");
}
RUN = Some(Box::new(run_app));
extern "C" fn run() {
if STATE.swap(ST_TAKEN, Ordering::SeqCst) != ST_SOME {
panic!("expected only one call to `run_app` closure");
}
let run_app = unsafe { RUN.take() }.unwrap();
run_app();
}
extern_run_same_process(run);
}
#[allow(unreachable_code)]
{
unreachable!("expected `extern_run_same_process` to never return");
}
}

View File

@ -5,6 +5,9 @@ authors = ["Samuel Guerra <sam.rodr.g@gmail.com>", "Well <well-r@hotmail.com>"]
edition = "2021"
license = "Apache-2.0"
[lib]
crate-type = ["lib", "staticlib"]
[dependencies]
zero-ui-view-api = { path = "../zero-ui-view-api" }
webrender = { path = "../dependencies/webrender/webrender" }

View File

@ -114,6 +114,12 @@ pub fn init() {
}
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn extern_init() {
init()
}
/// Runs the view-process server in the current process and calls `run_app` to also
/// run the app in the current process. Note that `run_app` will be called in a different thread
/// so it must be [`Send`].
@ -172,6 +178,13 @@ pub fn run_same_process(run_app: impl FnOnce() + Send + 'static) -> ! {
}
}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn extern_run_same_process(run_app: extern "C" fn()) -> ! {
#[allow(clippy::redundant_closure)]
run_same_process(move || run_app())
}
/// The backend implementation.
pub(crate) struct App<S> {
started: bool,