georust / proj

Rust bindings for the latest stable release of PROJ
https://docs.rs/proj
Apache License 2.0
137 stars 44 forks source link

Where (or how) to find built proj.db #128

Closed categulario closed 2 years ago

categulario commented 2 years ago

Ok, here is the situation I'm facing (similar to #66):

I'm trying to package a project built with proj for deployment. Since my build environment doesn't have a recent version of proj the build process just builds it from source. Everything is fine there when running locally. When I try to run the binary somewhere else I face a proj.db not found. It makes sense, it is not there.

Now, I know that one such database is being built as part of the building process of proj-sys. I even found it in target/debug/build/proj-sys-3de39dabca2db38d/out/share/proj/proj.ini the question now is, how do I find this path? Is it predictable? Is there another way to get the built proj.db?

Thanks folks!

urschrei commented 2 years ago

The info() method will give you a struct whose searchpath field is a String containing a :-delimited list of the PROJ search paths that are in use by the executable / library you built. I don't know if they're returned in any particular order, so you'll probably have to split on the : and check each entry for the presence of proj.db (mine is in the second entry in the list on macOS, for instance).

urschrei commented 2 years ago

This works:

use proj::{Info, Proj};
use std::path::{Path, PathBuf};

let pb = PathBuf::from("proj.db");
let p = Proj::new("EPSG:4326").unwrap();
let info = p.info().unwrap();
let foundproj = info
    .searchpath
    .split(':')
    .filter_map(|dir| {
        let projdir = Path::new(dir).join(&pb);
        projdir.exists().then(|| projdir)
    })
    .collect::<Vec<_>>();
// foundproj will either be empty or contain at least one PathBuf entry with the full proj.db path
// You may also want to assert that there's only a single entry in the vec, idk
urschrei commented 2 years ago

and finally if you want, you can put proj.db (you'll have to download it yourself from wherever OSgeo host it for v9.0.0) wherever you want, then add the path to the directory (as opposed to path to the file) to the search path using https://docs.rs/proj/0.26.0/proj/struct.ProjBuilder.html#method.set_search_paths

categulario commented 2 years ago

Thanks for your answers @urschrei !

All of this was triggered by my attempts at building a container for an app that uses proj. In the end the best solution I found was to use an intermediate container with alpine and use its proj.db :/

(you'll have to download it yourself from wherever OSgeo host it for v9.0.0)

From what I've seen they don't host it, because it is built at compile time. It is a target for cmake.

categulario commented 2 years ago

Just for completeness of this thread and in case it is useful for somebody else:

I'm now doing these three things:

And this is the resulting code for finding proj.db:

let proj = Proj::new("EPSG:4326").unwrap();
let searchpath = proj.info().unwrap().searchpath;
let foundproj = searchpath
    .split(':')
    .find_map(|dir| {
        let projdb = Path::new(dir).join("proj.db");
        projdb.is_file().then(|| projdb)
    });