build(xbuild): explicit support for compile output type
What changed, and why it matters
This is a build-system cleanup, not a security fix. It changes how the Trezor firmware build tells the compiler whether to produce object files or preprocessed source files, so that it no longer accidentally passes conflicting flags that newer versions of clang reject. There is no change to runtime behavior, cryptography, or device security.
No security action required. Treat as a normal build-system improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors the internal xbuild helper used by the Trezor firmware build. Previously, callers passed an output extension string (e.g., ‘o’ or ‘upydef’) and sometimes manually added ‘-E’ or ‘-c’ to compiler flags. The helper also appended ‘-c’ automatically for object builds. This could lead to clang receiving both ‘-c’ and ‘-E’, which clang treats as an error under -Wall -Werror. The patch introduces an explicit OutputType enum (Object vs. Preprocessed) and lets xbuild add the correct compiler flag (-c or -E) itself. It is purely a build-tooling correctness change.
Changed components
core/embed/xbuild/src/clibrary/compile.rscore/embed/xbuild/src/lib.rscore/embed/upymod/build.rsInspect captured patch +34 / −9
diff --git a/core/embed/upymod/build.rs b/core/embed/upymod/build.rs
index 48071270..7a90747a 100644
--- a/core/embed/upymod/build.rs
+++ b/core/embed/upymod/build.rs
@@ -8,8 +8,8 @@ use std::{
};
use xbuild::{
- CLibrary, InputFiles, Result, WrapErr, bail, bail_unsupported, current_model_id, ensure,
- model_ids,
+ CLibrary, InputFiles, OutputType, Result, WrapErr, bail, bail_unsupported, current_model_id,
+ ensure, model_ids,
};
fn main() -> Result<()> {
@@ -453,8 +453,8 @@ impl<'a> MpyBuilder<'a> {
// the preprocessed output in corresponding .upydef files next to
// each object file.
let upydefs = self.lib.process_sources(
- "upydef",
- Some(&["-E", "-DNO_QSTR", "-DN_X64", "-DN_X86", "-DN_THUMB"]),
+ OutputType::Preprocessed("upydef"),
+ Some(&["-DNO_QSTR", "-DN_X64", "-DN_X86", "-DN_THUMB"]),
Some(&extra_sources),
)?;
diff --git a/core/embed/xbuild/src/clibrary/compile.rs b/core/embed/xbuild/src/clibrary/compile.rs
index b84c1fe3..6276942e 100644
--- a/core/embed/xbuild/src/clibrary/compile.rs
+++ b/core/embed/xbuild/src/clibrary/compile.rs
@@ -29,6 +29,21 @@ struct CompileUnit {
attrs: Option<CompileAttrs>,
}
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum OutputType {
+ Object,
+ Preprocessed(&'static str),
+}
+
+impl OutputType {
+ pub fn extension(&self) -> &'static str {
+ match self {
+ OutputType::Object => "o",
+ OutputType::Preprocessed(ext) => ext,
+ }
+ }
+}
+
// Represents the result of compiling a single source file
struct CompileArtifact {
// Index of the compile unit, used to maintain the original order of units
@@ -52,7 +67,7 @@ impl CompileUnit {
cmd.arg("-MMD").arg("-MF").arg(cc_dep);
}
- cmd.arg("-c").arg("-o").arg(&self.output).arg(&self.input);
+ cmd.arg("-o").arg(&self.output).arg(&self.input);
run_command_with_cc_dep(
&mut cmd,
@@ -83,7 +98,7 @@ impl CLibrary {
measure_time(format!("@@ {} compiled in", lib_name), || {
// Run parallel build on all sources
- let objects = self.process_sources("o", None, None)?;
+ let objects = self.process_sources(OutputType::Object, None, None)?;
// Append manually added objects (e.g., vendor header)
let objects = objects
.into_iter()
@@ -110,7 +125,7 @@ impl CLibrary {
/// A vector of paths to the generated output files.
pub fn process_sources(
&self,
- output_ext: &str,
+ output_type: OutputType,
extra_args: Option<&[&str]>,
extra_sources: Option<&[PathBuf]>,
) -> Result<Vec<PathBuf>> {
@@ -132,10 +147,10 @@ impl CLibrary {
for (index, (src, attrs)) in sources.into_iter().enumerate() {
// Derive absolute paths for input and output files
let input = join_paths_lexically(&base_dir, &src);
- let output = derive_output_path(&base_dir, &src, &out_dir, output_ext);
+ let output = derive_output_path(&base_dir, &src, &out_dir, output_type.extension());
// Only generate .d files for object files compiled from C/C++ sources
- let cc_dep = if output_ext == "o"
+ let cc_dep = if matches!(output_type, OutputType::Object)
&& src
.extension()
.is_some_and(|ext| ext == "c" || ext == "cpp" || ext == "cc")
@@ -166,6 +181,15 @@ impl CLibrary {
}
}
+ match output_type {
+ OutputType::Object => {
+ attrs.add_flag("-c");
+ }
+ OutputType::Preprocessed(..) => {
+ attrs.add_flag("-E");
+ }
+ }
+
// Compile all units in parallel
let artifacts = compile_parallel(units, &attrs)?;
let outputs = artifacts.into_iter().map(|a| a.output).collect();
diff --git a/core/embed/xbuild/src/lib.rs b/core/embed/xbuild/src/lib.rs
index 9e3f67bb..63acd64a 100644
--- a/core/embed/xbuild/src/lib.rs
+++ b/core/embed/xbuild/src/lib.rs
@@ -8,6 +8,7 @@ mod trezor;
pub use attrs::CompileAttrs;
pub use clibrary::CLibrary;
+pub use clibrary::compile::OutputType;
pub use input_files::InputFiles;
pub use dep_tracking::format_command_error;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.