forked from jsloth/mosquitto-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.rs
240 lines (203 loc) · 8.05 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/// this file is mainly inspired by the great c library integration from https://github.com/eclipse/paho.mqtt.rust
fn main() {
bundled::main();
}
const MOSQUITTO_GIT_URL: &str = "https://github.com/eclipse/mosquitto.git";
const MOSQUITTO_VERSION: &str = "2.0.4";
#[cfg(feature = "build_bindgen")]
mod bindings {
use std::{env, fs};
use std::path::{Path, PathBuf};
use MOSQUITTO_VERSION;
pub fn place_bindings(inc_dir: &Path) {
let inc_search = format!("-I{}", inc_dir.display());
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// Older clang versions (~v3.6) improperly mangle the functions.
// We shouldn't require mangling for straight C library. I think.
.trust_clang_mangling(false)
// The input header we would like to generate
// bindings for.
.header("wrapper.h").clang_arg(inc_search)
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
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!");
// Save a copy of the bindings file into the bindings/ dir
// with version and target name, if it doesn't already exist
let target = env::var("TARGET").unwrap();
println!("debug:Target: {}", target);
let bindings = format!("bindings/bindings_mosquitto_{}-{}.rs",
MOSQUITTO_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 bundled {
use std::process::Command;
use super::*;
use std::path::{PathBuf};
use std::process;
use std::env;
use std::fs;
use std::str;
extern crate anyhow;
extern crate cmake;
use self::anyhow::{Result, Error};
#[cfg(target_os = "linux")]
use self::anyhow::Context;
struct LibInfos {
lib_dir: PathBuf,
lib_name: String,
lib_path: PathBuf,
include_dir: PathBuf,
}
pub fn main() {
println!("Running the bundled build");
if let Err(e) = execute() {
panic!("failed to build bundled library: {:?}", e)
}
}
fn execute() -> Result<()> {
checkout_lib()?;
bundle_lib_and_link()
}
fn get_mosquitto_parent_dir() -> Result<PathBuf> {
Ok(PathBuf::from(env::var("OUT_DIR")?))
}
fn get_mosquitto_dir() -> Result<PathBuf> {
let p = get_mosquitto_parent_dir()?;
Ok(p.join("mosquitto"))
}
#[cfg(target_os = "linux")]
fn build_lib() -> Result<LibInfos> {
let client_lib_dir = get_mosquitto_dir()?.join("lib");
let cross_compiler = env::var("MOSQUITTO_CROSS_COMPILER").unwrap_or("".to_string());
let cc_compiler = env::var("MOSQUITTO_CC").unwrap_or("gcc".to_string());
Command::new("make")
.env("CROSS_COMPILE", cross_compiler)
.env("CC", cc_compiler)
.current_dir(&client_lib_dir).args(&[
"WITH_TLS=no",
"WITH_CJSON=no",
"WITH_SHARED_LIBRARIES=no",
"WITH_STATIC_LIBRARIES=yes",
"all"
])
.status().context("failed to make lib")?;
Ok(LibInfos {
lib_dir: client_lib_dir.clone(),
lib_name: "mosquitto".into(),
lib_path: client_lib_dir.join("libmosquitto.a"),
include_dir: get_mosquitto_dir()?.join("include"),
})
}
#[cfg(target_os = "macos")]
fn build_lib() -> Result<LibInfos> {
let mut cmk_cfg = cmake::Config::new(get_mosquitto_dir()?);
let cmk = cmk_cfg
.define("WITH_BUNDLED_DEPS", "on")
.define("WITH_EC", "off")
.define("WITH_TLS", "off")
.define("WITH_TLS_PSK", "off")
.define("WITH_APPS", "off")
.define("WITH_PLUGINS", "off")
.define("WITH_CJSON", "off")
.define("WITH_LIB_CPP", "off")
.define("WITH_STATIC_LIBRARIES", "on")
.define("WITH_PIC", "off")
.define("WITH_CLIENTS", "on")
.define("WITH_BROKER", "off")
.define("WITH_PLUGINS", "off")
.define("DOCUMENTATION", "off")
.define("CMAKE_VERBOSE_MAKEFILE", "on")
.build();
let lib_dir = if cmk.join("lib").exists() {
cmk.join("lib")
} else {
panic!("Unknown library directory.")
};
Ok(LibInfos {
lib_dir: lib_dir.clone(),
lib_name: "mosquitto_static".into(),
lib_path: lib_dir.join("libmosquitto_static.a"),
include_dir: cmk.join("include"),
})
}
fn bundle_lib_and_link() -> Result<()> {
let lib_info = build_lib()?;
println!("debug:Using mosquitto C library at: {}", lib_info.lib_path.display());
if !lib_info.lib_path.exists() {
println!("Error building mosquitto C library: '{}'", lib_info.lib_path.display());
process::exit(103);
}
// Get bundled bindings or regenerate
bindings::place_bindings(&lib_info.include_dir);
// we add the folder where all the libraries are built to the path search
println!("cargo:rustc-link-search=native={}", lib_info.lib_dir.display());
println!("cargo:rustc-link-lib=static={}", lib_info.lib_name);
Ok(())
}
fn checkout_lib() -> Result<()> {
let git_parent_path = get_mosquitto_parent_dir()?;
let git_path = get_mosquitto_dir()?;
println!("checkout_lib to {} in {}", git_path.to_str().unwrap(), git_parent_path.to_str().unwrap());
if git_path.is_dir() {
fs::remove_dir_all(&git_path)?;
} else if !git_parent_path.is_dir() {
fs::create_dir_all(&git_parent_path)?;
}
if !git_parent_path.is_dir() {
return Err(Error::msg("was not able to create directory"));
}
let args = vec![
"clone".to_string(),
"--depth=1".to_string(),
env::var("MOSQUITTO_GIT_URL").unwrap_or(MOSQUITTO_GIT_URL.to_string()),
git_path.to_str().unwrap().to_string(),
];
if let Err(e) = Command::new("git").current_dir(&git_parent_path).args(&args).status() {
panic!("failed to clone the git repo: {:?}", e);
}
let hash = env::var("MOSQUITTO_GIT_HASH");
if let Ok(hash) = hash.as_ref() {
if let Err(e) = Command::new("git").current_dir(&git_path).args(&["fetch", "--depth", "1", "origin", hash.as_str()]).status() {
panic!("failed to fetch the git hash: {:?}", e);
}
if let Err(e) = Command::new("git").current_dir(&git_path).args(&["checkout", hash.as_str()]).status() {
panic!("failed to checkout the git hash: {:?}", e);
}
}
let output = Command::new("git").current_dir(&git_path).args(&["rev-parse", "HEAD"]).output()?;
let output = str::from_utf8(&output.stdout)?;
if let Ok(hash) = hash.as_ref() {
if output.ne(format!("{}\n", hash).as_str()) {
panic!("was not able to get correct hash: found {}, expected {}", output, hash);
} else {
println!("debug:Hash: {}", output);
Ok(())
}
} else {
println!("debug:Hash: {}", output);
Ok(())
}
}
}
#[cfg(not(feature = "bundled"))]
mod bundled {
pub fn main() {}
}