microsoft / vcpkg

C++ Library Manager for Windows, Linux, and MacOS
MIT License
22.79k stars 6.3k forks source link

[proj] PROJ package sets invalid locaiton for proj.db in debug installation #20577

Open Cazadorro opened 2 years ago

Cazadorro commented 2 years ago

Describe the bug PROJ package sets invalid locaiton for proj.db in debug mode. The PROJ_LIB variable (presumably controlled by CMake) is set to a location that doesn't exist in the debug installation of the library,

pj_obj_create: Cannot find proj.db
pj_obj_create: Cannot find proj.db
proj_create_operation_factory_context: Cannot find proj.db
proj_create_operations: source_crs is not a CRS

In filemanager.cpp, theres the lines:

static const char *proj_lib_name =
#ifdef PROJ_LIB
    PROJ_LIB;
#else
    nullptr;
#endif

in my project PROJ_LIB is "/home/user/Documents/projects/vcpkg/packages/proj4_x64-linux/debug/share/proj4", something set during the installation process. The problem with this directory, is that no such directory actually exists, there's only one directory inside:

/home/user/Documents/projects/vcpkg/packages/proj4_x64-linux/debug

and it's lib (which houses the static library). That doesn't mean, however, share and proj.db doesn't exist, it actually does, but in a separate sister directory:

/home/user/Documents/projects/vcpkg/packages/proj4_x64-linux/share/proj4

and in this directory is where proj.db exists.

Environment

To Reproduce Steps to reproduce the behavior:

  1. ./vcpkg install proj
  2. See error Repro code when
    #include <proj.h>
    int main(){
    auto proj_context = proj_context_create();
    auto proj_example = proj_create(proj_context, "+proj=latlong +ellps=WGS84 +datum=WGS84");
    proj_destroy(proj_example);
    proj_context_destroy(proj_context);
    return 0; 
    }

    Expected behavior PROJ_LIB should be set to /home/user/Documents/projects/vcpkg/packages/proj4_x64-linux/share/proj4

Failure logs N/A

Additional context N/A

dg0yt commented 2 years ago

There is no "right" absolute location. packages is just a staging location during build. installed may be in a different location when a binary artifact is restored from cache. And when you deploy an app, the location might be entirely different.

proj has various ways to set the search path for its data, e.g. environment variable PROJ_LIB. Cf. https://proj.org/resource_files.html

Cazadorro commented 2 years ago

There isn't a right location, but I'd say a location that doesn't even exist is clearly the wrong location.

dg0yt commented 2 years ago

There isn't a right location, but I'd say a location that doesn't even exist is clearly the wrong location.

What is the proposed "fix"?

JackBoosY commented 2 years ago

Anyway, we should fix the relative path in the code.

JackBoosY commented 2 years ago
  1. From data/CH line 5:

    # You'll need to download the grids separately and put in a directory
    # scanned by libproj. Directories may be added to the scan list through
    # the PROJ_LIB environment variable

    code https://github.com/OSGeo/PROJ/blob/master/src/filemanager.cpp#L1576-L1600:

    const std::string envPROJ_LIB = NS_PROJ::FileManager::getProjLibEnvVar(ctx);
    const std::string relativeSharedProj = pj_get_relative_share_proj(ctx);
    
    if (gbPROJ_LIB_ENV_VAR_TRIED_LAST) {
    /* Situation where PROJ_LIB environment variable is tried in last */
    #ifdef PROJ_LIB
        ret.push_back(PROJ_LIB);
    #endif
        if (!relativeSharedProj.empty()) {
            ret.push_back(relativeSharedProj);
        }
        if (!envPROJ_LIB.empty()) {
            ret.push_back(envPROJ_LIB);
        }
    } else {
        /* Situation where PROJ_LIB environment variable is used if defined */
        if (!envPROJ_LIB.empty()) {
            ret.push_back(envPROJ_LIB);
        } else {
            if (!relativeSharedProj.empty()) {
                ret.push_back(relativeSharedProj);
            }
    #ifdef PROJ_LIB
            ret.push_back(PROJ_LIB);
    #endif

    I think we should set PROJ_LIB as a environment variable.

  2. From appveyor.yml line 54:

    test_script:
    - echo test_script
    - set PROJ_LIB=%PROJ_DIR%\share\proj
    ...

    PROJ_LIB should be set to __IMPORTPREFIX/share/proj .

  3. From docs/plot/plot.py line 70:

    PROJ_LIB = os.environ.get('PROJ_LIB', '../../data')

    The folder name should be data.

So, what should be the installation path?

dg0yt commented 2 years ago

I think we should set PROJ_LIB as a environment variable.

The user must set the environment variable (or use another mechanism). There is no point setting it in vcpkg.

The folder name should be data.

The folder can have any name.

So, what should be the installation path?

That's the point: there is no single answer. In particular for the debug build, you don't know if the library is used from debug/bin, from tools/proj/debug/bin, from app-local deployment by vcpkg, or from another user installation directory. And so you don't know neither the absolute path nor the relative path.

In a way, it would be better to use an invalid default path also for the release variant, in order to remove the variability, and to stress the user responsibility for setting the resource path.

JackBoosY commented 2 years ago

Since we have installed a database, we should set them in cmake or other configuration for easy calling.