blob: e562691d81bf516014e1cf6501c464fb754f86a4 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
extern crate bindgen;
use bindgen::builder;
use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use std::str;
fn copy_headers(src_dir: &Path, dst_dir: &Path) -> Result<(), String> {
if dst_dir.is_file() {
fs::remove_file(&dst_dir).or_else(|e| {
Err(format!(
"failed to remove existing file at {:?}: {}",
dst_dir, e
))
})?;
}
if !dst_dir.is_dir() {
fs::create_dir(&dst_dir).or_else(|e| {
Err(format!(
"failed to create destination directory: {:?}: {}",
dst_dir, e
))
})?;
}
let header_files = vec![
"cras_audio_format.h",
"cras_iodev_info.h",
"cras_messages.h",
"cras_shm.h",
"cras_types.h",
"cras_util.h",
"packet_status_logger.h",
];
for header in &header_files {
let src = src_dir.join(&header);
let dst = dst_dir.join(&header);
fs::copy(&src, &dst).or_else(|e| {
Err(format!(
"failed to copy header file {:?} to {:?}: {}",
src, dst, e
))
})?;
}
Ok(())
}
/*
* If we use both `packed` and `align(4)` for a struct, bindgen will generate
* it as an opaque struct.
*
* `cras_server_state` is created from C with `packed` and `aligned(4)` and
* shared through a shared memory area.
*
* Structs with `packed` and `align(4)` have the same memory layout as those
* with `packed` except for some extra alignment bytes at the end.
*
* Therefore, using only `packed` for `cras_server_state` from Rust side is safe.
*
* This function modifies `cras_server_state` from
* `__attribute__ ((packed, aligned(4)))` to `__attribute__ ((packed))`
*/
fn modify_server_state_attributes(dir: &Path) -> Result<(), String> {
let cras_types_path = dir.join("cras_types.h");
let bytes = fs::read(&cras_types_path)
.or_else(|e| Err(format!("failed to read {:?}: {}", cras_types_path, e)))?;
let old = str::from_utf8(&bytes).or_else(|e| {
Err(format!(
"failed to parse {:?} as utf8: {}",
cras_types_path, e
))
})?;
let new = old.replacen(
"struct __attribute__((packed, aligned(4))) cras_server_state {",
"struct __attribute__((packed)) cras_server_state {",
1,
);
if new.len() >= old.len() {
return Err("failed to remove 'aligned(4)' from cras_server_state".to_string());
}
fs::write(&cras_types_path, new).or_else(|e| {
Err(format!(
"failed to write updated contents to {:?}: {}",
cras_types_path, e
))
})?;
Ok(())
}
fn gen() -> String {
let name = "cras_gen";
let bindings = builder()
.header("c_headers/cras_messages.h")
.header("c_headers/cras_types.h")
.header("c_headers/cras_audio_format.h")
.header("c_headers/cras_shm.h")
.whitelist_type("cras_.*")
.whitelist_var("cras_.*")
.whitelist_type("CRAS_.*")
.whitelist_var("CRAS_.*")
.whitelist_type("audio_message")
.whitelist_var("MAX_DEBUG_.*")
.rustified_enum("CRAS_.*")
.rustified_enum("_snd_pcm_.*")
.bitfield_enum("CRAS_STREAM_EFFECT")
.generate()
.expect(format!("Unable to generate {} code", name).as_str());
bindings.to_string()
}
fn write_output(output_path: &Path, output: String) -> std::io::Result<()> {
let header = b"// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/*
* generated from files in cras/src/common in adhd:
* cras_audio_format.h
* cras_iodev_info.h
* cras_messages.h
* cras_shm.h
* cras_types.h
* cras_util.h
* packet_status_logger.h
*/
#![allow(clippy::unreadable_literal)]
#![allow(clippy::cognitive_complexity)]
";
let mut output_file = File::create(output_path)?;
output_file.write_all(header)?;
output_file.write_all(output.as_bytes())?;
Ok(())
}
fn main() {
let src_header_dir = Path::new("../../../src/common");
let dst_header_dir = Path::new("./c_headers");
copy_headers(src_header_dir, dst_header_dir).expect("failed to copy C headers");
modify_server_state_attributes(dst_header_dir)
.expect("failed to modify cras_server_state's attributes");
let generated_code = gen();
write_output(Path::new("lib_gen.rs"), generated_code).expect("failed to write generated code");
}