This repository was archived by the owner on Apr 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathbuild.rs
More file actions
314 lines (269 loc) · 8.95 KB
/
Copy pathbuild.rs
File metadata and controls
314 lines (269 loc) · 8.95 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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
extern crate gcc;
use std::collections::{HashMap, HashSet};
use gcc::Build;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::fs::File;
use std::io::Write;
fn main() {
let outdir = PathBuf::from(env::var("OUT_DIR").unwrap());
// We're going to generate app_config.h from their feature
// selection, so let's extract that from the env.
let features: HashSet<_> = env::vars()
.filter_map(|(k, _)| {
if k.starts_with("CARGO_FEATURE_") && k != "CARGO_FEATURE_DEFAULT" {
Some(k[14..].to_owned())
} else {
None
}
})
.collect();
write_app_config(&outdir, &features);
// If any of these files/folders change, we should regenerate
// the whole C + bindings component
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=bindings.h");
let mut info = SdkInfo::default();
info.add_from_path(&PathBuf::from("nRF5-sdk"));
info.add_from_path(&PathBuf::from("shims"));
for src in info.srcs.iter() {
println!("cargo:rerun-if-changed={}", src.display());
}
for hdr in info.hdrs.iter() {
println!("cargo:rerun-if-changed={}", hdr.display());
}
process_linker_file(&outdir);
generate_ble(&outdir, &info);
make_c_deps(&outdir, &info, &features);
}
/// Emit app_config.h based on the enabled features. This is used
/// to override things in sdk_config.h
fn write_app_config(outdir: &PathBuf, features: &HashSet<String>) {
let mut app_config = File::create(outdir.join("app_config.h")).unwrap();
for feature in features.iter() {
writeln!(app_config, "#define {}_ENABLED 1", feature).ok();
}
}
#[derive(Default)]
struct SdkInfo {
/// Things to compile
srcs: Vec<PathBuf>,
/// Headers to depend upon
hdrs: Vec<PathBuf>,
/// All visited dirs (we'll add includes for them).
dirs: Vec<PathBuf>,
}
impl SdkInfo {
fn add_from_path(&mut self, path: &PathBuf) {
self.dirs.push(path.clone());
for entry in path.read_dir().expect("read_dir failed") {
if let Ok(entry) = entry {
let base_name = entry.file_name().into_string().unwrap();
if base_name.starts_with(".") {
continue;
}
let file_type = entry.metadata().unwrap().file_type();
if file_type.is_dir() {
self.add_from_path(&entry.path());
continue;
}
if file_type.is_file() {
if base_name.ends_with(".h") {
self.hdrs.push(entry.path());
continue;
}
if base_name.ends_with(".c") || base_name.ends_with(".S") {
self.srcs.push(entry.path());
continue;
}
}
}
}
}
}
fn process_linker_file(out: &PathBuf) {
// Copy over the target specific linker script
File::create(out.join("nrf52dk-sys.ld"))
.unwrap()
.write_all(include_bytes!("nrf52dk-sys.ld"))
.unwrap();
// Also copy the nrf general linker script
File::create(out.join("nrf5x_common.ld"))
.unwrap()
.write_all(include_bytes!("nrf5x_common.ld"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
}
fn make_c_deps(out_path: &PathBuf, info: &SdkInfo, features: &HashSet<String>) {
let mut config = Build::new();
config.out_dir(out_path);
for f in FLAGS {
config.flag(f);
}
for &(var, val) in DEFINES {
config.define(var, val);
}
let feat_map = compile_src_to_feat();
for f in info.srcs.iter() {
if is_src_enabled(f, &feat_map, features) {
config.file(f);
}
}
// out_path is where we find the app_config.h that we generate
// from the enabled features
config.include(out_path);
for i in info.dirs.iter() {
config.include(i);
}
config.compile("libnrf.a");
println!("cargo:rustc-link-search={}", out_path.display());
println!("cargo:rustc-link-lib=static=nrf");
}
/// Extract the default include path from the target compiler
fn find_system_includes() -> Vec<PathBuf> {
let output = Command::new("arm-none-eabi-gcc")
.arg("-E")
.arg("-Wp,-v")
.arg("-xc")
.arg("/dev/null")
.arg("-o/dev/null")
.output()
.expect("failed to invoke arg-none-eabi-gcc; it needs to be in your PATH");
let mut res = Vec::new();
for line in String::from_utf8_lossy(&output.stderr).split("\n") {
if line.starts_with(" ") {
res.push(PathBuf::from(line.trim()));
}
}
res
}
fn generate_ble(out: &PathBuf, info: &SdkInfo) {
// TODO version assert
let mut cmd = Command::new("bindgen");
// Bindgen Opts
cmd.arg("bindings.h");
cmd.arg("--no-doc-comments");
cmd.arg("--use-core");
cmd.arg("--ctypes-prefix=ctypes");
cmd.arg("--with-derive-default");
cmd.arg("--verbose");
cmd.arg("--blacklist-type");
cmd.arg("IRQn_Type");
cmd.arg("--blacklist-type");
cmd.arg("__va_list");
// This type wraps a mutable void pointer, and we cannot safely impl Copy.
cmd.arg("--output");
cmd.arg(out.join("bindings.rs"));
// Clang Opts begin here
cmd.arg("--");
// Don't pollute the headers with the host header files. This matters
// most on macOS where the headers have a lot of darwin specific things
cmd.arg("-nostdlib");
cmd.arg("-nostdinc");
cmd.arg("-ffreestanding");
// Probe the target compiler for its default includes
cmd.arg(format!("-I{}", out.display()));
for inc in find_system_includes() {
cmd.arg(format!("-I{}", inc.display()));
}
// Standard defines (common with GCC build)
for &(var, oval) in DEFINES {
match oval {
None => cmd.arg(format!("-D{}", var)),
Some(val) => cmd.arg(format!("-D{}={}", var, val)),
};
}
// Hack defines to make bindgen work
cmd.arg("-D__CMSIS_GCC_H");
cmd.arg("-DSVCALL_AS_NORMAL_FUNCTION"); // this is questionable
// Standard include paths (common with GCC build)
for inc in info.dirs.iter() {
cmd.arg(format!("-I{}", inc.display()));
}
// Final Clang args
cmd.arg("-fshort-enums");
cmd.arg("-target");
cmd.arg(env::var("TARGET").unwrap());
assert!(cmd.status()
.expect("failed to build BLE libs")
.success());
}
/// Build SRC_TO_FEAT into something using PathBufs
fn compile_src_to_feat() -> HashMap<PathBuf, String> {
let mut map = HashMap::new();
for &(file, feat) in SRC_TO_FEAT.iter() {
map.insert(PathBuf::from(file), feat.to_owned());
}
map
}
/// Test whether `src` has any prefixes in the SRC_TO_FEAT map,
/// and if it does whether the RHS is a disabled feature.
/// Returns true if the src is considered to be enabled,
/// false otherwise.
fn is_src_enabled(
src: &PathBuf,
feat_map: &HashMap<PathBuf, String>,
features: &HashSet<String>,
) -> bool {
for (prefix, feat) in feat_map.iter() {
if src.starts_with(prefix) {
if !features.contains(feat) {
return false;
}
}
}
true
}
static FLAGS: &[&str] = &[
"-std=c99",
"-mcpu=cortex-m4",
"-mthumb",
"-mabi=aapcs",
"-mfloat-abi=hard",
"-mfpu=fpv4-sp-d16",
"-ffunction-sections",
"-fdata-sections",
"-fno-strict-aliasing",
"-fno-builtin",
// the headers are riddled with unused parameters and emit
// hundreds of warnings: suppress them.
"-Wno-unused-parameter",
"-Wno-sign-compare",
"-Wno-missing-field-initializers",
"--short-enums",
];
static DEFINES: &[(&str, Option<&str>)] = &[
("USE_APP_CONFIG", None),
("BLE_STACK_SUPPORT_REQD", None),
("BOARD_PCA10040", None),
("CONFIG_GPIO_AS_PINRESET", None),
("NRF52", None),
("NRF52832_XXAA", None),
("NRF52_PAN_12", None),
("NRF52_PAN_15", None),
("NRF52_PAN_20", None),
("NRF52_PAN_31", None),
("NRF52_PAN_36", None),
("NRF52_PAN_51", None),
("NRF52_PAN_54", None),
("NRF52_PAN_55", None),
("NRF52_PAN_58", None),
("NRF52_PAN_64", None),
("NRF52_PAN_74", None),
("NRF_SD_BLE_API_VERSION", Some("4")),
("S132", None),
("SOFTDEVICE_PRESENT", None),
("SWI_DISABLE0", None),
];
/// The feature names on the RHS need to be enabled in order for the
/// sources on the LFS to get compiled in.
static SRC_TO_FEAT: &[(&str, &str)] = &[
("nRF5-sdk/components/ble/ble_advertising", "BLE_ADVERTISING"),
("nRF5-sdk/components/ble/peer_manager", "PEER_MANAGER"),
("nRF5-sdk/components/libraries/log", "NRF_LOG"),
("nRF5-sdk/components/libraries/crc16", "CRC16"),
("nRF5-sdk/components/libraries/button", "BUTTON"),
("nRF5-sdk/components/drivers_nrf/uart", "UART"),
("nRF5-sdk/components/drivers_nrf/gpiote", "GPIOTE"),
];