-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathbuild.rs
More file actions
170 lines (154 loc) · 5.99 KB
/
build.rs
File metadata and controls
170 lines (154 loc) · 5.99 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Build script for exec-harness
//!
//! This script compiles the `libcodspeed_preload.so` shared library that is used
//! to inject instrumentation into child processes via LD_PRELOAD.
//!
//! The library is built using the `core.c` and headers from the `instrument-hooks-bindings`
//! crate's `instrument-hooks` directory.
use std::env;
use std::path::PathBuf;
/// Shared constants for the preload library.
/// These are passed as C defines during compilation and exported as environment
/// variables for the Rust code to use via `env!()`.
struct PreloadConstants {
/// Environment variable name for the benchmark URI.
uri_env: &'static str,
/// Integration name reported to CodSpeed.
integration_name: &'static str,
/// Integration version reported to CodSpeed.
integration_version: &'static str,
/// Filename for the preload shared library.
preload_lib_filename: &'static str,
}
fn main() {
println!("cargo:rerun-if-changed=preload/codspeed_preload.c");
println!("cargo:rerun-if-env-changed=CODSPEED_INSTRUMENT_HOOKS_DIR");
let preload_constants: PreloadConstants = PreloadConstants::default();
// Export constants as environment variables for the Rust code
println!(
"cargo:rustc-env=CODSPEED_URI_ENV={}",
preload_constants.uri_env
);
println!(
"cargo:rustc-env=CODSPEED_INTEGRATION_NAME={}",
preload_constants.integration_name
);
println!(
"cargo:rustc-env=CODSPEED_INTEGRATION_VERSION={}",
preload_constants.integration_version
);
println!(
"cargo:rustc-env=CODSPEED_PRELOAD_LIB_FILENAME={}",
preload_constants.preload_lib_filename
);
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
// Try to get the instrument-hooks directory from the environment variable first,
// otherwise use the one from the instrument-hooks-bindings crate
let instrument_hooks_dir = manifest_dir
.parent()
.unwrap()
.join("instrument-hooks-bindings/instrument-hooks");
// Build the preload shared library
let paths = PreloadBuildPaths {
preload_c: manifest_dir.join("preload/codspeed_preload.c"),
core_c: instrument_hooks_dir.join("dist/core.c"),
includes_dir: instrument_hooks_dir.join("includes"),
};
println!("cargo:rerun-if-changed={}", paths.core_c.display());
paths.check_sources_exist();
build_shared_library(&paths, &preload_constants);
}
/// Build the shared library using the cc crate
fn build_shared_library(paths: &PreloadBuildPaths, constants: &PreloadConstants) {
let uri_env_val = format!("\"{}\"", constants.uri_env);
let integration_name_val = format!("\"{}\"", constants.integration_name);
let integration_version_val = format!("\"{}\"", constants.integration_version);
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_file = out_dir.join(constants.preload_lib_filename);
let mut build = cc::Build::new();
build
.file(&paths.preload_c)
.file(&paths.core_c)
.include(&paths.includes_dir)
.pic(true)
.opt_level(3)
// There's no need to output cargo metadata as we are just building a shared library
// that will be copied to disk and loaded through LD_PRELOAD at runtime
.cargo_metadata(false)
// Pass constants as C defines
.define("CODSPEED_URI_ENV", uri_env_val.as_str())
.define("CODSPEED_INTEGRATION_NAME", integration_name_val.as_str())
.define(
"CODSPEED_INTEGRATION_VERSION",
integration_version_val.as_str(),
)
.std("gnu11") // need gnu11 instead of just c11 for setenv
// Suppress warnings from generated Zig code
.flag("-Wno-format")
.flag("-Wno-format-security")
.flag("-Wno-unused-but-set-variable")
.flag("-Wno-unused-const-variable")
.flag("-Wno-type-limits")
.flag("-Wno-uninitialized")
.flag("-Wno-overflow")
.flag("-Wno-unused-function")
.flag("-Wno-unterminated-string-initialization");
// Compile source files to object files
let objects = build.compile_intermediates();
// Link object files into shared library
let compiler = build.get_compiler();
let mut link_cmd = compiler.to_command();
link_cmd
.arg("-shared")
.arg("-o")
.arg(&out_file)
.args(&objects)
.arg("-lpthread");
let status = link_cmd.status().expect("Failed to run linker");
if !status.success() {
panic!("Failed to link libcodspeed_preload.so");
}
}
impl Default for PreloadConstants {
fn default() -> Self {
Self {
uri_env: "CODSPEED_BENCH_URI",
integration_name: "exec-harness",
integration_version: env!("CARGO_PKG_VERSION"),
preload_lib_filename: "libcodspeed_preload.so",
}
}
}
/// Paths required to build the preload shared library.
struct PreloadBuildPaths {
/// Path to the preload C source file (codspeed_preload.c).
preload_c: PathBuf,
/// Path to the core C source file from instrument-hooks.
core_c: PathBuf,
/// Path to the includes directory from instrument-hooks.
includes_dir: PathBuf,
}
impl PreloadBuildPaths {
/// Verify that all required source files and directories exist.
/// Panics with a descriptive message if any path is missing.
fn check_sources_exist(&self) {
if !self.core_c.exists() {
panic!(
"core.c not found at {}. Make sure the instrument hooks submodule is available.",
self.core_c.display()
);
}
if !self.includes_dir.exists() {
panic!(
"includes directory not found at {}. instrument hooks submodule is available.",
self.includes_dir.display()
);
}
if !self.preload_c.exists() {
panic!(
"codspeed_preload.c not found at {}",
self.preload_c.display()
);
}
}
}