use std::collections::HashMap; use std::env; use std::path::PathBuf; use semver::Version; use clang::{token::TokenKind::Punctuation, Clang, Index}; fn main() { let ver = env!("CARGO_PKG_VERSION"); let ver = Version::parse(ver).unwrap(); dbg!(&ver); let header_ver = get_core_version_from_header(); dbg!(&header_ver); assert_eq!(ver, header_ver); bind(".".into(), "c2a_core_main.h"); //bind("system/time_manager".into(), "time_manager.h"); //bind("system/watchdog_timer".into(), "watchdog_timer.h"); bind("hal".into(), "ccsds.h"); bind("hal".into(), "i2c.h"); bind("hal".into(), "spi.h"); bind("hal".into(), "uart.h"); bind("hal".into(), "wdt.h"); } fn bind(module: PathBuf, header: &str) { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let gen_rs = header.replace(".h", ".rs"); let gen_rs = out_dir.join(gen_rs); let header_path = module.join(header); c2a_bind_utils::bind_c2a(header_path, gen_rs) } fn get_core_version_from_header() -> Version { let macros = get_definitions("c2a_core_main.h"); let major: u64 = macros .get("C2A_CORE_VER_MAJOR") .expect("failed to get major ver") .as_ref() .unwrap() .parse() .expect("failed to parse as u64"); let minor: u64 = macros .get("C2A_CORE_VER_MINOR") .expect("failed to get minor ver") .as_ref() .unwrap() .parse() .expect("failed to parse as u64"); let patch: u64 = macros .get("C2A_CORE_VER_PATCH") .expect("failed to get patch ver") .as_ref() .unwrap() .parse() .expect("failed to parse as u64"); let pre = macros .get("C2A_CORE_VER_PRE") .expect("failed to get pre ver") .as_ref() .unwrap(); let pre = semver::Prerelease::new(pre).expect("failed to parse as pre release"); Version { major, minor, patch, pre, build: semver::BuildMetadata::EMPTY, } } fn get_definitions(src_file: &str) -> HashMap> { let mut macros = HashMap::new(); let clang = Clang::new().expect("failed to acquire clang instance"); let index = Index::new(&clang, false, false); let tu = index .parser(src_file) .detailed_preprocessing_record(true) .parse() .expect("failed to parse c2a-core main header"); let entity = tu.get_entity(); let childlen = entity.get_children().into_iter(); for cursor in childlen { match cursor.get_kind() { clang::EntityKind::MacroDefinition => { let location = cursor.get_location().unwrap().get_file_location(); if let Some(file) = location.file { let file = file.get_path(); let _f = file.to_str().unwrap(); } else { continue; } let name = cursor.get_display_name().unwrap(); let mut token = cursor.get_range().unwrap().tokenize(); token.remove(0); // remove macro Identifier token if token.is_empty() { macros.insert(name, None); continue; // remove define only } let first = token.first().unwrap(); let last = token.last().unwrap(); if first.get_kind() == Punctuation && last.get_kind() == Punctuation && first.get_spelling() == "(" && last.get_spelling() == ")" { token.remove(0); token.remove(token.len() - 1); } if token.len() == 1 { let value = token[0].get_spelling(); let value = if value.starts_with('\"') && value.ends_with('\"') { let value = value.strip_prefix('\"').unwrap(); value.strip_suffix('\"').unwrap().to_string() } else { value }; macros.insert(name, Some(value)); } else { // 単純な値ではなかった(ex: 関数マクロ) dbg!(token); } } _ => {} } } macros }