Permalink
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up| extern crate pkg_config; | |
| #[cfg(target_env = "msvc")] | |
| extern crate vcpkg; | |
| extern crate cc; | |
| use std::env; | |
| use std::fs; | |
| use std::path::{PathBuf, Path}; | |
| use std::process::Command; | |
| fn main() { | |
| let target = env::var("TARGET").unwrap(); | |
| let windows = target.contains("windows"); | |
| // This feature trumps all others, and is largely set by rustbuild to force | |
| // usage of the system library to ensure that we're always building an | |
| // ABI-compatible Cargo. | |
| if cfg!(feature = "force-system-lib-on-osx") && target.contains("apple") { | |
| return println!("cargo:rustc-flags=-l curl"); | |
| } | |
| // If the static-curl feature is disabled, probe for a system-wide libcurl. | |
| if !cfg!(feature = "static-curl") { | |
| // OSX and Haiku ships libcurl by default, so we just use that version | |
| // so long as it has the right features enabled. | |
| if target.contains("apple") || target.contains("haiku") { | |
| if !cfg!(feature = "http2") || curl_config_reports_http2() { | |
| return println!("cargo:rustc-flags=-l curl"); | |
| } | |
| } | |
| // Next, fall back and try to use pkg-config if its available. | |
| if windows { | |
| if try_vcpkg() { | |
| return | |
| } | |
| } else { | |
| if try_pkg_config() { | |
| return | |
| } | |
| } | |
| } | |
| if !Path::new("curl/.git").exists() { | |
| let _ = Command::new("git").args(&["submodule", "update", "--init"]) | |
| .status(); | |
| } | |
| let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); | |
| let include = dst.join("include"); | |
| let build = dst.join("build"); | |
| println!("cargo:root={}", dst.display()); | |
| println!("cargo:include={}", include.display()); | |
| println!("cargo:static=1"); | |
| fs::create_dir_all(include.join("curl")).unwrap(); | |
| fs::copy("curl/include/curl/curl.h", include.join("curl/curl.h")).unwrap(); | |
| fs::copy("curl/include/curl/curlver.h", include.join("curl/curlver.h")).unwrap(); | |
| fs::copy("curl/include/curl/easy.h", include.join("curl/easy.h")).unwrap(); | |
| fs::copy("curl/include/curl/mprintf.h", include.join("curl/mprintf.h")).unwrap(); | |
| fs::copy("curl/include/curl/multi.h", include.join("curl/multi.h")).unwrap(); | |
| fs::copy("curl/include/curl/stdcheaders.h", include.join("curl/stdcheaders.h")).unwrap(); | |
| fs::copy("curl/include/curl/system.h", include.join("curl/system.h")).unwrap(); | |
| fs::copy("curl/include/curl/urlapi.h", include.join("curl/urlapi.h")).unwrap(); | |
| fs::copy("curl/include/curl/typecheck-gcc.h", include.join("curl/typecheck-gcc.h")).unwrap(); | |
| let pkgconfig = dst.join("lib/pkgconfig"); | |
| fs::create_dir_all(&pkgconfig).unwrap(); | |
| let contents = fs::read_to_string("curl/libcurl.pc.in").unwrap(); | |
| fs::write( | |
| pkgconfig.join("libcurl.pc"), | |
| contents | |
| .replace("@prefix@", dst.to_str().unwrap()) | |
| .replace("@exec_prefix@", "") | |
| .replace("@libdir@", dst.join("lib").to_str().unwrap()) | |
| .replace("@includedir@", include.to_str().unwrap()) | |
| .replace("@CPPFLAG_CURL_STATICLIB@", "-DCURL_STATICLIB") | |
| .replace("@LIBCURL_LIBS@", "") | |
| .replace("@SUPPORT_FEATURES@", "") | |
| .replace("@SUPPORT_PROTOCOLS@", "") | |
| .replace("@CURLVERSION@", "7.61.1"), | |
| ).unwrap(); | |
| let mut cfg = cc::Build::new(); | |
| cfg.out_dir(&build) | |
| .include("curl/lib") | |
| .include("curl/include") | |
| .define("BUILDING_LIBCURL", None) | |
| .define("CURL_DISABLE_CRYPTO_AUTH", None) | |
| .define("CURL_DISABLE_DICT", None) | |
| .define("CURL_DISABLE_FTP", None) | |
| .define("CURL_DISABLE_GOPHER", None) | |
| .define("CURL_DISABLE_IMAP", None) | |
| .define("CURL_DISABLE_LDAP", None) | |
| .define("CURL_DISABLE_LDAPS", None) | |
| .define("CURL_DISABLE_NTLM", None) | |
| .define("CURL_DISABLE_POP3", None) | |
| .define("CURL_DISABLE_RTSP", None) | |
| .define("CURL_DISABLE_SMB", None) | |
| .define("CURL_DISABLE_SMTP", None) | |
| .define("CURL_DISABLE_TELNET", None) | |
| .define("CURL_DISABLE_TFTP", None) | |
| .define("CURL_STATICLIB", None) | |
| .define("ENABLE_IPV6", None) | |
| .define("HAVE_ASSERT_H", None) | |
| .define("OS", "\"unknown\"") // TODO | |
| .define("HAVE_ZLIB_H", None) | |
| .define("HAVE_LIBZ", None) | |
| .file("curl/lib/asyn-thread.c") | |
| .file("curl/lib/base64.c") | |
| .file("curl/lib/conncache.c") | |
| .file("curl/lib/connect.c") | |
| .file("curl/lib/content_encoding.c") | |
| .file("curl/lib/cookie.c") | |
| .file("curl/lib/curl_addrinfo.c") | |
| .file("curl/lib/curl_ctype.c") | |
| .file("curl/lib/curl_memrchr.c") | |
| .file("curl/lib/curl_range.c") | |
| .file("curl/lib/curl_threads.c") | |
| .file("curl/lib/dotdot.c") | |
| .file("curl/lib/doh.c") | |
| .file("curl/lib/easy.c") | |
| .file("curl/lib/escape.c") | |
| .file("curl/lib/file.c") | |
| .file("curl/lib/fileinfo.c") | |
| .file("curl/lib/formdata.c") | |
| .file("curl/lib/getenv.c") | |
| .file("curl/lib/getinfo.c") | |
| .file("curl/lib/hash.c") | |
| .file("curl/lib/hostasyn.c") | |
| .file("curl/lib/hostcheck.c") | |
| .file("curl/lib/hostip.c") | |
| .file("curl/lib/hostip6.c") | |
| .file("curl/lib/http.c") | |
| .file("curl/lib/http2.c") | |
| .file("curl/lib/http_chunks.c") | |
| .file("curl/lib/http_proxy.c") | |
| .file("curl/lib/if2ip.c") | |
| .file("curl/lib/inet_ntop.c") | |
| .file("curl/lib/inet_pton.c") | |
| .file("curl/lib/llist.c") | |
| .file("curl/lib/mime.c") | |
| .file("curl/lib/mprintf.c") | |
| .file("curl/lib/multi.c") | |
| .file("curl/lib/netrc.c") | |
| .file("curl/lib/nonblock.c") | |
| .file("curl/lib/parsedate.c") | |
| .file("curl/lib/pipeline.c") | |
| .file("curl/lib/progress.c") | |
| .file("curl/lib/rand.c") | |
| .file("curl/lib/select.c") | |
| .file("curl/lib/sendf.c") | |
| .file("curl/lib/setopt.c") | |
| .file("curl/lib/share.c") | |
| .file("curl/lib/slist.c") | |
| .file("curl/lib/socks.c") | |
| .file("curl/lib/speedcheck.c") | |
| .file("curl/lib/splay.c") | |
| .file("curl/lib/strcase.c") | |
| .file("curl/lib/strdup.c") | |
| .file("curl/lib/strerror.c") | |
| .file("curl/lib/strtok.c") | |
| .file("curl/lib/strtoofft.c") | |
| .file("curl/lib/timeval.c") | |
| .file("curl/lib/transfer.c") | |
| .file("curl/lib/url.c") | |
| .file("curl/lib/urlapi.c") | |
| .file("curl/lib/version.c") | |
| .file("curl/lib/vtls/vtls.c") | |
| .file("curl/lib/warnless.c") | |
| .file("curl/lib/wildcard.c") | |
| .define("HAVE_GETADDRINFO", None) | |
| .warnings(false); | |
| if cfg!(feature = "http2") { | |
| cfg.define("USE_NGHTTP2", None) | |
| .define("NGHTTP2_STATICLIB", None); | |
| if let Some(path) = env::var_os("DEP_NGHTTP2_ROOT") { | |
| let path = PathBuf::from(path); | |
| cfg.include(path.join("include")); | |
| } | |
| } | |
| if let Some(path) = env::var_os("DEP_Z_INCLUDE") { | |
| cfg.include(path); | |
| } | |
| if cfg!(feature = "spnego") { | |
| cfg.define("USE_SPNEGO", None) | |
| .file("curl/lib/http_negotiate.c") | |
| .file("curl/lib/vauth/vauth.c"); | |
| } | |
| if windows { | |
| cfg.define("USE_THREADS_WIN32", None) | |
| .define("HAVE_IOCTLSOCKET_FIONBIO", None) | |
| .define("USE_WINSOCK", None) | |
| .file("curl/lib/system_win32.c"); | |
| if cfg!(feature = "ssl") { | |
| cfg.define("USE_WINDOWS_SSPI", None) | |
| .define("USE_SCHANNEL", None) | |
| .file("curl/lib/x509asn1.c") | |
| .file("curl/lib/curl_sspi.c") | |
| .file("curl/lib/socks_sspi.c") | |
| .file("curl/lib/vtls/schannel.c") | |
| .file("curl/lib/vtls/schannel_verify.c"); | |
| } | |
| if cfg!(feature = "spnego") { | |
| cfg.file("curl/lib/vauth/spnego_sspi.c"); | |
| } | |
| } else { | |
| cfg.define("RECV_TYPE_ARG1", "int") | |
| .define("HAVE_PTHREAD_H", None) | |
| .define("HAVE_ARPA_INET_H", None) | |
| .define("HAVE_ERRNO_H", None) | |
| .define("HAVE_FCNTL_H", None) | |
| .define("HAVE_NETDB_H", None) | |
| .define("HAVE_NETINET_IN_H", None) | |
| .define("HAVE_POLL_FINE", None) | |
| .define("HAVE_POLL_H", None) | |
| .define("HAVE_FCNTL_O_NONBLOCK", None) | |
| .define("HAVE_SYS_SELECT_H", None) | |
| .define("HAVE_SYS_STAT_H", None) | |
| .define("HAVE_UNISTD_H", None) | |
| .define("HAVE_RECV", None) | |
| .define("HAVE_SELECT", None) | |
| .define("HAVE_SEND", None) | |
| .define("HAVE_SOCKET", None) | |
| .define("HAVE_STERRROR_R", None) | |
| .define("HAVE_STRUCT_TIMEVAL", None) | |
| .define("USE_THREADS_POSIX", None) | |
| .define("RECV_TYPE_ARG2", "void*") | |
| .define("RECV_TYPE_ARG3", "size_t") | |
| .define("RECV_TYPE_ARG4", "int") | |
| .define("RECV_TYPE_RETV", "ssize_t") | |
| .define("SEND_QUAL_ARG2", "const") | |
| .define("SEND_TYPE_ARG1", "int") | |
| .define("SEND_TYPE_ARG2", "void*") | |
| .define("SEND_TYPE_ARG3", "size_t") | |
| .define("SEND_TYPE_ARG4", "int") | |
| .define("SEND_TYPE_RETV", "ssize_t") | |
| .define("SIZEOF_CURL_OFF_T", "8") | |
| .define("SIZEOF_INT", "4") | |
| .define("SIZEOF_SHORT", "2"); | |
| if cfg!(feature = "ssl") { | |
| if target.contains("-apple-") { | |
| cfg.define("USE_DARWINSSL", None) | |
| .file("curl/lib/vtls/darwinssl.c"); | |
| if xcode_major_version().map_or(true, |v| v >= 9) { | |
| // On earlier Xcode versions (<9), defining HAVE_BUILTIN_AVAILABLE | |
| // would cause __bultin_available() to fail to compile due to | |
| // unrecognized platform names, so we try to check for Xcode | |
| // version first (if unknown, assume it's recent, as in >= 9). | |
| cfg.define("HAVE_BUILTIN_AVAILABLE", "1"); | |
| } | |
| } else { | |
| cfg.define("USE_OPENSSL", None) | |
| .file("curl/lib/vtls/openssl.c"); | |
| if let Some(path) = env::var_os("DEP_OPENSSL_INCLUDE") { | |
| cfg.include(path); | |
| } | |
| } | |
| } | |
| if cfg!(feature = "spnego") { | |
| cfg.define("HAVE_GSSAPI", None) | |
| .file("curl/lib/curl_gssapi.c") | |
| .file("curl/lib/socks_gssapi.c") | |
| .file("curl/lib/vauth/spnego_gssapi.c"); | |
| // Link against the MIT gssapi library. It might be desirable to add support for | |
| // choosing between MIT and Heimdal libraries in the future. | |
| println!("cargo:rustc-link-lib=gssapi_krb5"); | |
| } | |
| let width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") | |
| .unwrap() | |
| .parse::<usize>() | |
| .unwrap(); | |
| cfg.define("SIZEOF_SSIZE_T", Some(&(width / 8).to_string()[..])); | |
| cfg.define("SIZEOF_SIZE_T", Some(&(width / 8).to_string()[..])); | |
| cfg.define("SIZEOF_LONG", Some(&(width / 8).to_string()[..])); | |
| cfg.flag("-fvisibility=hidden"); | |
| } | |
| cfg.compile("curl"); | |
| if windows { | |
| println!("cargo:rustc-link-lib=ws2_32"); | |
| println!("cargo:rustc-link-lib=crypt32"); | |
| } | |
| // Illumos/Solaris requires explicit linking with libnsl | |
| if target.contains("solaris") { | |
| println!("cargo:rustc-link-lib=nsl"); | |
| } | |
| if target.contains("-apple-") { | |
| println!("cargo:rustc-link-lib=framework=Security"); | |
| println!("cargo:rustc-link-lib=framework=CoreFoundation"); | |
| } | |
| } | |
| #[cfg(not(target_env = "msvc"))] | |
| fn try_vcpkg() -> bool { | |
| false | |
| } | |
| #[cfg(target_env = "msvc")] | |
| fn try_vcpkg() -> bool { | |
| // the import library for the dll is called libcurl_imp | |
| let mut successful_probe_details = | |
| match vcpkg::Config::new().lib_names("libcurl_imp", "libcurl") | |
| .emit_includes(true).probe("curl") { | |
| Ok(details) => Some(details), | |
| Err(e) => { | |
| println!("first run of vcpkg did not find libcurl: {}", e); | |
| None | |
| } | |
| }; | |
| if successful_probe_details.is_none() { | |
| match vcpkg::Config::new().lib_name("libcurl") | |
| .emit_includes(true).probe("curl") { | |
| Ok(details) => successful_probe_details = Some(details), | |
| Err(e) => println!("second run of vcpkg did not find libcurl: {}", e), | |
| } | |
| } | |
| if successful_probe_details.is_some() { | |
| // Found libcurl which depends on openssl, libssh2 and zlib | |
| // in the a default vcpkg installation. Probe for them | |
| // but do not fail if they are not present as we may be working | |
| // with a customized vcpkg installation. | |
| vcpkg::Config::new() | |
| .lib_name("libeay32") | |
| .lib_name("ssleay32") | |
| .probe("openssl").ok(); | |
| vcpkg::probe_package("libssh2").ok(); | |
| vcpkg::Config::new() | |
| .lib_names("zlib", "zlib1") | |
| .probe("zlib").ok(); | |
| println!("cargo:rustc-link-lib=crypt32"); | |
| println!("cargo:rustc-link-lib=gdi32"); | |
| println!("cargo:rustc-link-lib=user32"); | |
| println!("cargo:rustc-link-lib=wldap32"); | |
| return true; | |
| } | |
| false | |
| } | |
| fn try_pkg_config() -> bool { | |
| let mut cfg = pkg_config::Config::new(); | |
| cfg.cargo_metadata(false); | |
| let lib = match cfg.probe("libcurl") { | |
| Ok(lib) => lib, | |
| Err(e) => { | |
| println!("Couldn't find libcurl from pkgconfig ({:?}), \ | |
| compiling it from source...", e); | |
| return false | |
| } | |
| }; | |
| // Not all system builds of libcurl have http2 features enabled, so if we've | |
| // got a http2-requested build then we may fall back to a build from source. | |
| if cfg!(feature = "http2") && !curl_config_reports_http2() { | |
| return false | |
| } | |
| // Re-find the library to print cargo's metadata, then print some extra | |
| // metadata as well. | |
| cfg.cargo_metadata(true) | |
| .probe("libcurl") | |
| .unwrap(); | |
| for path in lib.include_paths.iter() { | |
| println!("cargo:include={}", path.display()); | |
| } | |
| return true | |
| } | |
| fn xcode_major_version() -> Option<u8> { | |
| let output = Command::new("xcodebuild") | |
| .arg("-version") | |
| .output() | |
| .ok()?; | |
| if output.status.success() { | |
| let stdout = String::from_utf8_lossy(&output.stdout); | |
| let mut words = stdout.split_whitespace(); | |
| if words.next()? == "Xcode" { | |
| let version = words.next()?; | |
| return version[..version.find('.')?].parse().ok() | |
| } | |
| } | |
| println!("unable to determine Xcode version, assuming >= 9"); | |
| None | |
| } | |
| fn curl_config_reports_http2() -> bool { | |
| let output = Command::new("curl-config") | |
| .arg("--features") | |
| .output(); | |
| let output = match output { | |
| Ok(out) => out, | |
| Err(e) => { | |
| println!("failed to run curl-config ({}), building from source", e); | |
| return false | |
| } | |
| }; | |
| if !output.status.success() { | |
| println!("curl-config failed: {}", output.status); | |
| return false | |
| } | |
| let stdout = String::from_utf8_lossy(&output.stdout); | |
| if !stdout.contains("HTTP2") { | |
| println!("failed to find http-2 feature enabled in pkg-config-found \ | |
| libcurl, building from source"); | |
| return false | |
| } | |
| return true | |
| } |