1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
//! Build script for seq-compiler
//!
//! Locates the seq-runtime static library so it can be embedded into the compiler.
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
// Verify that seq-runtime version matches compiler version
verify_runtime_version();
// Rerun verification if Cargo.toml changes
println!("cargo:rerun-if-changed=Cargo.toml");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
// OUT_DIR is something like:
// target/release/build/seq-compiler-xxx/out
// We need to find libseq_runtime.a in:
// target/release/libseq_runtime.a or target/release/deps/libseq_runtime-xxx.a
// Navigate up from OUT_DIR to find target directory
// OUT_DIR = target/<profile>/build/<pkg>-<hash>/out
let target_dir = out_dir
.parent() // build/<pkg>-<hash>/out -> build/<pkg>-<hash>
.and_then(|p| p.parent()) // -> build
.and_then(|p| p.parent()) // -> <profile> (release/debug)
.expect("Could not find target directory");
// Try to find libseq_runtime.a
let direct_lib = target_dir.join("libseq_runtime.a");
let runtime_lib = if direct_lib.exists() {
direct_lib
} else {
// Search in deps directory for libseq_runtime-*.a
let deps_dir = target_dir.join("deps");
find_runtime_in_deps(&deps_dir).unwrap_or_else(|| {
panic!(
"Runtime library not found.\n\
Looked in: {}\n\
And deps: {}\n\
OUT_DIR was: {}",
direct_lib.display(),
deps_dir.display(),
out_dir.display()
)
})
};
// Set environment variable for include_bytes! in lib.rs
println!(
"cargo:rustc-env=SEQ_RUNTIME_LIB_PATH={}",
runtime_lib.display()
);
// Rerun if the runtime library changes
println!("cargo:rerun-if-changed={}", runtime_lib.display());
}
fn find_runtime_in_deps(deps_dir: &PathBuf) -> Option<PathBuf> {
if !deps_dir.exists() {
return None;
}
fs::read_dir(deps_dir).ok()?.find_map(|entry| {
let entry = entry.ok()?;
let name = entry.file_name();
let name_str = name.to_string_lossy();
if name_str.starts_with("libseq_runtime") && name_str.ends_with(".a") {
Some(entry.path())
} else {
None
}
})
}
/// Verify that the seq-runtime version matches the seq-compiler version
/// by parsing the Cargo.toml files using a proper TOML parser
fn verify_runtime_version() {
let compiler_version = env!("CARGO_PKG_VERSION");
// Read and parse the compiler's Cargo.toml
let cargo_toml_content =
fs::read_to_string("Cargo.toml").expect("Failed to read compiler/Cargo.toml");
let cargo_toml: toml::Value = cargo_toml_content
.parse()
.expect("Failed to parse Cargo.toml");
// Extract the seq-runtime version from build-dependencies
let runtime_version = cargo_toml
.get("build-dependencies")
.and_then(|deps| deps.get("seq-runtime"))
.and_then(|dep| {
// Handle both inline table and string formats
match dep {
toml::Value::Table(t) => t.get("version").and_then(|v| v.as_str()),
toml::Value::String(s) => Some(s.as_str()),
_ => None,
}
})
.expect("Could not find seq-runtime version in Cargo.toml");
// Remove the '=' prefix from exact version requirement
let runtime_version = runtime_version.trim_start_matches('=');
if compiler_version != runtime_version {
panic!(
"\n\n\
╔══════════════════════════════════════════════════════════════╗\n\
║ VERSION MISMATCH ERROR ║\n\
╠══════════════════════════════════════════════════════════════╣\n\
║ seq-compiler version: {:<39}║\n\
║ seq-runtime version: {:<39}║\n\
║ ║\n\
║ The embedded runtime MUST match the compiler version. ║\n\
║ This ensures published crates.io packages are trustworthy. ║\n\
║ ║\n\
║ Update compiler/Cargo.toml to pin seq-runtime to: ║\n\
║ version = \"={:<46}║\n\
╚══════════════════════════════════════════════════════════════╝\n",
compiler_version, runtime_version, compiler_version
);
}
}