Skip to content

Commit

Permalink
build.rs: add a mode to go for "semi-static" compilation
Browse files Browse the repository at this point in the history
By "semi-static" I mean that the final binary is not statically linked, but
that it only dynamically links with core system libraries. Higher-level like
harfbuzz are linked into the executable statically. This is accomplished by an
environment variable TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC=1, since I
discovered that the pkg-config-rs library's logic for encouraging static
linking will turn it off in the common case that our static libraries live in
standard system prefixes.

Unfortunately, graphite2 seems to have issues with its various static builds
(e.g. silnrsi/graphite#54) so we won't always get a
super-minimal list of dependencies, but this seems to get us most of the way
there, and I've coded it so that we should start doing better if/when
graphite2 is fixed.
  • Loading branch information
pkgw committed Dec 23, 2019
1 parent 89ad89c commit ab731b8
Showing 1 changed file with 58 additions and 5 deletions.
63 changes: 58 additions & 5 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,15 @@ enum DepState {
impl DepState {
/// Probe for our dependent libraries using pkg-config.
fn new_pkg_config() -> Self {
let statik = if let Ok(_) = env::var("TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC") {
true
} else {
false
};

let libs = pkg_config::Config::new()
.cargo_metadata(false)
.statik(statik)
.probe(PKGCONFIG_LIBS)
.unwrap();
DepState::PkgConfig(PkgConfigState { libs })
Expand Down Expand Up @@ -110,11 +117,56 @@ impl DepState {
/// backend or the target.
fn emit_late_extras(&self, target: &str) {
match self {
&DepState::PkgConfig(_) => {
pkg_config::Config::new()
.cargo_metadata(true)
.probe(PKGCONFIG_LIBS)
.unwrap();
&DepState::PkgConfig(ref state) => {
if let Ok(_) = env::var("TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC") {
// pkg-config will prevent "system libraries" from being
// linked statically even when PKG_CONFIG_ALL_STATIC=1,
// but its definition of a system library isn't always
// perfect. For Debian cross builds, we'd like to make
// binaries that are dynamically linked with things like
// libc and libm but not libharfbuzz, etc. In this mode we
// override pkg-config's logic by emitting the metadata
// ourselves.
for link_path in &state.libs.link_paths {
println!("cargo:rustc-link-search=native={}", link_path.display());
}

for fw_path in &state.libs.framework_paths {
println!("cargo:rustc-link-search=framework={}", fw_path.display());
}

for libbase in &state.libs.libs {
let do_static = match libbase.as_ref() {
"c" | "m" | "dl" | "pthread" => false,
_ => {
// Frustratingly, graphite2 seems to have
// issues with static builds; e.g. static
// graphite2 is not available on Debian. So
// let's jump through the hoops of testing
// whether the static archive seems findable.
let libname = format!("lib{}.a", libbase);
state
.libs
.link_paths
.iter()
.any(|d| d.join(&libname).exists())
}
};

let mode = if do_static { "static=" } else { "" };
println!("cargo:rustc-link-lib={}{}", mode, libbase);
}

for fw in &state.libs.frameworks {
println!("cargo:rustc-link-lib=framework={}", fw);
}
} else {
// Just let pkg-config do its thing.
pkg_config::Config::new()
.cargo_metadata(true)
.probe(PKGCONFIG_LIBS)
.unwrap();
}
}

&DepState::VcPkg(_) => {
Expand Down Expand Up @@ -149,6 +201,7 @@ fn main() {
// OK, how are we finding our dependencies?

println!("cargo:rerun-if-env-changed=TECTONIC_DEP_BACKEND");
println!("cargo:rerun-if-env-changed=TECTONIC_PKGCONFIG_FORCE_SEMI_STATIC");

let dep_state = if let Ok(dep_backend_str) = env::var("TECTONIC_DEP_BACKEND") {
match dep_backend_str.as_ref() {
Expand Down

0 comments on commit ab731b8

Please sign in to comment.