Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for VCPKG on Windows #493

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

- Added support for VCPKG. Set `GDAL_VCPKG` environment variable to `1` to enable VCPKG support. Set `GDAL_VCPKG_TRIPLET` to the desired triplet (e.g. `x64-windows-static`). `VCPKG_ROOT` must point to the VCPKG root directory. Install GDAL with `vcpkg install gdal:x64-windows-static` (or the desired triplet). Install pkgconf with `vcpkg install pkgconf:x64-windows-static`, set `PKG_CONFIG` to the pkgconf executable (e.g. `%VCPKG_ROOT%\installed\x64-windows-static\tools\pkgconf\pkgconf.exe`) and `PKG_CONFIG_PATH` to `%VCPKG_ROOT%\installed\x64-windows-static\lib\pkgconfig`. When building non-static version, copy missing dlls from `%VCPKG_ROOT%\installed\x64-windows\bin` to the executable directory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you move the usage instructions into the gdal-sys README.md. That way, people might actually find them 🙂.


- <https://github.com/georust/gdal/pull/493>

- Defers the gdal_i.lib missing message until after the pkg-config check and outputs pkg-config metadata in case of a static build.

- <https://github.com/georust/gdal/pull/492>
Expand Down
137 changes: 111 additions & 26 deletions gdal-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ fn main() {
println!("cargo:rerun-if-env-changed=GDAL_HOME");
println!("cargo:rerun-if-env-changed=GDAL_VERSION");

if cfg!(windows) {
println!("cargo:rerun-if-env-changed=GDAL_VCPKG");
println!("cargo:rerun-if-env-changed=GDAL_VCPKG_TRIPLET");
}

let mut need_metadata = true;
let mut lib_name = String::from("gdal");

Expand All @@ -114,41 +119,109 @@ fn main() {
let mut version = env::var_os("GDAL_VERSION")
.map(|vs| vs.to_string_lossy().to_string())
.and_then(|vs| Version::parse(vs.trim()).ok());
let use_vcpkg = if cfg!(windows) {
env::var_os("GDAL_VCPKG").is_some()
} else {
false
};

let mut found = false;
if cfg!(windows) {
// first, look for a static library in $GDAL_LIB_DIR or $GDAL_HOME/lib
// works in windows-msvc and windows-gnu
if let Some(ref lib_dir) = lib_dir {
let lib_path = lib_dir.join("gdal_i.lib");
if lib_path.exists() {
prefer_static = true;
lib_name = String::from("gdal_i");
found = true;
if use_vcpkg {
let vcpkg_root = env_dir("VCPKG_ROOT");
let vcpkg_triplet = env::var("GDAL_VCPKG_TRIPLET");

if vcpkg_root.is_none() {
panic!("GDAL_VCPKG requires VCPKG_ROOT to be set.");
}
}
if !found {
if let Some(ref home_dir) = home_dir {
let home_lib_dir = home_dir.join("lib");
let lib_path = home_lib_dir.join("gdal_i.lib");

if vcpkg_triplet.is_err() {
panic!("GDAL_VCPKG requires GDAL_VCPKG_TRIPLET to be set.");
}

let vcpkg_root = vcpkg_root.unwrap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let vcpkg_root = vcpkg_root.unwrap();
let vcpkg_root = vcpkg_root.expect("GDAL_VCPKG requires VCPKG_ROOT to be set");

(same for vcpkg_triplet)

let vcpkg_triplet = vcpkg_triplet.unwrap();
prefer_static = vcpkg_triplet.ends_with("-static");

let vcpkg_install_dir = vcpkg_root.join("installed").join(vcpkg_triplet.clone());

let pkg_config = env::var("PKG_CONFIG");
let pkg_config_path = env::var("PKG_CONFIG_PATH");

let required_pkg_config = vcpkg_install_dir
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand these. If we know the correct PKG_CONFIG, why does the user have to set it?

.join("tools")
.join("pkgconf")
.join("pkgconf.exe")
.to_str()
.unwrap()
.to_owned();
let required_pkg_config_path = vcpkg_install_dir
.join("lib")
.join("pkgconfig")
.to_str()
.unwrap()
.to_owned();

let valid_pkg_config = match pkg_config {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would look a bit nicer like:

            if !matches!(pkg_config, Some(required_pkg_config)) {
                panic!("GDAL_VCPKG requires PKG_CONFIG to be set to '{required_pkg_config}'.");
            }

Ok(pkg_config) => pkg_config == required_pkg_config,
Err(_) => false,
};

if !valid_pkg_config {
panic!("GDAL_VCPKG requires PKG_CONFIG to be set to '{required_pkg_config}'.");
}

let valid_pkg_config_path = match pkg_config_path {
Ok(pkg_config_path) => pkg_config_path == required_pkg_config_path,
Err(_) => false,
};

if !valid_pkg_config_path {
panic!("GDAL_VCPKG requires PKG_CONFIG_PATH to be set to '{required_pkg_config_path}'.",);
}

let lib_path = vcpkg_install_dir.join("lib");

if !lib_path.join("gdal.lib").exists() {
panic!("GDAL_VCPKG requires that gdal is installed for '{vcpkg_triplet}' triplet.");
}

lib_dir = Some(lib_path);
lib_name = String::from("gdal");
} else {
// first, look for a static library in $GDAL_LIB_DIR or $GDAL_HOME/lib
// works in windows-msvc and windows-gnu
if let Some(ref lib_dir) = lib_dir {
let lib_path = lib_dir.join("gdal_i.lib");
if lib_path.exists() {
prefer_static = true;
lib_name = String::from("gdal_i");
lib_dir = Some(home_lib_dir);
found = true;
}
}
}
if !found {
// otherwise, look for a gdalxxx.dll in $GDAL_HOME/bin
// works in windows-gnu
if let Some(ref home_dir) = home_dir {
let bin_dir = home_dir.join("bin");
if bin_dir.exists() {
if let Some(name) = find_gdal_dll(&bin_dir).unwrap() {
prefer_static = false;
lib_dir = Some(bin_dir);
lib_name = name;
if !found {
if let Some(ref home_dir) = home_dir {
let home_lib_dir = home_dir.join("lib");
let lib_path = home_lib_dir.join("gdal_i.lib");
if lib_path.exists() {
prefer_static = true;
lib_name = String::from("gdal_i");
lib_dir = Some(home_lib_dir);
found = true;
}
}
}
if !found {
// otherwise, look for a gdalxxx.dll in $GDAL_HOME/bin
// works in windows-gnu
if let Some(ref home_dir) = home_dir {
let bin_dir = home_dir.join("bin");
if bin_dir.exists() {
if let Some(name) = find_gdal_dll(&bin_dir).unwrap() {
prefer_static = false;
lib_dir = Some(bin_dir);
lib_name = name;
}
}
}
}
Expand Down Expand Up @@ -182,8 +255,8 @@ fn main() {
if let Some(lib_dir) = lib_dir {
let link_type = if prefer_static { "static" } else { "dylib" };

println!("cargo:rustc-link-lib={link_type}={lib_name}");
println!("cargo:rustc-link-search={}", lib_dir.to_str().unwrap());
println!("cargo:rustc-link-lib={link_type}={lib_name}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


if !prefer_static {
need_metadata = false;
Expand All @@ -208,6 +281,18 @@ fn main() {
for dir in &gdal.include_paths {
include_paths.push(dir.to_str().unwrap().to_string());
}

if cfg!(windows) && prefer_static && use_vcpkg {
for lib in &gdal.link_files {
let lib_name = lib.file_stem().unwrap().to_str().unwrap();
println!("cargo:rustc-link-lib=static={lib_name}");
}
println!("cargo:rustc-link-lib=crypt32");
println!("cargo:rustc-link-lib=Secur32");
println!("cargo:rustc-link-lib=Wbemuuid");
println!("cargo:rustc-link-lib=Wldap32");
}

if version.is_none() {
// development GDAL versions look like 3.7.2dev, which is not valid semver
let mut version_string = gdal.version.trim().to_string();
Expand Down