Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ jobs:
- name: Install dependencies
run: |
sudo apt update
sudo apt install libkrb5-dev
sudo apt install libkrb5-dev libc-ares-dev
- name: Build documentation
run: cargo doc --no-deps --all-features
- name: Publish documentation
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ static-ssl = ["curl-sys/static-ssl"]
windows-static-ssl = ["static-curl", "curl-sys/windows-static-ssl"]
force-system-lib-on-osx = ['curl-sys/force-system-lib-on-osx']
protocol-ftp = ["curl-sys/protocol-ftp"]
c-ares = ["curl-sys/c-ares"]
zlib-ng-compat = ["curl-sys/zlib-ng-compat", "static-curl"]
upkeep_7_62_0 = ["curl-sys/upkeep_7_62_0"]
poll_7_68_0 = ["curl-sys/poll_7_68_0"]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ with various Cargo features:
- `static-curl`: Use a bundled libcurl version and statically link to it. Disabled by default.
- `apple-sectrust`: Use Apple SecTrust for certificate verification with bundled libcurl and OpenSSL on Apple platforms. Implies `ssl` and `static-curl`. Disabled by default.
- `static-ssl`: Use a bundled OpenSSL version and statically link to it. Only applies on platforms that use OpenSSL. Disabled by default.
- `c-ares`: Enable c-ares DNS support. This enables c-ares checks for both system and vendored builds. With `static-curl`, vendored libcurl is built with c-ares (requires c-ares development files discoverable by `pkg-config` or `vcpkg` on MSVC Windows). Without `static-curl`, a system libcurl with c-ares support is required. Disabled by default.
- `spnego`: Enable SPNEGO support. Disabled by default.
- `upkeep_7_62_0`: Enable curl_easy_upkeep() support, introduced in curl 7.62.0. Disabled by default.
- `poll_7_68_0`: Enable curl_multi_poll()/curl_multi_wakeup() support, requires curl 7.68.0 or later. Disabled by default.
Expand Down
1 change: 1 addition & 0 deletions curl-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ static-ssl = ["openssl-sys/vendored"]
spnego = []
force-system-lib-on-osx = []
protocol-ftp = []
c-ares = []
zlib-ng-compat = ["libz-sys/zlib-ng", "static-curl"]
upkeep_7_62_0 = []
poll_7_68_0 = []
Expand Down
152 changes: 140 additions & 12 deletions curl-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ fn main() {
);
let target = env::var("TARGET").unwrap();
let windows = target.contains("windows");
let needs_http2 = cfg!(feature = "http2");
let needs_cares = cfg!(feature = "c-ares");

if cfg!(feature = "mesalink") {
println!("cargo:warning=MesaLink support has been removed as of curl 7.82.0, will use default TLS backend instead.");
Expand All @@ -61,18 +63,28 @@ fn main() {
if !cfg!(feature = "static-curl") {
// OSX ships libcurl by default, so we just use that version
// so long as it has the right features enabled.
if target.contains("apple") && (!cfg!(feature = "http2") || curl_config_reports_http2()) {
if target.contains("apple")
&& (!needs_http2 || curl_config_reports_http2())
&& (!needs_cares || curl_config_reports_cares())
{
return println!("cargo:rustc-flags=-l curl");
}

// Next, fall back and try to use pkg-config if its available.
if windows {
if try_vcpkg() {
if try_vcpkg(needs_http2, needs_cares) {
return;
}
} else if try_pkg_config() {
} else if try_pkg_config(needs_http2, needs_cares) {
return;
}

if needs_cares {
panic!(
"feature `c-ares` without `static-curl` requires a system \
libcurl with c-ares support (or enable `static-curl`)"
);
}
}

if !Path::new("curl/.git").exists() {
Expand Down Expand Up @@ -161,7 +173,6 @@ fn main() {
.define("HAVE_BOOL_T", None)
.define("HAVE_STDBOOL_H", None)
.define("HAVE_STDINT_H", None)
.define("USE_RESOLV_THREADED", None)
.file("curl/lib/altsvc.c")
.file("curl/lib/api.c")
.file("curl/lib/bufq.c")
Expand Down Expand Up @@ -303,6 +314,17 @@ fn main() {
.define("HAVE_GETSOCKNAME", None)
.warnings(false);

// One asynchronous resolver: c-ares when asked for, otherwise curl's
// threaded resolver.
if needs_cares {
cfg.define("USE_ARES", None)
.define("USE_RESOLV_ARES", None)
.file("curl/lib/vdns/asyn-ares.c");
configure_cares(&mut cfg, windows);
} else {
cfg.define("USE_RESOLV_THREADED", None);
}

if cfg!(feature = "ntlm") {
cfg.file("curl/lib/curl_endian.c")
.file("curl/lib/curl_gethostname.c")
Expand Down Expand Up @@ -530,12 +552,12 @@ fn main() {
}

#[cfg(not(target_env = "msvc"))]
fn try_vcpkg() -> bool {
fn try_vcpkg(_needs_http2: bool, _needs_cares: bool) -> bool {
false
}

#[cfg(target_env = "msvc")]
fn try_vcpkg() -> bool {
fn try_vcpkg(_needs_http2: bool, needs_cares: bool) -> 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")
Expand Down Expand Up @@ -582,15 +604,23 @@ fn try_vcpkg() -> bool {
println!("cargo:rustc-link-lib=gdi32");
println!("cargo:rustc-link-lib=user32");
println!("cargo:rustc-link-lib=wldap32");

if needs_cares {
if let Err(e) = vcpkg::probe_package("c-ares") {
println!("vcpkg could not find c-ares for system libcurl: {}", e);
return false;
}
}

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") {
fn try_pkg_config(needs_http2: bool, needs_cares: bool) -> bool {
let mut pkgcfg = pkg_config::Config::new();
pkgcfg.cargo_metadata(false);
let lib = match pkgcfg.probe("libcurl") {
Ok(lib) => lib,
Err(e) => {
println!(
Expand All @@ -604,13 +634,20 @@ fn try_pkg_config() -> bool {

// 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() {
if needs_http2 && !curl_config_reports_http2() {
return false;
}

// c-ares support is required for CURLOPT_DNS_SERVERS and related APIs.
// If we cannot confirm the system libcurl was configured with c-ares,
// fall back to compiling libcurl from source.
if needs_cares && !pkg_config_reports_cares(&lib) && !curl_config_reports_cares() {
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();
pkgcfg.cargo_metadata(true).probe("libcurl").unwrap();
for path in lib.include_paths.iter() {
println!("cargo:include={}", path.display());
}
Expand Down Expand Up @@ -641,3 +678,94 @@ fn curl_config_reports_http2() -> bool {

true
}

fn pkg_config_reports_cares(lib: &pkg_config::Library) -> bool {
if lib.libs.iter().any(|name| name.contains("cares")) {
return true;
}

println!(
"failed to find c-ares in pkg-config metadata for libcurl, \
validating with curl-config"
);
false
}

fn curl_config_reports_cares() -> bool {
let output = Command::new("curl-config").arg("--configure").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("--enable-ares") && !stdout.contains("--with-ares") {
println!(
"failed to find c-ares enabled in pkg-config-found libcurl, \
building from source"
);
return false;
}

true
}

fn configure_cares(cfg: &mut cc::Build, windows: bool) {
if windows {
if try_vcpkg_cares(cfg) {
return;
}
} else if try_pkg_config_cares(cfg) {
return;
}

panic!(
"c-ares support requires a discoverable c-ares installation (via vcpkg \
on Windows or pkg-config on non-Windows platforms)"
);
}

#[cfg(not(target_env = "msvc"))]
fn try_vcpkg_cares(_cfg: &mut cc::Build) -> bool {
false
}

#[cfg(target_env = "msvc")]
fn try_vcpkg_cares(cfg: &mut cc::Build) -> bool {
let lib = match vcpkg::Config::new().emit_includes(true).probe("c-ares") {
Ok(lib) => lib,
Err(e) => {
println!("vcpkg could not find c-ares: {}", e);
return false;
}
};

for include in lib.include_paths {
cfg.include(include);
}
true
}

fn try_pkg_config_cares(cfg: &mut cc::Build) -> bool {
for package in ["libcares", "c-ares"] {
match pkg_config::Config::new().probe(package) {
Ok(lib) => {
for include in lib.include_paths {
cfg.include(include);
}
return true;
}
Err(e) => {
println!("pkg-config could not find {}: {}", package, e);
}
}
}

false
}
Loading