-
Notifications
You must be signed in to change notification settings - Fork 9
/
build.rs
244 lines (217 loc) · 8.5 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
241
242
243
244
// Copyright Materialize, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file at the
// root of this repository, or online at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::env;
#[cfg(unix)]
use std::ffi::OsString;
use std::fs;
use std::io::{stderr, Write};
#[cfg(unix)]
use std::path::Path;
use std::path::PathBuf;
use std::str;
use duct::cmd;
struct Metadata {
host: String,
target: String,
build_dir: PathBuf,
install_dir: PathBuf,
}
impl Metadata {
fn is_cross_compiling(&self) -> bool {
self.host != self.target
}
fn get_target_env(&self, name: &str) -> Option<String> {
if self.is_cross_compiling() {
env::var(format!("{}_{}", name, self.target.replace("-", "_"))).ok()
} else {
env::var(name).ok()
}
}
}
trait DuctExpressionExt: Sized {
fn set_target_env_vars(self, metadata: &Metadata) -> Self;
}
impl DuctExpressionExt for duct::Expression {
fn set_target_env_vars(mut self, metadata: &Metadata) -> Self {
if let Some(target_cc) = metadata.get_target_env("CC") {
self = self.env("CC", target_cc)
}
if let Some(target_ar) = metadata.get_target_env("AR") {
self = self.env("AR", target_ar)
}
self
}
}
fn main() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let metadata = Metadata {
host: env::var("HOST").unwrap(),
target: env::var("TARGET").unwrap(),
build_dir: out_dir.join("build"),
install_dir: out_dir.join("install"),
};
fs::create_dir_all(&metadata.build_dir).expect("failed to create build dir");
fs::create_dir_all(&metadata.install_dir).expect("failed to create install dir");
build(&metadata);
println!("cargo:root={}", metadata.install_dir.display());
}
#[cfg(unix)]
fn build(metadata: &Metadata) {
// Configure.
{
let mut cppflags = env::var("CPPFLAGS").ok().unwrap_or_else(String::new);
let mut cflags = env::var("CFLAGS").ok().unwrap_or_else(String::new);
// Some platforms require that we explicitly request
// position-independent code in our static libraries.
cflags += " -fPIC";
// If OpenSSL has been vendored, point libkrb5 at the vendored headers.
if let Ok(openssl_root) = env::var("DEP_OPENSSL_ROOT") {
cppflags += &format!(" -I{}", Path::new(&openssl_root).join("include").display());
}
let mut configure_args = vec![
format!("--prefix={}", metadata.install_dir.display()),
"--enable-static".into(),
"--disable-shared".into(),
#[cfg(feature = "nls")]
"--enable-nls".into(),
#[cfg(not(feature = "nls"))]
"--disable-nls".into(),
format!("CPPFLAGS={}", cppflags),
format!("CFLAGS={}", cflags),
];
// If we're cross-compiling, let configure know.
if metadata.is_cross_compiling() {
configure_args.push(format!("--build={}", metadata.host));
// `--host` is the target platform in autotools parlance, not the
// host platform.
configure_args.push(format!("--host={}", metadata.target));
}
let configure_path = Path::new("krb5").join("src").join("configure");
let configure = cmd(configure_path, &configure_args)
.dir(&metadata.build_dir)
.set_target_env_vars(metadata)
.env_remove("CONFIG_SITE");
let configure_output = configure.stderr_capture().unchecked().run().unwrap();
let _ = stderr().write_all(&configure_output.stderr);
if !configure_output.status.success() && metadata.is_cross_compiling() {
if let Ok(s) = str::from_utf8(&configure_output.stderr) {
let last_error = s.trim_end();
if last_error.ends_with(
"Cannot test for constructor/destructor support when cross compiling",
) {
eprintln!("set krb5_cv_attr_constructor_destructor={{yes|no}} in the environment to skip this test");
}
if last_error.ends_with("Cannot test regcomp when cross compiling") {
eprintln!(
"set ac_cv_func_regcomp={{yes|no}} in the environment to skip this test"
);
}
if last_error.ends_with(
"Cannot test for printf positional argument support when cross compiling",
) {
eprintln!("set ac_cv_printf_positional={{yes|no}} in the environment to skip this test");
}
}
panic!("configure failed");
}
}
// Make.
{
let mut make_flags = OsString::new();
let mut make_args = vec![];
if let Ok(s) = env::var("NUM_JOBS") {
match env::var_os("CARGO_MAKEFLAGS") {
// Only do this on non-windows and non-bsd
// On Windows, we could be invoking make instead of
// mingw32-make which doesn't work with our jobserver
// bsdmake also does not work with our job server
Some(ref s)
if !(cfg!(windows)
|| cfg!(target_os = "openbsd")
|| cfg!(target_os = "netbsd")
|| cfg!(target_os = "freebsd")
|| cfg!(target_os = "bitrig")
|| cfg!(target_os = "dragonflybsd")) =>
{
make_flags = s.clone()
}
// This looks like `make`, let's hope it understands `-jN`.
_ => make_args.push(format!("-j{}", s)),
}
}
// Hack our way through building just the libraries, and not any of the
// utility programs. This avoids a dependency on Yacc.
cmd!("make", "install-mkdirs")
.dir(&metadata.build_dir)
.set_target_env_vars(metadata)
.run()
.expect("install-mkdirs failed");
for dir in &[
"util/support",
"util/et",
"util/profile",
"util/verto",
"include",
"lib",
#[cfg(feature = "binaries")]
"plugins/kdb/db2",
#[cfg(feature = "binaries")]
"clients",
] {
for target in &["all", "install"] {
cmd!("make", target)
.dir(metadata.build_dir.join(dir))
.set_target_env_vars(metadata)
.env("MAKEFLAGS", &make_flags)
.run()
.unwrap_or_else(|_| panic!("make failed in {}", dir));
}
}
}
}
#[cfg(windows)]
fn build(metadata: &Metadata) {
if metadata.host != metadata.target {
panic!("cross-compilation on a Windows host is not supported");
}
// The Windows build system doesn't seem to support out-of-tree builds, so
// copy the source tree into the build directory since we're not allowed to
// build in the checkout directly.
let output = cmd!("robocopy", "krb5\\src", &metadata.build_dir, "/s", "/e")
.unchecked()
.run()
.unwrap_or_else(|e| panic!("copying source tree failed: {}", e));
// https://docs.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/return-codes-used-robocopy-utility
if !matches!(output.status.code(), Some(0..=7)) {
panic!("copying source tree failed: {:?}", output);
}
let nmake = |args: &[&str]| {
cmd("nmake", args)
.dir(&metadata.build_dir)
.env("KRB_INSTALL_DIR", &metadata.install_dir)
};
// Prepare Windows Makefile.
nmake(&["-f", "Makefile.in", "prep-windows"])
.run()
.unwrap_or_else(|e| panic!("nmake prep failed: {}", e));
// Build.
nmake(&[])
.run()
.unwrap_or_else(|e| panic!("nmake build failed: {}", e));
// Install.
nmake(&["install"])
.run()
.unwrap_or_else(|e| panic!("nmake install failed: {}", e));
}