blob: fb4c47e65a427b5980fd70bfabbadcb73eb6b365 [file] [log] [blame]
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +02001extern crate cc;
2extern crate pkg_config;
3#[cfg(target_env = "msvc")]
4extern crate vcpkg;
5
6use std::env;
7use std::fs;
8use std::path::PathBuf;
9use std::process::Command;
10
11fn main() {
12 println!("cargo:rerun-if-env-changed=LIBZ_SYS_STATIC");
13 println!("cargo:rerun-if-changed=build.rs");
14 let host = env::var("HOST").unwrap();
15 let target = env::var("TARGET").unwrap();
16
17 let host_and_target_contain = |s| host.contains(s) && target.contains(s);
18
19 let want_ng = cfg!(feature = "zlib-ng") && !cfg!(feature = "stock-zlib");
20
21 if want_ng && target != "wasm32-unknown-unknown" {
22 return build_zlib_ng(&target);
23 }
24
25 // Don't run pkg-config if we're linking statically (we'll build below) and
26 // also don't run pkg-config on macOS/FreeBSD/DragonFly. That'll end up printing
27 // `-L /usr/lib` which wreaks havoc with linking to an OpenSSL in /usr/local/lib
28 // (Homebrew, Ports, etc.)
29 let want_static =
30 cfg!(feature = "static") || env::var("LIBZ_SYS_STATIC").unwrap_or(String::new()) == "1";
31 if !want_static &&
32 !target.contains("msvc") && // pkg-config just never works here
33 !(host_and_target_contain("apple") ||
34 host_and_target_contain("freebsd") ||
35 host_and_target_contain("dragonfly"))
36 {
37 // Don't print system lib dirs to cargo since this interferes with other
38 // packages adding non-system search paths to link against libraries
39 // that are also found in a system-wide lib dir.
40 let zlib = pkg_config::Config::new()
41 .cargo_metadata(true)
42 .print_system_libs(false)
43 .probe("zlib");
44 if zlib.is_ok() {
45 return;
46 }
47 }
48
49 if target.contains("msvc") {
50 if try_vcpkg() {
51 return;
52 }
53 }
54
55 // All android compilers should come with libz by default, so let's just use
Joel Galenson78439eb2021-06-01 13:23:38 -070056 // the one already there. Likewise, Haiku always ships with libz, so we can
57 // link to it even when cross-compiling.
58 if target.contains("android") || target.contains("haiku") {
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +020059 println!("cargo:rustc-link-lib=z");
60 return;
61 }
62
63 let mut cfg = cc::Build::new();
64
65 // Situations where we build unconditionally.
66 //
67 // MSVC basically never has it preinstalled, MinGW picks up a bunch of weird
68 // paths we don't like, `want_static` may force us, cross compiling almost
69 // never has a prebuilt version, and musl is almost always static.
70 if target.contains("msvc")
71 || target.contains("pc-windows-gnu")
72 || want_static
73 || target != host
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +020074 {
75 return build_zlib(&mut cfg, &target);
76 }
77
78 // If we've gotten this far we're probably a pretty standard platform.
79 // Almost all platforms here ship libz by default, but some don't have
80 // pkg-config files that we would find above.
81 //
82 // In any case test if zlib is actually installed and if so we link to it,
83 // otherwise continue below to build things.
84 if zlib_installed(&mut cfg) {
85 println!("cargo:rustc-link-lib=z");
86 return;
87 }
88
89 build_zlib(&mut cfg, &target)
90}
91
92fn build_zlib(cfg: &mut cc::Build, target: &str) {
93 let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
Joel Galenson78439eb2021-06-01 13:23:38 -070094 let lib = dst.join("lib");
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +020095
Joel Galenson78439eb2021-06-01 13:23:38 -070096 cfg.warnings(false).out_dir(&lib).include("src/zlib");
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +020097
98 cfg.file("src/zlib/adler32.c")
99 .file("src/zlib/compress.c")
100 .file("src/zlib/crc32.c")
101 .file("src/zlib/deflate.c")
102 .file("src/zlib/infback.c")
103 .file("src/zlib/inffast.c")
104 .file("src/zlib/inflate.c")
105 .file("src/zlib/inftrees.c")
106 .file("src/zlib/trees.c")
107 .file("src/zlib/uncompr.c")
108 .file("src/zlib/zutil.c");
109
Joel Galenson78439eb2021-06-01 13:23:38 -0700110 if !cfg!(feature = "libc") || target.starts_with("wasm32") {
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +0200111 cfg.define("Z_SOLO", None);
112 } else {
113 cfg.file("src/zlib/gzclose.c")
114 .file("src/zlib/gzlib.c")
115 .file("src/zlib/gzread.c")
116 .file("src/zlib/gzwrite.c");
117 }
118
119 if !target.contains("windows") {
120 cfg.define("STDC", None);
121 cfg.define("_LARGEFILE64_SOURCE", None);
122 cfg.define("_POSIX_SOURCE", None);
123 cfg.flag("-fvisibility=hidden");
124 }
125 if target.contains("apple") {
126 cfg.define("_C99_SOURCE", None);
127 }
128 if target.contains("solaris") {
129 cfg.define("_XOPEN_SOURCE", "700");
130 }
131
132 cfg.compile("z");
133
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +0200134 fs::create_dir_all(dst.join("include")).unwrap();
135 fs::copy("src/zlib/zlib.h", dst.join("include/zlib.h")).unwrap();
136 fs::copy("src/zlib/zconf.h", dst.join("include/zconf.h")).unwrap();
137
Joel Galenson78439eb2021-06-01 13:23:38 -0700138 fs::create_dir_all(lib.join("pkgconfig")).unwrap();
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +0200139 fs::write(
Joel Galenson78439eb2021-06-01 13:23:38 -0700140 lib.join("pkgconfig/zlib.pc"),
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +0200141 fs::read_to_string("src/zlib/zlib.pc.in")
142 .unwrap()
143 .replace("@prefix@", dst.to_str().unwrap()),
144 )
145 .unwrap();
146
147 println!("cargo:root={}", dst.to_str().unwrap());
Joel Galenson78439eb2021-06-01 13:23:38 -0700148 println!("cargo:rustc-link-search=native={}", lib.to_str().unwrap());
Jeff Vander Stoep6e2b0a62020-10-14 16:02:39 +0200149 println!("cargo:include={}/include", dst.to_str().unwrap());
150}
151
152#[cfg(not(feature = "zlib-ng"))]
153fn build_zlib_ng(_target: &str) {}
154
155#[cfg(feature = "zlib-ng")]
156fn build_zlib_ng(target: &str) {
157 let install_dir = cmake::Config::new("src/zlib-ng")
158 .define("BUILD_SHARED_LIBS", "OFF")
159 .define("ZLIB_COMPAT", "ON")
160 .define("WITH_GZFILEOP", "ON")
161 .build();
162 let includedir = install_dir.join("include");
163 let libdir = install_dir.join("lib");
164 println!(
165 "cargo:rustc-link-search=native={}",
166 libdir.to_str().unwrap()
167 );
168 let libname = if target.contains("windows") {
169 if target.contains("msvc") && env::var("OPT_LEVEL").unwrap() == "0" {
170 "zlibd"
171 } else {
172 "zlib"
173 }
174 } else {
175 "z"
176 };
177 println!("cargo:rustc-link-lib=static={}", libname);
178 println!("cargo:root={}", install_dir.to_str().unwrap());
179 println!("cargo:include={}", includedir.to_str().unwrap());
180}
181
182#[cfg(not(target_env = "msvc"))]
183fn try_vcpkg() -> bool {
184 false
185}
186
187#[cfg(target_env = "msvc")]
188fn try_vcpkg() -> bool {
189 // see if there is a vcpkg tree with zlib installed
190 match vcpkg::Config::new()
191 .emit_includes(true)
192 .lib_names("zlib", "zlib1")
193 .probe("zlib")
194 {
195 Ok(_) => true,
196 Err(e) => {
197 println!("note, vcpkg did not find zlib: {}", e);
198 false
199 }
200 }
201}
202
203fn zlib_installed(cfg: &mut cc::Build) -> bool {
204 let compiler = cfg.get_compiler();
205 let mut cmd = Command::new(compiler.path());
206 cmd.arg("src/smoke.c").arg("-o").arg("/dev/null").arg("-lz");
207
208 println!("running {:?}", cmd);
209 if let Ok(status) = cmd.status() {
210 if status.success() {
211 return true;
212 }
213 }
214
215 false
216}