build.rs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. use std::env;
  2. use std::fs;
  3. use std::path::{Path, PathBuf};
  4. fn main() {
  5. println!("cargo:rerun-if-env-changed=FORCE_BINDGEN");
  6. let generator = BindingsGenerator::new();
  7. generator.generate_cmsis_os_bindings();
  8. generator.generate_stm32_hal_bindings();
  9. generator.generate_stm32_hal_statics();
  10. }
  11. struct BindingsGenerator {
  12. clib_dir: PathBuf,
  13. workspace_dir: PathBuf,
  14. out_dir: PathBuf,
  15. gcc_include_dir: PathBuf,
  16. force_bindgen: bool,
  17. }
  18. impl BindingsGenerator {
  19. pub fn new() -> Self {
  20. let out_dir = env::var("OUT_DIR").unwrap();
  21. let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
  22. let workspace_dir = Path::new(&crate_dir).parent().unwrap();
  23. let clib_dir = workspace_dir.parent().unwrap().join("target_f1");
  24. assert!(clib_dir.is_dir());
  25. let force_bindgen: bool = std::env::var_os("FORCE_BINDGEN").is_some();
  26. let gcc_include_dir = detect_gcc_inclide_dir();
  27. Self {
  28. clib_dir: clib_dir.to_path_buf(),
  29. workspace_dir: workspace_dir.to_path_buf(),
  30. out_dir: Path::new(&out_dir).to_path_buf(),
  31. gcc_include_dir,
  32. force_bindgen,
  33. }
  34. }
  35. fn builder(&self) -> bindgen::Builder {
  36. let stm32_sdk_includes = [
  37. "Inc",
  38. "Drivers/STM32L4xx_HAL_Driver/Inc",
  39. "Drivers/STM32L4xx_HAL_Driver/Inc/Legacy",
  40. "Middlewares/Third_Party/FreeRTOS/Source/include",
  41. "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS",
  42. "Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F",
  43. "Drivers/CMSIS/Device/ST/STM32L4xx/Include",
  44. "Drivers/CMSIS/Include",
  45. "Middlewares/ST/STM32_USB_Device_Library/Core/Inc",
  46. "Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc",
  47. ];
  48. let stm32_sdk_includes = stm32_sdk_includes
  49. .iter()
  50. .map(|stm32_include| format!("{}/{}", self.clib_dir.to_string_lossy(), stm32_include));
  51. let flipper_core_bindings = self.workspace_dir.join("flipper-core").join("bindings");
  52. let includes = [
  53. // This are bindings generated by cbindgen nearby
  54. &flipper_core_bindings.to_string_lossy(),
  55. &self.gcc_include_dir.to_string_lossy(),
  56. ];
  57. #[rustfmt::skip]
  58. return bindgen::Builder::default()
  59. .use_core()
  60. .ctypes_prefix("self")
  61. .blacklist_type("__uint8_t")
  62. .blacklist_type("__uint32_t")
  63. .blacklist_type("c_int")
  64. .blacklist_type("__int32_t")
  65. // TODO there's no .no_debug method, to disable only for specific type
  66. .derive_debug(false)
  67. .clang_arg("-DUSE_HAL_DRIVER")
  68. .clang_arg("-DSTM32L476xx")
  69. .clang_arg("-DBUTON_INVERT=false")
  70. .clang_arg("-DDEBUG_UART=huart1")
  71. .clang_args(
  72. (includes.iter().map(|x| From::from(x as &str)).chain(stm32_sdk_includes))
  73. .map(|include| format!("-I{}", include))
  74. )
  75. .clang_arg("--target=thumbv7em-none-eabihf")
  76. .clang_arg("--verbose")
  77. //.clang_arg("-nostdinc")
  78. ;
  79. }
  80. pub fn generate_cmsis_os_bindings(&self) {
  81. let result_path = self.out_dir.join("cmsis_os_bindings.rs");
  82. let should_build = !result_path.is_file() || self.force_bindgen;
  83. if !should_build {
  84. return;
  85. }
  86. println!("cargo:warning=writing cmsis os bindings");
  87. #[rustfmt::skip]
  88. let builder = self.builder()
  89. .whitelist_recursively(false)
  90. .header(format!("{}/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS/cmsis_os.h", self.clib_dir.to_string_lossy()))
  91. .whitelist_type("osStatus")
  92. .rustified_enum("osStatus")
  93. .whitelist_type("osEvent")
  94. .whitelist_type("os_pthread")
  95. .whitelist_type("osThreadId")
  96. .opaque_type("osThreadId")
  97. .whitelist_type("os_thread_def")
  98. .whitelist_type("osThreadDef_t")
  99. .whitelist_type("osStaticThreadDef_t")
  100. .opaque_type("osStaticThreadDef_t")
  101. .whitelist_type("osPriority")
  102. .rustified_enum("osPriority")
  103. .whitelist_function("osThreadCreate")
  104. .whitelist_function("osThreadGetId")
  105. .whitelist_function("osThreadTerminate")
  106. .whitelist_function("osThreadYield")
  107. .whitelist_type("osMutexId")
  108. .opaque_type("osMutexId")
  109. .whitelist_type("os_mutex_def")
  110. .whitelist_type("osMutexDef_t")
  111. .whitelist_type("osStaticMutexDef_t")
  112. .opaque_type("osStaticMutexDef_t")
  113. .whitelist_function("osMutexCreate")
  114. .whitelist_function("osMutexWait")
  115. .whitelist_function("osMutexRelease")
  116. .whitelist_type("osSemaphoreId")
  117. .opaque_type("osSemaphoreId")
  118. .whitelist_type("os_semaphore_def")
  119. .whitelist_type("osSemaphoreDef_t")
  120. .whitelist_type("osStaticSemaphoreDef_t")
  121. .opaque_type("osStaticSemaphoreDef_t")
  122. .whitelist_function("osSemaphoreCreate")
  123. .whitelist_function("osSemaphoreWait")
  124. .whitelist_function("osSemaphoreRelease")
  125. .whitelist_type("osMessageQId")
  126. .opaque_type("osMessageQId")
  127. .whitelist_type("osMailQId")
  128. .opaque_type("osMailQId")
  129. .whitelist_type("os_mailQ_def")
  130. .whitelist_type("osMailQDef_t")
  131. .whitelist_type("os_mailQ_cb")
  132. .whitelist_function("osMailCreate")
  133. .whitelist_function("osMailAlloc")
  134. .whitelist_function("osMailFree")
  135. .whitelist_function("osMailPut")
  136. .whitelist_function("osMailGet")
  137. .whitelist_var("osWaitForever")
  138. .whitelist_function("osDelay")
  139. // TODO for some reason, bindgen wont generate osKernelSysTickFrequency
  140. .whitelist_var("osKernelSysTickFrequency")
  141. .whitelist_function("osKernelSysTick")
  142. ;
  143. let bindings = builder.generate().expect("Unable to generate bindings");
  144. bindings
  145. .write_to_file(result_path)
  146. .expect("Couldn't write bindings!");
  147. }
  148. pub fn generate_stm32_hal_bindings(&self) {
  149. let result_path = self.out_dir.join("stm32_hal_bindings.rs");
  150. let should_build = !result_path.is_file() || self.force_bindgen;
  151. if !should_build {
  152. return;
  153. }
  154. println!("cargo:warning=writing STM32 HAL bindings");
  155. #[rustfmt::skip]
  156. let builder = self.builder()
  157. .whitelist_recursively(false)
  158. .header(format!("{}/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_hal.h", self.clib_dir.to_string_lossy()))
  159. .whitelist_type("HAL_StatusTypeDef")
  160. .rustified_enum("HAL_StatusTypeDef")
  161. .whitelist_type("GPIO_TypeDef")
  162. .opaque_type("GPIO_TypeDef")
  163. .whitelist_type("GPIO_PinState")
  164. .rustified_enum("GPIO_PinState")
  165. .whitelist_function("HAL_GPIO_WritePin")
  166. .whitelist_function("HAL_GPIO_TogglePin")
  167. .whitelist_function("HAL_GPIO_ReadPin")
  168. .whitelist_type("UART_HandleTypeDef")
  169. .opaque_type("UART_HandleTypeDef")
  170. .whitelist_function("HAL_UART_Transmit_IT")
  171. .whitelist_type("SPI_HandleTypeDef")
  172. .opaque_type("SPI_HandleTypeDef")
  173. .whitelist_function("HAL_SPI_Transmit_IT")
  174. .whitelist_function("HAL_SPI_Receive_IT")
  175. .whitelist_function("HAL_SPI_TransmitReceive_IT")
  176. .whitelist_type("ADC_HandleTypeDef")
  177. .opaque_type("ADC_HandleTypeDef")
  178. .whitelist_type("COMP_HandleTypeDef")
  179. .opaque_type("COMP_HandleTypeDef")
  180. .whitelist_type("DAC_HandleTypeDef")
  181. .opaque_type("DAC_HandleTypeDef")
  182. .whitelist_type("TIM_HandleTypeDef")
  183. .opaque_type("TIM_HandleTypeDef")
  184. ;
  185. let bindings = builder.generate().expect("Unable to generate bindings");
  186. bindings
  187. .write_to_file(result_path)
  188. .expect("Couldn't write bindings!");
  189. }
  190. pub fn generate_stm32_hal_statics(&self) {
  191. let result_path = self.out_dir.join("stm32_hal_statics.rs");
  192. let should_build = !result_path.is_file() || self.force_bindgen;
  193. if !should_build {
  194. return;
  195. }
  196. println!("cargo:warning=writing STM32 HAL bindings");
  197. #[rustfmt::skip]
  198. let builder = self.builder()
  199. .whitelist_recursively(false)
  200. .header(format!("{}/Src/main.c", self.clib_dir.to_string_lossy()))
  201. .whitelist_var(".*_Pin")
  202. .whitelist_var(".*_Port")
  203. .whitelist_var("HAL_.*_Pin")
  204. .whitelist_var("HAL_.*_Port")
  205. .whitelist_var("hadc[0-9]+")
  206. .whitelist_var("hcomp[0-9]+")
  207. .whitelist_var("hdac[0-9]+")
  208. .whitelist_var("hspi[0-9]+")
  209. .whitelist_var("htim[0-9]+")
  210. .whitelist_var("huart[0-9]+")
  211. ;
  212. let bindings = builder.generate().expect("Unable to generate bindings");
  213. bindings
  214. .write_to_file(result_path)
  215. .expect("Couldn't write bindings!");
  216. }
  217. }
  218. fn detect_gcc_inclide_dir() -> PathBuf {
  219. let base_path = Path::new("/usr/lib/gcc/arm-none-eabi");
  220. if !base_path.is_dir() {
  221. panic!("Can't find arm-none-eabi-gcc lib directory");
  222. }
  223. let entries = fs::read_dir(base_path).expect("Can't read arm-none-eabi-gcc lib directory");
  224. for entry in entries {
  225. let entry = entry.expect("Can't read dir entry");
  226. let path = entry.path();
  227. if path.is_dir() {
  228. let include_dir = path.join("include");
  229. if include_dir.is_dir() {
  230. return include_dir.to_path_buf();
  231. }
  232. }
  233. }
  234. panic!("Can't find arm-none-eabi-gcc include directory");
  235. }