Currently we provide a optee-utee-build
crate to simplify the compilcated building process of TA, and we recommend everyone use it in future developement.
Assuming currently we are developing a hello_world
TA, and we want to build it with optee-utee-build
crate, we can do it by following steps.
Firstly, we should add optee-utee-build
in build-dependencies
:
cargo add --build optee-utee-build
Secondly, we set a ta_config
and call optee-utee-build::build
with it in build.rs:
use proto; use optee_utee_build::{TaConfig, Error, RustEdition}; fn main() -> Result<(), Error> { let ta_config = TaConfig::new_default_with_cargo_env(proto::UUID)?; optee_utee_build::build(RustEdition::Before2024, ta_config) }
It will generate a user_ta_header.rs
file and setup all the required configurations of the linker of rustc.
Finally, we include the generated user_ta_header.rs
in the source codes, normally we put it in src/main.rs
.
// src/main.rs include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs"));
After that, everything finished, we can start building the TA now.
For full codes, you can check the hello_world-rs example
This is a struct that use for the configuration of the TA we are developing, it has some public fields:
We can construct the TaConfig
by providing all of the public fields manually, or use our standard constructor:
version
and description
from cargo.toml so simply providing a uuid as parameter is enough.The generated user_ta_header.rs
must be different between edition of 2024
and edition before 2024
, and currently there is no official stable way to know what edition we are compiling with, so we provide a argument to set with.
What’s the difference?
the generated
user_ta_header.rs
file include some const variables and global functions tagged withno_mangle
andlink_section
, start from rust edition of 2024, they must be wrapped with unsafe, or rustc will output a compilation error (while before edition of 2024 it must not, or rustc will output a syntax error).
optee-utee-build
provide some structs for flexible use.
Instead of calling the build
function directly, you can use Builder for customization.
Usage:
use proto; use optee_utee_build::{TaConfig, Builder, Error, RustEdition, LinkType}; fn main() -> Result<(), Error> { let ta_config = TaConfig::new_default_with_cargo_env(proto::UUID)?; Builder::new(RustEdition::Before2024, ta_config) .out_dir("/tmp") .header_file_name("my_generated_user_ta_header.rs") .link_type(LinkType::CC) .build() }
As you can see from the codes, there are some customizations of the builder:
user_ta_header.rs
CC
and LD
types, for example, --sort-section
in CC
types of linkers changes to -Wl,--sort-section
, we will try to detect current linker that cargo using, you can use this function to set it manually if you think our detection mismatch.For developers who prefer to use a hand-written user_ta_header.rs
and only want optee-utee-build
to handle the linking process, they can use the Linker
, otherwise, try Builder
instead.
Usage:
use optee_utee_build::{Linker, Error}; use std::env; fn main() -> Result<(), Error> { let out_dir = env::var("OUT_DIR")?; Linker::auto().link_all(out_dir)?; Ok(()) }
When linking manually, developers construct a Linker
and calling the link_all
method by providing the out_dir, and linker will generate some required files (link script, etc, used by linker) into out_dir and handle all the linking stuff.
In above codes, we use auto
to construct the linker, it will detect current linker that cargo using automatically, you can use new
function to construct the linker manually if you think our detection mismatch.
use optee_utee_build::{Linker, Error, LinkType}; use std::env; fn main() -> Result<(), Error> { let out_dir = env::var("OUT_DIR")?; Linker::new(LinkerType::CC).link_all(out_dir)?; Ok(()) }
For developers who prefer to do the linking themselves and only want optee-utee-build
to generate the header file, they can use the HeaderFileGenerator
, otherwise, try Builder
instead.
Usage:
use optee_utee_build::{HeaderFileGenerator, TaConfig, RustEdition, Error}; fn main() -> Result<(), Error> { const UUID: &str = "26509cec-4a2b-4935-87ab-762d89fbf0b0"; let ta_config = TaConfig::new_default(UUID, "0.1.0", "example")?; let codes = HeaderFileGenerator::new(RustEdition::Before2024).generate(&ta_config)?; Ok(std::io::Write("/tmp/user_ta_header.rs", codes.as_bytes())?) }
For developers still using const configuration values
in src/main.rs
and custom build scripts
in build.rs
(described in [migrating-to-new-building-env]), they can upgrade to optee-utee-build
by following step:
Firstly, add optee-utee-build
as build-dependencies
:
cargo add --build optee-utee-build
Secondly, in build.rs
, remove codes of custom build scripts
, and use optee_utee_build::build
instead:
// ... other imports use optee_utee_build::{TaConfig, Error} fn main() -> Result<(), Error> { // should customize the ta_config with the same as const configuration values // in your src/main.rs let ta_config = TaConfig::new_default_with_cargo_env(proto::UUID)? .ta_stack_size(10 * 1024); optee_utee_build::build(RustEdition::Before2024, ta_config)?; // ... other build scripts }
Thirdly, remove const configuration values
in src/main.rs
, keep the line of include user_ta_header.rs
.
/// ... other codes in src/main.rs /* remove const configuration values, move them to TaConfig in src/main.rs // TA configurations const TA_FLAGS: u32 = 0; const TA_DATA_SIZE: u32 = 32 * 1024; const TA_STACK_SIZE: u32 = 2 * 1024; const TA_VERSION: &[u8] = b"0.1\0"; const TA_DESCRIPTION: &[u8] = b"This is a hello world example.\0"; const EXT_PROP_VALUE_1: &[u8] = b"Hello World TA\0"; const EXT_PROP_VALUE_2: u32 = 0x0010; const TRACE_LEVEL: i32 = 4; const TRACE_EXT_PREFIX: &[u8] = b"TA\0"; const TA_FRAMEWORK_STACK_SIZE: u32 = 2048; */ include!(concat!(env!("OUT_DIR"), "/user_ta_header.rs")); // keep this line
Finally, delete the useless ta_static.rs
and start building now.