Copilot commented on code in PR #263: URL: https://github.com/apache/teaclave-trustzone-sdk/pull/263#discussion_r2626866381
########## cargo-optee/src/ca_builder.rs: ########## @@ -0,0 +1,281 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use anyhow::{bail, Result}; +use std::path::PathBuf; +use std::process::Command; + +use crate::common::{ + find_target_directory, get_target_and_cross_compile, print_cargo_command, + print_output_and_bail, read_uuid_from_file, Arch, ChangeDirectoryGuard, +}; + +#[derive(Clone)] +pub struct CaBuildConfig { + pub arch: Arch, // Architecture + pub optee_client_export: PathBuf, // Path to OP-TEE client export + pub debug: bool, // Debug mode (default false = release) + pub path: PathBuf, // Path to CA directory + pub plugin: bool, // Build as plugin (shared library) + pub uuid_path: Option<PathBuf>, // Path to UUID file (for plugins) + // Customized variables + pub env: Vec<(String, String)>, // Custom environment variables for cargo build + pub no_default_features: bool, // Disable default features + pub features: Option<String>, // Additional features to enable +} + +// Main function to build the CA, optionally installing to a target directory +pub fn build_ca(config: CaBuildConfig, install_dir: Option<&std::path::Path>) -> Result<()> { + // Change to the CA directory + let _guard = ChangeDirectoryGuard::new(&config.path)?; + + let component_type = if config.plugin { "Plugin" } else { "CA" }; + // Get the absolute path for better clarity + let absolute_path = std::fs::canonicalize(&config.path).unwrap_or_else(|_| config.path.clone()); + println!( + "Building {} in directory: {}", + component_type, + absolute_path.display() + ); + + // Step 1: Run clippy for code quality checks + run_clippy(&config)?; + + // Step 2: Build the CA + build_binary(&config)?; + + // Step 3: Post-build processing (strip for binaries, copy for plugins) + let final_binary = post_build(&config)?; + + // Print the final binary path with descriptive prompt + let absolute_final_binary = final_binary + .canonicalize() + .unwrap_or_else(|_| final_binary.clone()); + if config.plugin { + println!("Plugin copied to: {}", absolute_final_binary.display()); + } else { + println!( + "CA binary stripped and saved to: {}", + absolute_final_binary.display() + ); + } + + // Step 4: Install if requested + if let Some(install_dir) = install_dir { + use std::fs; + + // Check if install directory exists + if !install_dir.exists() { + bail!("Install directory does not exist: {:?}", install_dir); + } + + // Get package name from the final binary path + let package_name = final_binary + .file_name() + .and_then(|name| name.to_str()) + .ok_or_else(|| anyhow::anyhow!("Could not get binary name"))?; + + // Copy binary to install directory + let dest_path = install_dir.join(package_name); + fs::copy(&final_binary, &dest_path)?; + + println!( + "{} installed to: {:?}", + component_type, + dest_path.canonicalize().unwrap_or(dest_path) + ); + } + + println!("{} build successfully!", component_type); + + Ok(()) +} + +fn run_clippy(config: &CaBuildConfig) -> Result<()> { + println!("Running cargo fmt and clippy..."); + + // Run cargo fmt + let fmt_output = Command::new("cargo").arg("fmt").output()?; + + if !fmt_output.status.success() { + print_output_and_bail("cargo fmt", &fmt_output)?; + } + + // Determine target based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch); + + let mut clippy_cmd = Command::new("cargo"); + clippy_cmd.arg("clippy"); + clippy_cmd.arg("--target").arg(&target); + + // Set OPTEE_CLIENT_EXPORT environment variable for build scripts + clippy_cmd.env("OPTEE_CLIENT_EXPORT", &config.optee_client_export); + + clippy_cmd.arg("--"); + clippy_cmd.arg("-D").arg("warnings"); + clippy_cmd.arg("-D").arg("clippy::unwrap_used"); + clippy_cmd.arg("-D").arg("clippy::expect_used"); + clippy_cmd.arg("-D").arg("clippy::panic"); + + let clippy_output = clippy_cmd.output()?; + + if !clippy_output.status.success() { + print_output_and_bail("clippy", &clippy_output)?; + } + + Ok(()) +} + +fn build_binary(config: &CaBuildConfig) -> Result<()> { + let component_type = if config.plugin { "Plugin" } else { "CA" }; + println!("Building {} binary...", component_type); + + // Determine target and cross-compile based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch); + + let mut build_cmd = Command::new("cargo"); + build_cmd.arg("build"); + build_cmd.arg("--target").arg(&target); + + // Add --no-default-features if specified + if config.no_default_features { + build_cmd.arg("--no-default-features"); + } + + // Add additional features if specified + if let Some(ref features) = config.features { + build_cmd.arg("--features").arg(features); + } + + if !config.debug { + build_cmd.arg("--release"); + } + + // Configure linker + let linker = format!("{}gcc", cross_compile); + let linker_cfg = format!("target.{}.linker=\"{}\"", target, linker); + build_cmd.arg("--config").arg(&linker_cfg); + + // Set OPTEE_CLIENT_EXPORT environment variable + build_cmd.env("OPTEE_CLIENT_EXPORT", &config.optee_client_export); + + // Apply custom environment variables + for (key, value) in &config.env { + build_cmd.env(key, value); + } + + // Print the full cargo build command for debugging + print_cargo_command(&build_cmd, "Building CA binary"); + + let build_output = build_cmd.output()?; + + if !build_output.status.success() { + print_output_and_bail("build", &build_output)?; + } + + Ok(()) +} + +fn post_build(config: &CaBuildConfig) -> Result<PathBuf> { + if config.plugin { + copy_plugin(config) + } else { + strip_binary(config) + } +} + +fn copy_plugin(config: &CaBuildConfig) -> Result<PathBuf> { + println!("Processing plugin..."); + + // Determine target based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch); + + let profile = if config.debug { "debug" } else { "release" }; + + // Use Cargo's workspace discovery strategy to find target directory + let workspace_target_dir = find_target_directory()?; + let target_dir = workspace_target_dir.join(target).join(profile); + + // Get the library name from Cargo.toml + let cargo_toml = std::fs::read_to_string("Cargo.toml")?; + let lib_name = cargo_toml + .lines() + .find(|line| line.trim().starts_with("name")) + .and_then(|line| line.split('=').nth(1)) + .map(|s| s.trim().trim_matches('"')) + .ok_or_else(|| anyhow::anyhow!("Could not find package name in Cargo.toml"))?; Review Comment: The cargo_toml parsing is fragile and may fail if the Cargo.toml has comments, whitespace variations, or if the name field appears in other sections. Consider using the toml crate to properly parse the Cargo.toml file, or use cargo metadata command which provides this information reliably. ########## cargo-optee/src/ca_builder.rs: ########## @@ -0,0 +1,281 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use anyhow::{bail, Result}; +use std::path::PathBuf; +use std::process::Command; + +use crate::common::{ + find_target_directory, get_target_and_cross_compile, print_cargo_command, + print_output_and_bail, read_uuid_from_file, Arch, ChangeDirectoryGuard, +}; + +#[derive(Clone)] +pub struct CaBuildConfig { + pub arch: Arch, // Architecture + pub optee_client_export: PathBuf, // Path to OP-TEE client export + pub debug: bool, // Debug mode (default false = release) + pub path: PathBuf, // Path to CA directory + pub plugin: bool, // Build as plugin (shared library) + pub uuid_path: Option<PathBuf>, // Path to UUID file (for plugins) + // Customized variables + pub env: Vec<(String, String)>, // Custom environment variables for cargo build + pub no_default_features: bool, // Disable default features + pub features: Option<String>, // Additional features to enable +} + +// Main function to build the CA, optionally installing to a target directory +pub fn build_ca(config: CaBuildConfig, install_dir: Option<&std::path::Path>) -> Result<()> { + // Change to the CA directory + let _guard = ChangeDirectoryGuard::new(&config.path)?; + + let component_type = if config.plugin { "Plugin" } else { "CA" }; + // Get the absolute path for better clarity + let absolute_path = std::fs::canonicalize(&config.path).unwrap_or_else(|_| config.path.clone()); + println!( + "Building {} in directory: {}", + component_type, + absolute_path.display() + ); + + // Step 1: Run clippy for code quality checks + run_clippy(&config)?; + + // Step 2: Build the CA + build_binary(&config)?; + + // Step 3: Post-build processing (strip for binaries, copy for plugins) + let final_binary = post_build(&config)?; + + // Print the final binary path with descriptive prompt + let absolute_final_binary = final_binary + .canonicalize() + .unwrap_or_else(|_| final_binary.clone()); + if config.plugin { + println!("Plugin copied to: {}", absolute_final_binary.display()); + } else { + println!( + "CA binary stripped and saved to: {}", + absolute_final_binary.display() + ); + } + + // Step 4: Install if requested + if let Some(install_dir) = install_dir { + use std::fs; + + // Check if install directory exists + if !install_dir.exists() { + bail!("Install directory does not exist: {:?}", install_dir); + } + + // Get package name from the final binary path + let package_name = final_binary + .file_name() + .and_then(|name| name.to_str()) + .ok_or_else(|| anyhow::anyhow!("Could not get binary name"))?; + + // Copy binary to install directory + let dest_path = install_dir.join(package_name); + fs::copy(&final_binary, &dest_path)?; + + println!( + "{} installed to: {:?}", + component_type, + dest_path.canonicalize().unwrap_or(dest_path) + ); + } + + println!("{} build successfully!", component_type); + + Ok(()) +} + +fn run_clippy(config: &CaBuildConfig) -> Result<()> { + println!("Running cargo fmt and clippy..."); + + // Run cargo fmt + let fmt_output = Command::new("cargo").arg("fmt").output()?; + + if !fmt_output.status.success() { + print_output_and_bail("cargo fmt", &fmt_output)?; + } + + // Determine target based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch); + + let mut clippy_cmd = Command::new("cargo"); + clippy_cmd.arg("clippy"); + clippy_cmd.arg("--target").arg(&target); + + // Set OPTEE_CLIENT_EXPORT environment variable for build scripts + clippy_cmd.env("OPTEE_CLIENT_EXPORT", &config.optee_client_export); + + clippy_cmd.arg("--"); + clippy_cmd.arg("-D").arg("warnings"); + clippy_cmd.arg("-D").arg("clippy::unwrap_used"); + clippy_cmd.arg("-D").arg("clippy::expect_used"); + clippy_cmd.arg("-D").arg("clippy::panic"); + + let clippy_output = clippy_cmd.output()?; + + if !clippy_output.status.success() { + print_output_and_bail("clippy", &clippy_output)?; + } + + Ok(()) +} + +fn build_binary(config: &CaBuildConfig) -> Result<()> { + let component_type = if config.plugin { "Plugin" } else { "CA" }; + println!("Building {} binary...", component_type); + + // Determine target and cross-compile based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch); + + let mut build_cmd = Command::new("cargo"); + build_cmd.arg("build"); + build_cmd.arg("--target").arg(&target); + + // Add --no-default-features if specified + if config.no_default_features { + build_cmd.arg("--no-default-features"); + } + + // Add additional features if specified + if let Some(ref features) = config.features { + build_cmd.arg("--features").arg(features); + } + + if !config.debug { + build_cmd.arg("--release"); + } + + // Configure linker + let linker = format!("{}gcc", cross_compile); + let linker_cfg = format!("target.{}.linker=\"{}\"", target, linker); + build_cmd.arg("--config").arg(&linker_cfg); + + // Set OPTEE_CLIENT_EXPORT environment variable + build_cmd.env("OPTEE_CLIENT_EXPORT", &config.optee_client_export); + + // Apply custom environment variables + for (key, value) in &config.env { + build_cmd.env(key, value); + } + + // Print the full cargo build command for debugging + print_cargo_command(&build_cmd, "Building CA binary"); + + let build_output = build_cmd.output()?; + + if !build_output.status.success() { + print_output_and_bail("build", &build_output)?; + } + + Ok(()) +} + +fn post_build(config: &CaBuildConfig) -> Result<PathBuf> { + if config.plugin { + copy_plugin(config) + } else { + strip_binary(config) + } +} + +fn copy_plugin(config: &CaBuildConfig) -> Result<PathBuf> { + println!("Processing plugin..."); + + // Determine target based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch); + + let profile = if config.debug { "debug" } else { "release" }; + + // Use Cargo's workspace discovery strategy to find target directory + let workspace_target_dir = find_target_directory()?; + let target_dir = workspace_target_dir.join(target).join(profile); + + // Get the library name from Cargo.toml + let cargo_toml = std::fs::read_to_string("Cargo.toml")?; + let lib_name = cargo_toml + .lines() + .find(|line| line.trim().starts_with("name")) + .and_then(|line| line.split('=').nth(1)) + .map(|s| s.trim().trim_matches('"')) + .ok_or_else(|| anyhow::anyhow!("Could not find package name in Cargo.toml"))?; + + // Plugin is built as a shared library (lib<name>.so) + let plugin_src = target_dir.join(format!("lib{}.so", lib_name)); + + if !plugin_src.exists() { + bail!("Plugin library not found at {:?}", plugin_src); + } + + // Read UUID from specified file + let uuid = read_uuid_from_file( + config + .uuid_path + .as_ref() + .ok_or_else(|| anyhow::anyhow!("UUID path is required for plugin builds"))?, + )?; + + // Copy to <uuid>.plugin.so + let plugin_dest = target_dir.join(format!("{}.plugin.so", uuid)); + std::fs::copy(&plugin_src, &plugin_dest)?; + + Ok(plugin_dest) +} + +fn strip_binary(config: &CaBuildConfig) -> Result<PathBuf> { + println!("Stripping binary..."); + + // Determine target based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch); + + let profile = if config.debug { "debug" } else { "release" }; + let target_dir = PathBuf::from("target").join(target).join(profile); + + // Get the binary name from Cargo.toml + let cargo_toml = std::fs::read_to_string("Cargo.toml")?; + let binary_name = cargo_toml + .lines() + .find(|line| line.trim().starts_with("name")) + .and_then(|line| line.split('=').nth(1)) + .map(|s| s.trim().trim_matches('"')) + .ok_or_else(|| anyhow::anyhow!("Could not find package name in Cargo.toml"))?; Review Comment: The same fragile Cargo.toml parsing pattern is used here. Consider using the toml crate to properly parse the Cargo.toml file, or use cargo metadata command which provides this information reliably. ########## cargo-optee/src/ta_builder.rs: ########## @@ -0,0 +1,505 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use anyhow::{bail, Result}; +use std::env; +use std::fs; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; +use tempfile::TempDir; +use toml::Value; + +use crate::common::{print_cargo_command, print_output_and_bail, read_uuid_from_file, Arch}; + +// Embed the target JSON files at compile time +const AARCH64_TARGET_JSON: &str = include_str!("../aarch64-unknown-optee.json"); +const ARM_TARGET_JSON: &str = include_str!("../arm-unknown-optee.json"); + +// Target configurations for different architectures and std modes +const TARGET_CONFIGS: [(Arch, bool, &str, &str); 4] = [ + // (Architecture, has_std, target, cross_compile_prefix) + ( + Arch::Arm, + false, + "arm-unknown-linux-gnueabihf", + "arm-linux-gnueabihf-", + ), + (Arch::Arm, true, "arm-unknown-optee", "arm-linux-gnueabihf-"), + ( + Arch::Aarch64, + false, + "aarch64-unknown-linux-gnu", + "aarch64-linux-gnu-", + ), + ( + Arch::Aarch64, + true, + "aarch64-unknown-optee", + "aarch64-linux-gnu-", + ), +]; + +/// Check if the required cross-compile toolchain is available +fn check_toolchain_exists(cross_compile_prefix: &str) -> Result<()> { + let gcc_command = format!("{}gcc", cross_compile_prefix); + let objcopy_command = format!("{}objcopy", cross_compile_prefix); + + // Check if gcc exists + let gcc_check = Command::new("which").arg(&gcc_command).output(); + + // Check if objcopy exists + let objcopy_check = Command::new("which").arg(&objcopy_command).output(); + + let gcc_exists = gcc_check.map_or(false, |output| output.status.success()); + let objcopy_exists = objcopy_check.map_or(false, |output| output.status.success()); + + if !gcc_exists || !objcopy_exists { + let missing_tools: Vec<&str> = [ + if !gcc_exists { + Some(gcc_command.as_str()) + } else { + None + }, + if !objcopy_exists { + Some(objcopy_command.as_str()) + } else { + None + }, + ] + .iter() + .filter_map(|&x| x) + .collect(); + + eprintln!("Error: Required cross-compile toolchain not found!"); + eprintln!("Missing tools: {}", missing_tools.join(", ")); + eprintln!(); + eprintln!("Please install the required toolchain:"); + eprintln!(); + eprintln!("# For aarch64 host (ARM64 machine):"); + eprintln!("apt update && apt -y install gcc gcc-arm-linux-gnueabihf"); + eprintln!(); + eprintln!("# For x86_64 host (Intel/AMD machine):"); + eprintln!("apt update && apt -y install gcc-aarch64-linux-gnu gcc-arm-linux-gnueabihf"); + eprintln!(); + eprintln!("Or manually install the cross-compilation tools for your target architecture."); + + bail!("Cross-compile toolchain not available"); + } + + Ok(()) +} + +#[derive(Clone)] +pub struct TaBuildConfig { + pub arch: Arch, // Architecture + pub std: bool, // Enable std feature + pub ta_dev_kit_dir: PathBuf, // Path to TA dev kit + pub signing_key: PathBuf, // Path to signing key + pub debug: bool, // Debug mode (default false = release) + pub path: PathBuf, // Path to TA directory + pub uuid_path: PathBuf, // Path to UUID file + // Customized variables + pub env: Vec<(String, String)>, // Custom environment variables for cargo build + pub no_default_features: bool, // Disable default features + pub features: Option<String>, // Additional features to enable +} + +// Helper function to derive target and cross-compile from arch and std +fn get_target_and_cross_compile(arch: Arch, std: bool) -> Result<(String, String)> { + for &(config_arch, config_std, target, cross_compile_prefix) in &TARGET_CONFIGS { + if config_arch == arch && config_std == std { + return Ok((target.to_string(), cross_compile_prefix.to_string())); + } + } + + bail!( + "No target configuration found for arch: {:?}, std: {}", + arch, + std + ); +} + +// Helper function to setup custom target JSONs for std builds +// Returns TempDir to keep it alive during the build +fn setup_custom_targets() -> Result<TempDir> { + let temp_dir = TempDir::new()?; + + // Write the embedded target JSON files + let aarch64_path = temp_dir.path().join("aarch64-unknown-optee.json"); + let arm_path = temp_dir.path().join("arm-unknown-optee.json"); + + fs::write(aarch64_path, AARCH64_TARGET_JSON)?; + fs::write(arm_path, ARM_TARGET_JSON)?; + + Ok(temp_dir) +} + +// Helper function to setup base command with common environment variables +fn setup_build_command( + config: &TaBuildConfig, + command: &str, +) -> Result<(Command, Option<TempDir>)> { + // Determine target and cross-compile based on arch + let (target, _cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + // Determine builder (cargo or xargo) + let builder = if config.std { "xargo" } else { "cargo" }; + + // Setup custom targets if using std - keep TempDir alive + let temp_dir = if config.std { + Some(setup_custom_targets()?) + } else { + None + }; + + let mut cmd = Command::new(builder); + cmd.arg(command); + cmd.arg("--target").arg(&target); + + // Add --no-default-features if specified + if config.no_default_features { + cmd.arg("--no-default-features"); + } + + // Build features list + let mut features = Vec::new(); + if config.std { + features.push("std".to_string()); + } + if let Some(ref custom_features) = config.features { + // Split custom features by comma and add them + for feature in custom_features.split(',') { + let feature = feature.trim(); + if !feature.is_empty() { + features.push(feature.to_string()); + } + } + } + + // Add features if any are specified + if !features.is_empty() { + cmd.arg("--features").arg(features.join(",")); + } + + // Add no-std specific flags to avoid the linking error of _Unwind_Resume + if !config.std { + cmd.arg("-Z").arg("build-std=core,alloc"); + cmd.arg("-Z") + .arg("build-std-features=panic_immediate_abort"); + } + + // Set RUSTFLAGS - preserve existing ones and add panic=abort + let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + if !rustflags.is_empty() { + rustflags.push(' '); + } + rustflags.push_str("-C panic=abort"); + cmd.env("RUSTFLAGS", &rustflags); + + // Apply custom environment variables + for (key, value) in &config.env { + cmd.env(key, value); + } + + // Set TA_DEV_KIT_DIR environment variable (use absolute path) + let absolute_ta_dev_kit_dir = config + .ta_dev_kit_dir + .canonicalize() + .unwrap_or_else(|_| config.ta_dev_kit_dir.clone()); + cmd.env("TA_DEV_KIT_DIR", &absolute_ta_dev_kit_dir); + + // Set RUST_TARGET_PATH for custom targets when using std + if let Some(ref temp_dir_ref) = temp_dir { + cmd.env("RUST_TARGET_PATH", temp_dir_ref.path()); + } + + Ok((cmd, temp_dir)) +} + +// Main function to build the TA, optionally installing to a target directory +pub fn build_ta(config: TaBuildConfig, install_dir: Option<&Path>) -> Result<()> { + // Check if required cross-compile toolchain is available + let (_, cross_compile_prefix) = get_target_and_cross_compile(config.arch, config.std)?; + check_toolchain_exists(&cross_compile_prefix)?; + + // Verify we're in a valid Rust project directory + let manifest_path = config.path.join("Cargo.toml"); + if !manifest_path.exists() { + bail!( + "No Cargo.toml found in TA project directory: {:?}\n\ + Please run cargo-optee from a TA project directory or specify --manifest-path", + config.path + ); + } + // Get the absolute path for better clarity + let absolute_path = std::fs::canonicalize(&config.path).unwrap_or_else(|_| config.path.clone()); + println!("Building TA in directory: {}", absolute_path.display()); + + // Step 1: Run clippy for code quality checks + run_clippy(&config, &manifest_path)?; + + // Step 2: Build the TA + build_binary(&config, &manifest_path)?; + + // Step 3: Strip the binary + let (stripped_path, target_dir) = strip_binary(&config, &manifest_path)?; + + // Step 4: Sign the TA + sign_ta(&config, &stripped_path, &target_dir)?; + + // Step 5: Install if requested + if let Some(install_dir) = install_dir { + // Check if install directory exists + if !install_dir.exists() { + bail!("Install directory does not exist: {:?}", install_dir); + } + + let uuid = read_uuid_from_file(&config.uuid_path)?; + let ta_file = target_dir.join(format!("{}.ta", uuid)); + + if !ta_file.exists() { + bail!("Signed TA file not found at {:?}", ta_file); + } + + let dest_path = install_dir.join(format!("{}.ta", uuid)); + fs::copy(&ta_file, &dest_path)?; + + println!( + "TA installed to: {:?}", + dest_path.canonicalize().unwrap_or(dest_path) + ); + } + + println!("TA build successfully!"); + + Ok(()) +} + +fn run_clippy(config: &TaBuildConfig, manifest_path: &Path) -> Result<()> { + println!("Running cargo fmt and clippy..."); + + // Get the project directory from manifest path + let project_dir = manifest_path + .parent() + .ok_or_else(|| anyhow::anyhow!("Invalid manifest path: {:?}", manifest_path))?; + + // Change to project directory to respect rust-toolchain.toml + let original_dir = std::env::current_dir()?; + std::env::set_current_dir(project_dir)?; + + // Run cargo fmt (without --manifest-path since we're in the project dir) + let mut fmt_cmd = Command::new("cargo"); + fmt_cmd.arg("fmt"); + let fmt_output = fmt_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(&original_dir)?; + + let fmt_output = fmt_output?; + if !fmt_output.status.success() { + print_output_and_bail("cargo fmt", &fmt_output)?; + } + + // Change back to project directory for clippy + std::env::set_current_dir(project_dir)?; + + // Setup clippy command with common environment (without --manifest-path) + let (mut clippy_cmd, _temp_dir) = setup_build_command(config, "clippy")?; + + clippy_cmd.arg("--"); + clippy_cmd.arg("-D").arg("warnings"); + clippy_cmd.arg("-D").arg("clippy::unwrap_used"); + clippy_cmd.arg("-D").arg("clippy::expect_used"); + clippy_cmd.arg("-D").arg("clippy::panic"); + + let clippy_output = clippy_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(&original_dir)?; + + let clippy_output = clippy_output?; + if !clippy_output.status.success() { + print_output_and_bail("clippy", &clippy_output)?; + } + + Ok(()) +} + +fn build_binary(config: &TaBuildConfig, manifest_path: &Path) -> Result<()> { + // Get the project directory from manifest path + let project_dir = manifest_path + .parent() + .ok_or_else(|| anyhow::anyhow!("Invalid manifest path: {:?}", manifest_path))?; + + // Change to project directory to respect rust-toolchain.toml + let original_dir = std::env::current_dir()?; + std::env::set_current_dir(project_dir)?; + + // Determine target and cross-compile based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + // Setup build command with common environment (without --manifest-path) + let (mut build_cmd, _temp_dir) = setup_build_command(config, "build")?; + + if !config.debug { + build_cmd.arg("--release"); + } + + // Configure linker + let linker = format!("{}gcc", cross_compile); + let linker_cfg = format!("target.{}.linker=\"{}\"", target, linker); + build_cmd.arg("--config").arg(&linker_cfg); + + // Print the full cargo build command for debugging + print_cargo_command(&build_cmd, "Building TA binary"); + + let build_output = build_cmd.output(); + + // Restore original directory before checking results + std::env::set_current_dir(original_dir)?; + + let build_output = build_output?; + if !build_output.status.success() { + print_output_and_bail("build", &build_output)?; + } + + Ok(()) +} + +fn get_package_name(manifest_path: &Path) -> Result<String> { + if !manifest_path.exists() { + bail!("Cargo.toml not found at: {:?}", manifest_path); + } + + let cargo_toml_content = fs::read_to_string(manifest_path)?; + let cargo_toml: Value = toml::from_str(&cargo_toml_content)?; + + let package_name = cargo_toml + .get("package") + .and_then(|p| p.get("name")) + .and_then(|n| n.as_str()) + .ok_or_else(|| anyhow::anyhow!("Could not find package name in Cargo.toml"))?; + + Ok(package_name.to_string()) +} + +fn strip_binary(config: &TaBuildConfig, manifest_path: &Path) -> Result<(PathBuf, PathBuf)> { + println!("Stripping binary..."); + + // Determine target based on arch + let (target, cross_compile) = get_target_and_cross_compile(config.arch, config.std)?; + + let profile = if config.debug { "debug" } else { "release" }; + + // Get the actual package name from Cargo.toml + let package_name = get_package_name(manifest_path)?; + + // Use cargo metadata to get the target directory that cargo is actually using + let output = Command::new("cargo") + .arg("metadata") + .arg("--manifest-path") + .arg(manifest_path) + .arg("--format-version") + .arg("1") + .arg("--no-deps") + .output()?; + + if !output.status.success() { + bail!("Failed to get cargo metadata"); + } + + let metadata: serde_json::Value = serde_json::from_slice(&output.stdout)?; + let target_directory = metadata + .get("target_directory") + .and_then(|v| v.as_str()) + .ok_or_else(|| anyhow::anyhow!("Could not get target directory from cargo metadata"))?; + + let target_dir = PathBuf::from(target_directory); + let profile_dir = target_dir.join(target).join(profile); + let binary_path = profile_dir.join(&package_name); + + if !binary_path.exists() { + bail!("Binary not found at {:?}", binary_path); + } + + let stripped_path = profile_dir.join(format!("stripped_{}", package_name)); + + if !stripped_path.exists() { + bail!("Stripped binary path does not exist: {:?}", stripped_path); + } Review Comment: The code checks if the stripped binary path exists before creating it, which will always fail. The stripped binary should be created by the objcopy command on line 448-452. This check should be removed, or it should verify that objcopy succeeded by checking if the file exists after the command runs. ########## docs/emulate-and-dev-in-docker-std.md: ########## @@ -34,19 +54,62 @@ $ docker run -it --rm \ teaclave/teaclave-trustzone-emulator-std-expand-memory:latest ``` -### One-Time Setup Inside Container +#### One-Time Setup Inside Container ```bash -# Create symbolic link to make it compatiable with existing SDK examples +# Create symbolic link to make it compatible with existing SDK examples $ ln -s $RUST_STD_DIR rust ``` > 📝 **Note**: This symlink is required for current SDK examples due to > hardcoded std dependency paths in Cargo.toml. Your own projects may organize > std files differently. -## 2. Configuration Management System +### 2. Configuring and Building TA and CA + +#### Configuration Model + +cargo-optee uses its own configuration system instead of relying on the +global `switch_config` mechanism. This design avoids implicit global state +and makes the build configuration more explicit and easier to maintain. +For more details, see the +[cargo-optee configuration system](../cargo-optee/README.md#configuration-system). + + +#### Build Target Differences + +Depending on the selected configuration, cargo-optee produces different build +targets as summarized below: + +| Configuration | TA Target | Build Tool | Host Target | +|---------------|-----------|------------|-------------| +| `std/*` | `*-unknown-optee` | `xargo` | `*-unknown-linux-gnu` | +| `no-std/*` | `*-unknown-linux-gnu` | `cargo` | `*-unknown-linux-gnu` | Review Comment: The formatting issue with the table requires fixing. The table header row should have pipes properly aligned. The current format will not render correctly as a markdown table. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
