// SPDX-License-Identifier: GPL-2.0 use std::path::PathBuf; use std::env; const INCLUDED_TYPES: &[&str] = &["file_system_type", "mode_t", "umode_t", "ctl_table"]; const INCLUDED_FUNCTIONS: &[&str] = &[ "cdev_add", "cdev_init", "cdev_del", "register_filesystem", "unregister_filesystem", "krealloc", "kfree", "mount_nodev", "kill_litter_super", "register_sysctl", "unregister_sysctl_table", "access_ok", "_copy_to_user", "_copy_from_user", "alloc_chrdev_region", "unregister_chrdev_region", "wait_for_random_bytes", "get_random_bytes", "rng_is_initialized", "printk", "add_device_randomness", ]; const INCLUDED_VARS: &[&str] = &[ "EINVAL", "ENOMEM", "ESPIPE", "EFAULT", "EAGAIN", "__this_module", "FS_REQUIRES_DEV", "FS_BINARY_MOUNTDATA", "FS_HAS_SUBTYPE", "FS_USERNS_MOUNT", "FS_RENAME_DOES_D_MOVE", "BINDINGS_GFP_KERNEL", "KERN_INFO", "VERIFY_WRITE", "LINUX_VERSION_CODE", "SEEK_SET", "SEEK_CUR", "SEEK_END", "O_NONBLOCK", "param_ops_bool", "param_ops_int", ]; const OPAQUE_TYPES: &[&str] = &[ // These need to be opaque because they're both packed and aligned, which rustc // doesn't support yet. See https://github.com/rust-lang/rust/issues/59154 // and https://github.com/rust-lang/rust-bindgen/issues/1538 "desc_struct", "xregs_state", ]; // Takes the CFLAGS from the kernel Makefile and changes all the include paths to be absolute // instead of relative. fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Vec { let cflag_parts = shlex::split(&cflags).unwrap(); let mut cflag_iter = cflag_parts.iter(); let mut kernel_args = vec![]; while let Some(arg) = cflag_iter.next() { // TODO: bindgen complains if arg.starts_with("-Wp,-MMD") { continue; } if arg.starts_with("-I") && !arg.starts_with("-I/") { kernel_args.push(format!("-I{}/{}", kernel_dir, &arg[2..])); } else if arg == "-include" { kernel_args.push(arg.to_string()); let include_path = cflag_iter.next().unwrap(); if include_path.starts_with('/') { kernel_args.push(include_path.to_string()); } else { kernel_args.push(format!("{}/{}", kernel_dir, include_path)); } } else { kernel_args.push(arg.to_string()); } } kernel_args } fn main() { println!("cargo:rerun-if-env-changed=CC"); println!("cargo:rerun-if-env-changed=RUST_BINDGEN_CFLAGS"); let kernel_dir = "../../"; let cflags = env::var("RUST_BINDGEN_CFLAGS") .expect("Must be invoked from kernel makefile"); let kernel_args = prepare_cflags(&cflags, &kernel_dir); let target = env::var("TARGET").unwrap(); let mut builder = bindgen::Builder::default() .use_core() .ctypes_prefix("c_types") .derive_default(true) .size_t_is_usize(true) .rustfmt_bindings(true); builder = builder.clang_arg(format!("--target={}", target)); for arg in kernel_args.iter() { builder = builder.clang_arg(arg.clone()); } println!("cargo:rerun-if-changed=src/bindings_helper.h"); builder = builder.header("src/bindings_helper.h"); for t in INCLUDED_TYPES { builder = builder.whitelist_type(t); } for f in INCLUDED_FUNCTIONS { builder = builder.whitelist_function(f); } for v in INCLUDED_VARS { builder = builder.whitelist_var(v); } for t in OPAQUE_TYPES { builder = builder.opaque_type(t); } let bindings = builder.generate().expect("Unable to generate bindings"); let out_path = PathBuf::from("src/bindings_gen.rs"); bindings .write_to_file(out_path) .expect("Couldn't write bindings!"); }