Add another way to load .60 files from a build script

This commit is contained in:
Olivier Goffart 2020-06-05 13:32:56 +02:00
parent 0553ab8b1a
commit 9fc60e104f
10 changed files with 219 additions and 2 deletions

View file

@ -8,12 +8,14 @@ members = [
'sixtyfps_compiler/parser_test_macro',
'api/sixtyfps-rs',
'api/sixtyfps-rs/sixtyfps-rs-macro',
'api/sixtyfps-rs/sixtyfps-build',
'api/sixtyfps-node/native',
'tools/compiler',
'tools/viewer',
'tools/syntax_updater',
'examples/graphicstest',
'examples/rusttest',
'examples/rusttest2',
'examples/rustwasmtest',
'helper_crates/const-field-offset',
'helper_crates/vtable',

View file

@ -1,6 +1,72 @@
/*!
# SixtyFPS
This create is the main entry point for project using SixtyFPS UI in rust.
## How to use:
There are two ways to use this crate.
- The `.60` code inline in a macro.
- The `.60` code in external files compiled with `build.rs`
### The .60 code in a macro
This is the simpler way, just put the
```rust
sixtyfps::sixtyfps!{
HelloWolrd := Text { text: "hello world"; }
}
fn main() {
# return; // Don't run a window in an example
HelloWolrd::default().run()
}
```
### The .60 file in external files compiled with `build.rs`
In your Cargo.toml:
FIXME! set the version
```toml
[package]
...
build = "build.rs"
[dependencies]
sixtyfps = "*"
...
[build-dependencies]
sixtyfps-build = "*"
```
In the `build.rs` file:
```ignore
fn main() {
sixtyfps_build::compile("ui/hello.60");
}
```
Then in your main file
```ignore
sixtyfps::include_modules!();
fn main() {
HelloWolrd::default().run()
}
```
*/
#![warn(missing_docs)]
pub use sixtyfps_rs_macro::sixtyfps;
/// internal re_exports used by the macro generated
#[doc(hidden)]
pub mod re_exports {
pub use const_field_offset::{self, FieldOffsets};
pub use corelib::abi::datastructures::{Component, ComponentTO, ComponentVTable, ItemTreeNode};
@ -17,3 +83,11 @@ pub mod re_exports {
#[cfg(doctest)]
mod compile_fail_tests;
/// Include the code generated with the sixtyfps-build crate from the build script
#[macro_export]
macro_rules! include_modules {
() => {
include!(env!("SIXTYFPS_INCLUDE_GENERATED"));
};
}

View file

@ -0,0 +1,12 @@
[package]
name = "sixtyfps-build"
version = "0.1.0"
authors = ["Sixty FPS <info@sixtyfps.io>"]
edition = "2018"
[lib]
path = "lib.rs"
[dependencies]
sixtyfps_compilerlib = { path = "../../../sixtyfps_compiler", features = ["rust", "display-diagnostics"] }
thiserror = "1"

View file

@ -0,0 +1,77 @@
/*!
This crate serves as a compagnon crate for the sixtyfps crate.
It is meant to be able to compile the `.60` files from your `build.rs`script
The main entry point of this crate is the gernerate() function
*/
#![warn(missing_docs)]
use sixtyfps_compilerlib::*;
use std::env;
use std::io::Write;
use std::path::Path;
/// Error returned by the `compile` function
#[derive(thiserror::Error, Debug)]
pub enum CompileError {
/// Cannot read environment variable CARGO_MANIFEST_DIR or OUT_DIR. The build script need to be run via cargo.
#[error("Cannot read environment variable CARGO_MANIFEST_DIR or OUT_DIR. The build script need to be run via cargo.")]
NotRunViaCargo,
/// Cannot load the input .60 file
#[error("Cannot load the .60 file: {0}")]
LoadError(std::io::Error),
/// Parse error. The error are printed in the stderr, and also are in the vector
#[error("{0:?}")]
CompileError(Vec<String>),
/// Cannot write the generated file
#[error("Cannot load the .60 file: {0}")]
SaveError(std::io::Error),
}
/// Compile the `.60` file and generate rust code for it.
///
/// The path is relative to the `CARGO_MANIFEST_DIR`.
///
/// The following line need to be added within your crate to include the generated code.
/// ```ignore
/// sixtyfps::include_modules!();
/// ```
pub fn compile(path: impl AsRef<std::path::Path>) -> Result<(), CompileError> {
let path = Path::new(&env::var_os("CARGO_MANIFEST_DIR").ok_or(CompileError::NotRunViaCargo)?)
.join(path.as_ref());
let source = std::fs::read_to_string(&path).map_err(CompileError::LoadError)?;
let (syntax_node, mut diag) = parser::parse(&source);
diag.current_path = path.clone();
if diag.has_error() {
let vec = diag.inner.iter().map(|d| d.message.clone()).collect();
diag.print(source);
return Err(CompileError::CompileError(vec));
}
let mut tr = typeregister::TypeRegister::builtin();
let doc = object_tree::Document::from_node(syntax_node, &mut diag, &mut tr);
run_passes(&doc, &mut diag, &mut tr);
if diag.has_error() {
let vec = diag.inner.iter().map(|d| d.message.clone()).collect();
diag.print(source);
return Err(CompileError::CompileError(vec));
}
let output_file_path = Path::new(&env::var_os("OUT_DIR").ok_or(CompileError::NotRunViaCargo)?)
.join(path.file_name().map(Path::new).unwrap_or(Path::new("sixtyfps_out.rs")));
let mut file = std::fs::File::create(&output_file_path).map_err(CompileError::SaveError)?;
let generated = generator::rust::generate(&doc.root_component, &mut diag).ok_or_else(|| {
let vec = diag.inner.iter().map(|d| d.message.clone()).collect();
diag.print(source);
CompileError::CompileError(vec)
})?;
write!(file, "{}", generated).map_err(CompileError::SaveError)?;
println!("cargo:rerun-if-changed={}", path.to_string_lossy());
println!("cargo:rustc-env=SIXTYFPS_INCLUDE_GENERATED={}", output_file_path.to_string_lossy());
Ok(())
}

View file

@ -0,0 +1,12 @@
[package]
name = "rusttest2"
version = "0.1.0"
authors = ["Sixty FPS <info@sixtyfps.io>"]
edition = "2018"
build = "build.rs"
[dependencies]
sixtyfps = { path = "../../api/sixtyfps-rs" }
[build-dependencies]
sixtyfps-build = { path = "../../api/sixtyfps-rs/sixtyfps-build" }

View file

@ -0,0 +1,3 @@
fn main() {
sixtyfps_build::compile("../cpptest/hello.60").unwrap();
}

View file

@ -0,0 +1,16 @@
sixtyfps::include_modules!();
fn main() {
let mut app = Hello::default();
app.plus_clicked.set_handler(|context, ()| {
let app = context.component.downcast::<Hello>().unwrap();
app.counter.set(app.counter.get(context) + 1);
});
app.minus_clicked.set_handler(|context, ()| {
let app = context.component.downcast::<Hello>().unwrap();
app.counter.set(app.counter.get(context) - 1);
});
app.run();
}

View file

@ -1,7 +1,11 @@
/*!
# The SixtyFPS compiler
# The SixtyFPS compiler library
The different modules tage the source code and transform into data structures
**NOTE:** This library is an internal crate for the SixtyFPS project.
This crate should not be used directly by application using SixtyFPS.
You should use the `sixtyfps` crate instead
The different modules take the source code and transform into data structures
according to the following schema
```text

View file

@ -1,3 +1,12 @@
/*!
# SixtyFPS runtime library
**NOTE:** This library is an internal crate for the SixtyFPS project.
This crate should not be used directly by application using SixtyFPS.
You should use the `sixtyfps` crate instead
*/
pub mod graphics;
pub mod input;
pub mod layout;

View file

@ -1,3 +1,11 @@
/*!
# SixtyFPS interpreter library
**NOTE:** This library is an internal crate for the SixtyFPS project.
This crate should not be used directly by application using SixtyFPS.
You should use the `sixtyfps` crate instead
*/
mod dynamic_component;
mod dynamic_type;
mod eval;