use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path::Path;
use std::error::Error;
use std::string::ToString;
use std::collections::hash_map::Iter;
const DBUS_VERSION: &str = "\"1.14.4\"";
const DBUS_VERSION_MAJOR: u32 = 1;
const DBUS_VERSION_MINOR: u32 = 14;
const DBUS_VERSION_MICRO: u32 = 4;
const DBUS_SYSTEM_BUS_DEFAULT_ADDRESS: &str = "/run/dbus/system_bus_socket";
const DBUS_SESSION_SOCKET_DIR: &str = "/tmp";
const DBUS_MACHINE_UUID_FILE: &str = "/etc/machine-id";
const SOURCE_FILES: &'static [&'static str] = &[
"./vendor/dbus/dbus/dbus-address.c",
"./vendor/dbus/dbus/dbus-auth.c",
"./vendor/dbus/dbus/dbus-bus.c",
"./vendor/dbus/dbus/dbus-connection.c",
"./vendor/dbus/dbus/dbus-credentials.c",
"./vendor/dbus/dbus/dbus-errors.c",
"./vendor/dbus/dbus/dbus-keyring.c",
"./vendor/dbus/dbus/dbus-marshal-byteswap.c",
"./vendor/dbus/dbus/dbus-marshal-header.c",
"./vendor/dbus/dbus/dbus-marshal-recursive.c",
"./vendor/dbus/dbus/dbus-marshal-validate.c",
"./vendor/dbus/dbus/dbus-message.c",
"./vendor/dbus/dbus/dbus-misc.c",
"./vendor/dbus/dbus/dbus-nonce.c",
"./vendor/dbus/dbus/dbus-object-tree.c",
"./vendor/dbus/dbus/dbus-pending-call.c",
"./vendor/dbus/dbus/dbus-resources.c",
"./vendor/dbus/dbus/dbus-server-debug-pipe.c",
"./vendor/dbus/dbus/dbus-server-socket.c",
"./vendor/dbus/dbus/dbus-server.c",
"./vendor/dbus/dbus/dbus-sha.c",
"./vendor/dbus/dbus/dbus-signature.c",
"./vendor/dbus/dbus/dbus-syntax.c",
"./vendor/dbus/dbus/dbus-threads.c",
"./vendor/dbus/dbus/dbus-timeout.c",
"./vendor/dbus/dbus/dbus-transport-socket.c",
"./vendor/dbus/dbus/dbus-transport.c",
"./vendor/dbus/dbus/dbus-watch.c",
];
const INTERNAL_FILES: &'static [&'static str] = &[
"./vendor/dbus/dbus/dbus-dataslot.c",
"./vendor/dbus/dbus/dbus-file.c",
"./vendor/dbus/dbus/dbus-hash.c",
"./vendor/dbus/dbus/dbus-internals.c",
"./vendor/dbus/dbus/dbus-list.c",
"./vendor/dbus/dbus/dbus-marshal-basic.c",
"./vendor/dbus/dbus/dbus-memory.c",
"./vendor/dbus/dbus/dbus-mempool.c",
"./vendor/dbus/dbus/dbus-pipe.c",
"./vendor/dbus/dbus/dbus-string.c",
"./vendor/dbus/dbus/dbus-sysdeps.c",
];
const UNIX_SOURCES: &'static [&'static str] = &[
"./vendor/dbus/dbus/dbus-uuidgen.c",
"./vendor/dbus/dbus/dbus-server-unix.c",
"./vendor/dbus/dbus/dbus-file-unix.c",
"./vendor/dbus/dbus/dbus-pipe-unix.c",
"./vendor/dbus/dbus/dbus-sysdeps-pthread.c",
"./vendor/dbus/dbus/dbus-sysdeps-unix.c",
"./vendor/dbus/dbus/dbus-transport-unix.c",
"./vendor/dbus/dbus/dbus-userdb.c",
];
const CWARNINGS: &'static [&'static str] = &[
"-Wno-missing-field-initializers",
"-Wno-unused-parameter",
"-Wno-error=duplicated-branches",
"-Wno-error=cast-align",
"-Wno-error=sign-compare",
"-Wno-error=unused-but-set-variable",
"-Warray-bounds",
"-Wchar-subscripts",
"-Wdouble-promotion",
"-Wduplicated-branches",
"-Wduplicated-cond",
"-Wfloat-equal",
"-Wformat-nonliteral",
"-Wformat-security",
"-Wformat=2",
"-Winit-self",
"-Winline",
"-Wlogical-op",
"-Wmissing-declarations",
"-Wmissing-format-attribute",
"-Wmissing-include-dirs",
"-Wmissing-noreturn",
"-Wnull-dereference",
"-Wpacked",
"-Wpointer-arith",
"-Wredundant-decls",
"-Wrestrict",
"-Wreturn-type",
"-Wshadow",
"-Wstrict-aliasing",
"-Wswitch-default",
"-Wswitch-enum",
"-Wundef",
"-Wunused-but-set-variable",
"-Wwrite-strings",
"-Wdeclaration-after-statement",
"-Wimplicit-function-declaration",
"-Wjump-misses-init",
"-Wmissing-prototypes",
"-Wnested-externs",
"-Wold-style-definition",
"-Wpointer-sign",
"-Wstrict-prototypes",
];
struct Config<'a> {
defs: HashMap<&'a str, Option<String>>,
undefs: Vec<&'a str>,
}
impl<'a> Config<'a> {
fn new() -> Self {
Self {
defs: HashMap::new(),
undefs: Vec::new(),
}
}
fn enable(&mut self, flag: &'a str) {
self.defs.insert(flag, None);
}
fn disable(&mut self, flag: &'a str) {
self.undefs.push(flag);
}
fn set<T: ToString>(&mut self, flag: &'a str, value: T) {
self.defs.insert(flag, Some(value.to_string()));
}
fn defs<'b>(&'b self) -> Iter<'b, &'a str, Option<String>> {
self.defs.iter()
}
fn undefs<'b>(&'b self) -> std::slice::Iter<'b, &'a str> {
self.undefs.iter()
}
}
fn generate_stubs(outdir: &str) -> Result<(), Box<dyn Error>> {
let mut config = File::create(format!("{}/include/config.h", outdir))?;
let mut arch = File::create(format!("{}/include/dbus/dbus-arch-deps.h", outdir))?;
config.write_all(b"
#pragma once
#pragma GCC diagnostic ignored \"-Wunused-but-set-variable\"
#if ((defined __GNUC__ && __GNUC__ > 7) || defined(__clang__))
#pragma GCC diagnostic ignored \"-Wduplicated-branches\"
#pragma GCC diagnostic ignored \"-Wsign-compare\"
#endif
")?;
arch.write_all(b"
#ifndef DBUS_ARCH_DEPS_H
#define DBUS_ARCH_DEPS_H
#include <stdint.h>
#include <stdarg.h>
#include <dbus/dbus-macros.h>
DBUS_BEGIN_DECLS
_DBUS_GNUC_EXTENSION typedef int64_t dbus_int64_t;
_DBUS_GNUC_EXTENSION typedef uint64_t dbus_uint64_t;
#define DBUS_INT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION (val##L))
#define DBUS_UINT64_CONSTANT(val) (_DBUS_GNUC_EXTENSION (val##UL))
typedef int32_t dbus_int32_t;
typedef uint32_t dbus_uint32_t;
typedef int16_t dbus_int16_t;
typedef uint16_t dbus_uint16_t;
// Required for 1.14 but not 1.15
#define DBUS_VA_COPY va_copy
DBUS_END_DECLS
#endif /* DBUS_ARCH_DEPS_H */
")?;
Ok(())
}
fn generate_config(cc: &mut cc::Build, config: &mut Config) -> Result<(), Box<dyn Error>> {
let ptr_width: u32 = u32::from_str_radix(&env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
.or(Err("Pointer width missing."))?, 10)?;
config.set("DBUS_SIZEOF_VOID_P", ptr_width / 8);
config.enable("DBUS_COMPILATION");
config.enable("DBUS_HAVE_INT64");
config.enable("DBUS_INT64_MODIFIER");
config.enable("HAVE_BYTESWAP_H");
let version_number = (DBUS_VERSION_MAJOR << 16) | (DBUS_VERSION_MINOR << 8) | DBUS_VERSION_MICRO;
config.set("VERSION", DBUS_VERSION);
config.set("DBUS_VERSION_STRING", DBUS_VERSION);
config.set("DBUS_VERSION", version_number);
config.set("DBUS_MAJOR_VERSION", DBUS_VERSION_MAJOR);
config.set("DBUS_MINOR_VERSION", DBUS_VERSION_MINOR);
config.set("DBUS_MICRO_VERSION", DBUS_VERSION_MICRO);
config.set("DBUS_SESSION_BUS_CONNECT_ADDRESS", "\"autolaunch:\"");
config.enable("HAVE_DECL_MSG_NOSIGNAL");
config.enable("DBUS_USE_SYNC");
config.enable("DBUS_ENABLE_CHECKS");
config.disable("DBUS_DISABLE_CHECKS");
config.enable("DBUS_DISABLE_ASSERT");
match env::var("CARGO_CFG_TARGET_ENDIAN").as_deref() {
Ok("little") => {
config.disable("WORDS_BIGENDIAN");
},
Ok("big") => {
config.enable("WORDS_BIGENDIAN");
}
_ => unreachable!(),
}
match env::var("CARGO_CFG_TARGET_OS").as_deref() {
Ok("linux") => {
config.enable("DBUS_UNIX");
config.enable("DBUS_HAVE_LINUX_EPOLL");
config.enable("HAVE_EPOLL");
config.enable("HAVE_ERRNO_H");
config.enable("HAVE_SOCKLEN_T");
config.enable("HAVE_GETPWNAM_R");
config.enable("HAVE_UNIX_FD_PASSING");
config.enable("HAVE_LOCALE_H");
config.enable("HAVE_DECL_ENVIRON");
config.disable("HAVE_GETPEERUCRED");
config.disable("HAVE_CMSGCRED");
let bus = format!("\"unix:path={}\"", DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
let dir = format!("\"{}\"", DBUS_SESSION_SOCKET_DIR);
let uid = format!("\"{}\"", DBUS_MACHINE_UUID_FILE);
config.set("DBUS_SESSION_SOCKET_DIR", dir);
config.set("DBUS_SYSTEM_BUS_DEFAULT_ADDRESS", bus);
config.set("DBUS_MACHINE_UUID_FILE", uid);
config.enable("_GNU_SOURCE");
cc.files(UNIX_SOURCES);
}
_ => return Err("Unsupported platform.".into()),
}
Ok(())
}
pub fn build_libdbus() -> Result<(), Box<dyn Error>> {
let mut compiler = cc::Build::new();
let mut config = Config::new();
let outdir = env::var("OUT_DIR").or(Err("No output directory."))?;
std::fs::create_dir_all(format!("{}/include/dbus", &outdir))?;
if !Path::new("vendor/dbus/dbus").exists() {
let _ = Command::new("git")
.args(&["submodule", "update", "--init", "vendor/dbus"])
.status()?;
}
generate_config(&mut compiler, &mut config)?;
generate_stubs(&outdir)?;
compiler.files(SOURCE_FILES);
compiler.files(INTERNAL_FILES);
compiler.include(format!("{}/include", &outdir));
compiler.include("./vendor/dbus/");
for (opt, val) in config.defs() {
compiler.define(opt, val.as_deref());
}
for opt in config.undefs() {
compiler.flag(&format!("-U{}", opt));
}
for flag in CWARNINGS.iter() {
compiler.flag_if_supported(flag);
}
compiler.flag_if_supported("-fno-strict-aliasing");
compiler
.shared_flag(false)
.static_flag(true)
.compile("libdbus.a");
println!("cargo:rustc-link-search=native={}", outdir);
println!("cargo:rustc-link-lib=static=dbus");
Ok(())
}