build.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // NOTE: Adapted from cortex-m/build.rs
  2. use std::{collections::HashSet, env, fs, io, path::PathBuf};
  3. fn add_linker_script(arch_width: u32) -> io::Result<()> {
  4. // Read the file to a string and replace all occurrences of ${ARCH_WIDTH} with the arch width
  5. let mut content = fs::read_to_string("link.x.in")?;
  6. content = content.replace("${ARCH_WIDTH}", &arch_width.to_string());
  7. let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
  8. // Put the linker script somewhere the linker can find it
  9. fs::write(out_dir.join("link.x"), content)?;
  10. println!("cargo:rustc-link-search={}", out_dir.display());
  11. println!("cargo:rerun-if-changed=link.x");
  12. Ok(())
  13. }
  14. /// Parse the target RISC-V architecture and returns its bit width and the extension set
  15. fn parse_target(target: &str) -> (u32, HashSet<char>) {
  16. // isolate bit width and extensions from the rest of the target information
  17. let arch = target
  18. .trim_start_matches("riscv")
  19. .split('-')
  20. .next()
  21. .unwrap();
  22. let bits = arch
  23. .chars()
  24. .take_while(|c| c.is_ascii_digit())
  25. .collect::<String>()
  26. .parse::<u32>()
  27. .unwrap();
  28. let mut extensions: HashSet<char> = arch.chars().skip_while(|c| c.is_ascii_digit()).collect();
  29. // get rid of the 'g' shorthand extension
  30. if extensions.remove(&'g') {
  31. extensions.insert('i');
  32. extensions.insert('m');
  33. extensions.insert('a');
  34. extensions.insert('f');
  35. extensions.insert('d');
  36. }
  37. (bits, extensions)
  38. }
  39. fn main() {
  40. let target = env::var("TARGET").unwrap();
  41. let _name = env::var("CARGO_PKG_NAME").unwrap();
  42. // This is required until target_feature risc-v work is stable and in-use (rust 1.75.0)
  43. let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
  44. let cargo_flags = cargo_flags
  45. .split(0x1fu8 as char)
  46. .filter(|arg| !arg.is_empty());
  47. let target_features = cargo_flags
  48. .filter(|k| k.starts_with("target-feature=")).flat_map(|str| {
  49. let flags = str.split('=').collect::<Vec<&str>>()[1];
  50. flags.split(',')
  51. });
  52. // set configuration flags depending on the target
  53. if target.starts_with("riscv") {
  54. println!("cargo:rustc-cfg=riscv");
  55. let (bits, mut extensions) = parse_target(&target);
  56. // generate the linker script and expose the ISA width
  57. let arch_width = match bits {
  58. 32 => {
  59. println!("cargo:rustc-cfg=riscv32");
  60. 4
  61. }
  62. 64 => {
  63. println!("cargo:rustc-cfg=riscv64");
  64. 8
  65. }
  66. _ => panic!("Unsupported bit width"),
  67. };
  68. add_linker_script(arch_width).unwrap();
  69. target_features.for_each(|feature| {
  70. let chars = feature.chars().collect::<Vec<char>>();
  71. if chars[0] == '+' {
  72. extensions.insert(chars[1]);
  73. } else if chars[0] == '-' {
  74. extensions.remove(&chars[1]);
  75. }
  76. });
  77. // expose the ISA extensions
  78. for ext in &extensions {
  79. println!("cargo:rustc-cfg=riscv{}", ext);
  80. }
  81. }
  82. }