1use std::{env, io, path, process, sync::mpsc, thread, time};
2
3pub fn build_native() -> thread::Result<()> {
6 let start = time::Instant::now();
7 let (tx, rx) = mpsc::sync_channel(1);
9 let make = thread::spawn(move || {
10 let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
11 if cfg!(feature = "build_idf") {
12 let res = process::Command::new("idf.py")
13 .arg("build")
14 .current_dir(&path::Path::new(&manifest_dir))
15 .status();
16 match res {
17 Ok(_status) => {},
18 Err(error) if error.kind() == io::ErrorKind::NotFound => panic!("Not found. `source $IDF_PATH/export.sh`?"),
24 Err(error) => panic!("{}", error),
25 }
26 } else if cfg!(feature = "build_make") {
27 process::Command::new("make")
28 .current_dir(&path::Path::new(&manifest_dir))
29 .status()
30 .unwrap();
31 } else {
32 println!("cargo:warning=No build feature enabled. Build skipped.");
33 }
34
35 tx.send(()).unwrap();
36 });
37 loop {
38 match rx.try_recv() {
39 Err(mpsc::TryRecvError::Disconnected) | Ok(_) => break,
40 Err(mpsc::TryRecvError::Empty) => {}
41 }
42 thread::sleep(time::Duration::from_millis(1000));
46 }
47 let ret = make.join();
48 println!("cargo:warning=ESP-IDF build_native() time {:?}", start.elapsed());
50 ret
51}
52
53pub fn print_link_search() {
55 let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
56 if target_arch == "xtensa" {
57 let esp_idf =
58 path::PathBuf::from(env::var("IDF_PATH").expect("IDF_PATH environment variable must be set"));
59 let build_subdir = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("build");
61 if glob::glob(&build_subdir.join("*.bin").to_string_lossy())
62 .unwrap()
63 .next()
64 .is_none()
65 {
66 panic!("No .bin files, did you run `make menuconfig && make`?");
67 }
68
69 let build_dirs = [
70 "esp-idf/esp32",
72 "esp-idf/esp32/ld",
73
74 "app_trace",
75 "app_update",
76 "asio",
77 "bootloader_support",
78 "bt",
79 "cbor",
80 "coap",
81 "console",
82 "cxx",
83 "driver",
84 "efuse",
85 "esp-tls",
86 "esp32",
87 "esp_adc_cal",
88 "esp_common",
89 "esp_eth",
90 "esp_event",
91 "esp_gdbstub",
92 "esp_hid",
93 "esp_http_client",
94 "esp_http_server",
95 "esp_https_ota",
96 "esp_https_server",
97 "esp_ipc",
98 "esp_local_ctrl",
99 "esp_netif",
100 "esp_ringbuf",
101 "esp_rom",
102 "esp_serial_slave_link",
103 "esp_system",
104 "esp_timer",
105 "esp_websocket_client",
106 "esp_wifi",
107 "espcoredump",
108 "ethernet",
109 "expat",
110 "fatfs",
111 "freemodbus",
112 "freertos",
113 "heap",
114 "idf_test",
115 "jsmn",
116 "json",
117 "libsodium",
118 "log",
119 "lwip",
120 "main",
121 "mbedtls",
122 "mdns",
123 "mqtt",
124 "newlib",
125 "nghttp",
126 "nvs_flash",
127 "openssl",
128 "perfmon",
129 "protobuf-c",
130 "protocomm",
131 "pthread",
132 "sdmmc",
133 "smartconfig_ack",
134 "soc",
135 "spi_flash",
136 "spiffs",
137 "tcp_transport",
138 "tcpip_adapter",
139 "ulp",
140 "unity",
141 "vfs",
142 "wear_levelling",
143 "wifi_provisioning",
144 "wpa_supplicant",
145 "xtensa",
146 ]
147 .iter()
148 .map(|subdir| build_subdir.join(subdir));
149 let idf_components = [
150 "esp32/ld",
151 "esp_rom/esp32/ld",
152 "esp_wifi/lib/esp32",
153 "xtensa/esp32",
154 ]
155 .iter()
156 .map(|subdir| esp_idf.join("components").join(subdir));
157
158 for dir in build_dirs.chain(idf_components) {
159 println!("cargo:rustc-link-search=native={}", dir.display());
160 }
161 }
162}
163
164pub fn esptool_write_script() -> io::Result<()> {
167 use io::Write;
168 let root = path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
169 let mut file = std::fs::File::create(root.join("image.sh"))?;
170
171 use std::os::unix::fs::PermissionsExt;
173 let perms = std::fs::Permissions::from_mode(0o744);
174 file.set_permissions(perms)?;
175 let cmd = format!(
176 r#""$IDF_PATH/components/esptool_py/esptool/esptool.py" \
177 --chip esp32 \
178 elf2image \
179 -o build/esp-app.bin \
180 target/{}/{}/{}"#,
181 env::var("TARGET").unwrap(),
182 env::var("PROFILE").unwrap(),
183 env::var("CARGO_PKG_NAME").unwrap()
184 );
185
186 write!(file, "#!/usr/bin/env bash\n\n{}", cmd)
188}