build.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  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, cargo_flags: &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. // expand the 'g' shorthand extension
  30. if extensions.contains(&'g') {
  31. extensions.insert('i');
  32. extensions.insert('m');
  33. extensions.insert('a');
  34. extensions.insert('f');
  35. extensions.insert('d');
  36. }
  37. let cargo_flags = cargo_flags
  38. .split(0x1fu8 as char)
  39. .filter(|arg| !arg.is_empty());
  40. cargo_flags
  41. .filter(|k| k.starts_with("target-feature="))
  42. .flat_map(|str| {
  43. let flags = str.split('=').collect::<Vec<&str>>()[1];
  44. flags.split(',')
  45. })
  46. .for_each(|feature| {
  47. let chars = feature.chars().collect::<Vec<char>>();
  48. match chars[0] {
  49. '+' => {
  50. extensions.insert(chars[1]);
  51. }
  52. '-' => {
  53. extensions.remove(&chars[1]);
  54. }
  55. _ => {
  56. panic!("Unsupported target feature operation");
  57. }
  58. }
  59. });
  60. (bits, extensions)
  61. }
  62. fn main() {
  63. let target = env::var("TARGET").unwrap();
  64. let cargo_flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap();
  65. let _name = env::var("CARGO_PKG_NAME").unwrap();
  66. // set configuration flags depending on the target
  67. if target.starts_with("riscv") {
  68. println!("cargo:rustc-cfg=riscv");
  69. // This is required until target_arch & target_feature risc-v work is
  70. // stable and in-use (rust 1.75.0)
  71. let (bits, extensions) = parse_target(&target, &cargo_flags);
  72. // generate the linker script and expose the ISA width
  73. let arch_width = match bits {
  74. 32 => {
  75. println!("cargo:rustc-cfg=riscv32");
  76. 4
  77. }
  78. 64 => {
  79. println!("cargo:rustc-cfg=riscv64");
  80. 8
  81. }
  82. _ => panic!("Unsupported bit width"),
  83. };
  84. add_linker_script(arch_width).unwrap();
  85. // expose the ISA extensions
  86. for ext in &extensions {
  87. println!("cargo:rustc-cfg=riscv{}", ext);
  88. }
  89. }
  90. }