use std::{
env,
path::{Path, PathBuf},
};
const PAHO_MQTT_C_VERSION: &str = "1.3.13";
fn main() {
build::main();
}
fn is_windows() -> bool {
env::var("CARGO_CFG_WINDOWS").is_ok()
}
fn is_msvc() -> bool {
env::var("CARGO_CFG_TARGET_ENV").unwrap() == "msvc"
}
fn pointer_width() -> u32 {
env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
.map(|s| s.parse::<u32>().unwrap())
.unwrap()
}
fn link_lib_base() -> &'static str {
if cfg!(feature = "ssl") {
println!("debug:link Using SSL library");
if is_windows() { "paho-mqtt3as-static" } else { "paho-mqtt3as" }
}
else {
println!("debug:link Using non-SSL library");
if is_windows() { "paho-mqtt3a-static" } else { "paho-mqtt3a" }
}
}
fn find_link_lib<P>(install_path: P) -> Option<(PathBuf,&'static str)>
where P: AsRef<Path>
{
let install_path = install_path.as_ref();
let lib_dirs = &[ "lib", "lib64" ];
let lib_base = link_lib_base();
let lib_file = if is_msvc() {
format!("{}.lib", lib_base)
}
else {
format!("lib{}.a", lib_base)
};
for dir in lib_dirs {
let lib_path = install_path.join(dir);
let lib = lib_path.join(&lib_file);
if lib.exists() {
return Some((lib_path, lib_base));
}
}
None
}
#[cfg(not(feature = "build_bindgen"))]
mod bindings {
use super::*;
use std::fs;
pub fn place_bindings(_inc_dir: &Path) {
let target = env::var("TARGET").unwrap();
println!("debug:Using existing Paho C binding for target: {}", target);
let out_dir = env::var("OUT_DIR").unwrap();
let out_path = Path::new(&out_dir).join("bindings.rs");
let ptr_wd = pointer_width();
println!("debug:Target Pointer Width: {}", ptr_wd);
let mut bindings = format!("bindings/bindings_paho_mqtt_c_{}-{}.rs",
PAHO_MQTT_C_VERSION, target);
if !Path::new(&bindings).exists() {
println!("No bindings exist for: {}. Using {}-bit default.",
bindings, ptr_wd);
bindings = format!("bindings/bindings_paho_mqtt_c_{}-default-{}.rs",
PAHO_MQTT_C_VERSION, ptr_wd)
}
println!("debug:Using bindings from: {}", bindings);
fs::copy(&bindings, out_path)
.expect("Could not copy bindings to output directory");
}
}
#[cfg(feature = "build_bindgen")]
mod bindings {
extern crate bindgen;
use super::*;
use std::{
fs, env,
path::{Path, PathBuf},
};
pub fn place_bindings(inc_dir: &Path) {
println!("debug:Using bindgen for Paho C");
let cver = bindgen::clang_version();
println!("debug:clang version: {}", cver.full);
let inc_search = format!("-I{}", inc_dir.display());
println!("debug:bindgen include path: {}", inc_search);
let bindings = bindgen::Builder::default()
.trust_clang_mangling(false)
.header("wrapper.h").clang_arg(inc_search)
.generate()
.expect("Unable to generate bindings");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_path = out_dir.join("bindings.rs");
bindings.write_to_file(out_path.clone())
.expect("Couldn't write bindings!");
let target = env::var("TARGET").unwrap();
println!("debug:Target: {}", target);
let bindings = format!("bindings/bindings_paho_mqtt_c_{}-{}.rs",
PAHO_MQTT_C_VERSION, target);
if !Path::new(&bindings).exists() {
if let Err(err) = fs::copy(out_path, &bindings) {
println!("debug:Error copying new binding file: {}", err);
}
else {
println!("debug:Created new bindings file {}", bindings)
}
}
}
}
#[cfg(feature = "bundled")]
mod build {
extern crate cmake;
use super::*;
use std::{
process,
process::Command,
};
fn openssl_root_dir() -> Option<String> {
env::var("DEP_OPENSSL_INCLUDE").ok().and_then(|path| {
Path::new(&path)
.parent()
.map(|path| path.display().to_string())
})
}
pub fn main() {
println!("debug:Running the bundled build for Paho C");
if is_windows() {
println!("debug:Building for Windows");
if is_msvc() {
println!("debug:Building with MSVC");
}
}
println!("cargo:rerun-if-changed=build.rs");
if !Path::new("paho.mqtt.c/.git").exists() {
let _ = Command::new("git")
.args(["submodule", "update", "--init"])
.status();
}
let ssl = if cfg!(feature = "ssl") { "on" } else { "off" };
let mut cmk_cfg = cmake::Config::new("paho.mqtt.c/");
cmk_cfg
.define("PAHO_BUILD_SHARED", "off")
.define("PAHO_BUILD_STATIC", "on")
.define("PAHO_ENABLE_TESTING", "off")
.define("PAHO_HIGH_PERFORMANCE", "on")
.define("PAHO_WITH_SSL", ssl);
if is_msvc() {
cmk_cfg.cflag("/DWIN32");
}
if let Some(ssl_dir) = openssl_root_dir() {
cmk_cfg.define("OPENSSL_ROOT_DIR", ssl_dir);
}
let cmk_install_path = cmk_cfg.build();
println!("debug:CMake output dir: {}", cmk_install_path.display());
let (lib_path, link_lib) = match find_link_lib(&cmk_install_path) {
Some(lib) => lib,
_ => {
println!("Error building Paho C library.");
process::exit(103);
},
};
println!("debug:Using Paho C library at: {} [{}]", lib_path.display(), link_lib);
let inc_dir = cmk_install_path.join("include");
println!("debug:Using Paho C headers at: {}", inc_dir.display());
bindings::place_bindings(&inc_dir);
if cfg!(feature = "ssl") {
if let Some(openssl_root_dir) = openssl_root_dir() {
println!("cargo:rustc-link-search={}/lib", openssl_root_dir);
}
let linkage = match env::var("OPENSSL_STATIC")
.as_ref()
.map(|s| s.as_str())
{
Ok("0") => "",
Ok(_) => "=static",
Err(_) => ""
};
let prefix = if is_msvc() { "lib" } else { "" };
println!("cargo:rustc-link-lib{}={}ssl", linkage, prefix);
println!("cargo:rustc-link-lib{}={}crypto", linkage, prefix);
if is_windows() {
if !is_msvc() {
println!("cargo:rustc-link-lib{}=crypt32", linkage);
println!("cargo:rustc-link-lib{}=rpcrt4", linkage);
}
println!("cargo:rustc-link-lib=User32");
}
}
println!("cargo:rustc-link-search=native={}", lib_path.display());
println!("cargo:rustc-link-lib=static={}", link_lib);
}
}
#[cfg(not(feature = "bundled"))]
mod build {
use super::*;
use std::{
env,
path::Path,
};
fn find_paho_c() -> Option<String> {
let link_lib = link_lib_base();
println!("cargo:rerun-if-env-changed=PAHO_MQTT_C_DIR");
println!("cargo:rerun-if-env-changed=PAHO_MQTT_C_INCLUDE_DIR");
println!("cargo:rerun-if-env-changed=PAHO_MQTT_C_LIB_DIR");
if cfg!(target_os = "windows") {
println!("cargo:rerun-if-env-changed=PATH");
}
println!("debug:Building with existing library: {}", link_lib);
println!("cargo:rustc-link-lib={}", link_lib);
if let Ok(lib_dir) = env::var("PAHO_MQTT_C_LIB_DIR") {
if let Ok(inc_dir) = env::var("PAHO_MQTT_C_INCLUDE_DIR") {
println!("debug:inc_dir={}", inc_dir);
println!("debug:lib_dir={}", lib_dir);
println!("cargo:rustc-link-search={}", lib_dir);
Some(inc_dir)
}
else {
panic!("If specifying lib dir, must also specify include dir");
}
}
else if let Ok(dir) = env::var("PAHO_MQTT_C_DIR") {
if let Some((lib_path, _link_lib)) = find_link_lib(&dir) {
println!("cargo:rustc-link-search={}", lib_path.display());
Some(format!("{}/include", dir))
}
else {
None
}
}
else {
None
}
}
pub fn main() {
println!("debug:Running the un-bundled build for Paho C");
println!("cargo:rerun-if-changed=paho.mqtt.c/");
let inc_dir = find_paho_c().unwrap_or_default();
if cfg!(feature = "build_bindgen") && inc_dir.is_empty() {
panic!("Can't generate bindings. Unknown library location");
}
bindings::place_bindings(&Path::new(&inc_dir));
}
}