diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-02-09 00:53:35 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-02-11 15:48:05 +0100 |
| commit | 29583196dfae2565a35c7a8759cc8a5640d6a2b1 (patch) | |
| tree | c862cb9d4206f3be8bc11b9f28855abe43cff018 /src | |
| parent | a10b5edfad805b1e09d88b31b953707412440b09 (diff) | |
| download | PROJ-29583196dfae2565a35c7a8759cc8a5640d6a2b1.tar.gz PROJ-29583196dfae2565a35c7a8759cc8a5640d6a2b1.zip | |
Use relative directory to locate PROJ resource files.
Fixes #1490
This is an extension of the Window-specific logic added recently to
Unix builds. This reuses parts of proposed past commit
https://github.com/OSGeo/PROJ/pull/1517/commits/82a07e51c6e24ddb936d131ababe29f1ac36ef14
(credits to @abellgithub)
Diffstat (limited to 'src')
| -rw-r--r-- | src/apps/projsync.cpp | 7 | ||||
| -rw-r--r-- | src/filemanager.cpp | 115 | ||||
| -rw-r--r-- | src/filemanager.hpp | 2 | ||||
| -rw-r--r-- | src/lib_proj.cmake | 4 | ||||
| -rw-r--r-- | src/proj_internal.h | 1 |
5 files changed, 97 insertions, 32 deletions
diff --git a/src/apps/projsync.cpp b/src/apps/projsync.cpp index 40848f51..61681260 100644 --- a/src/apps/projsync.cpp +++ b/src/apps/projsync.cpp @@ -137,7 +137,12 @@ int main(int argc, char *argv[]) { } else if (arg == "--user-writable-directory") { // do nothing } else if (arg == "--system-directory") { - targetDir = PROJ_LIB; + targetDir = pj_get_relative_share_proj(ctx); +#ifdef PROJ_LIB + if (targetDir.empty()) { + targetDir = PROJ_LIB; + } +#endif } else if (arg == "--target-dir" && i + 1 < argc) { i++; targetDir = argv[i]; diff --git a/src/filemanager.cpp b/src/filemanager.cpp index aea9b11d..a90af572 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -46,9 +46,15 @@ #include <sys/stat.h> +#include "proj_config.h" + #ifdef _WIN32 #include <shlobj.h> +#include <windows.h> #else +#ifdef HAVE_LIBDL +#include <dlfcn.h> +#endif #include <sys/types.h> #include <unistd.h> #endif @@ -1264,13 +1270,15 @@ static bool is_rel_or_absolute_filename(const char *name) { // --------------------------------------------------------------------------- +static std::string pj_get_relative_share_proj_internal_no_check() { +#if defined(_WIN32) || defined(HAVE_LIBDL) #ifdef _WIN32 - -static std::string pj_get_win32_projlib() { - /* Check if proj.db lieves in a share/proj dir parallel to bin/proj.dll */ - /* Based in - * https://stackoverflow.com/questions/9112893/how-to-get-path-to-executable-in-c-running-on-windows - */ + HMODULE hm = NULL; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCSTR)&pj_get_relative_share_proj, &hm) == 0) { + return std::string(); + } DWORD path_size = 1024; @@ -1278,7 +1286,7 @@ static std::string pj_get_win32_projlib() { for (;;) { wout.clear(); wout.resize(path_size); - DWORD result = GetModuleFileNameW(nullptr, &wout[0], path_size - 1); + DWORD result = GetModuleFileNameW(hm, &wout[0], path_size - 1); DWORD last_error = GetLastError(); if (result == 0) { @@ -1292,26 +1300,79 @@ static std::string pj_get_win32_projlib() { break; } } - // Now remove the program's name. It was (example) - // "C:\programs\gmt6\bin\gdal_translate.exe" wout.resize(wcslen(wout.c_str())); std::string out = NS_PROJ::WStringToUTF8(wout); - size_t k = out.size(); - while (k > 0 && out[--k] != '\\') { + constexpr char dir_sep = '\\'; +#else + Dl_info info; + if (!dladdr((const void *)pj_get_relative_share_proj, &info)) { + return std::string(); } - out.resize(k); - - out += "/../share/proj"; + std::string out(info.dli_fname); + constexpr char dir_sep = '/'; + // "optimization" for cmake builds where RUNPATH is set to ${prefix}/lib + out = replaceAll(out, "/bin/../", "/"); +#ifdef __linux + // If we get a filename without any path, this is most likely a static + // binary. Resolve the executable name + if (out.find(dir_sep) == std::string::npos) { + constexpr size_t BUFFER_SIZE = 1024; + std::vector<char> path(BUFFER_SIZE + 1); + ssize_t nResultLen = readlink("/proc/self/exe", &path[0], BUFFER_SIZE); + if (nResultLen >= 0 && static_cast<size_t>(nResultLen) < BUFFER_SIZE) { + out.assign(path.data(), static_cast<size_t>(nResultLen)); + } + } +#endif + if (starts_with(out, "./")) + out = out.substr(2); +#endif + auto pos = out.find_last_of(dir_sep); + if (pos == std::string::npos) { + // The initial path was something like libproj.so" + out = "../share/proj"; + return out; + } + out.resize(pos); + pos = out.find_last_of(dir_sep); + if (pos == std::string::npos) { + // The initial path was something like bin/libproj.so" + out = "share/proj"; + return out; + } + out.resize(pos); + // The initial path was something like foo/bin/libproj.so" + out += "/share/proj"; return out; +#else + return std::string(); +#endif } -// --------------------------------------------------------------------------- +static std::string +pj_get_relative_share_proj_internal_check_exists(PJ_CONTEXT *ctx) { + if (ctx == nullptr) { + ctx = pj_get_default_ctx(); + } + std::string path(pj_get_relative_share_proj_internal_no_check()); + if (!path.empty() && NS_PROJ::FileManager::exists(ctx, path.c_str())) { + return path; + } + return std::string(); +} -static const char *get_path_from_win32_projlib(PJ_CONTEXT *ctx, - const char *name, - std::string &out) { +std::string pj_get_relative_share_proj(PJ_CONTEXT *ctx) { + static std::string path( + pj_get_relative_share_proj_internal_check_exists(ctx)); + return path; +} - out = pj_get_win32_projlib(); +// --------------------------------------------------------------------------- + +static const char *get_path_from_relative_share_proj(PJ_CONTEXT *ctx, + const char *name, + std::string &out) { + out = pj_get_relative_share_proj(ctx); if (out.empty()) { return nullptr; } @@ -1322,8 +1383,6 @@ static const char *get_path_from_win32_projlib(PJ_CONTEXT *ctx, : nullptr; } -#endif - /************************************************************************/ /* pj_open_lib_internal() */ /************************************************************************/ @@ -1442,11 +1501,9 @@ pj_open_lib_internal(projCtx ctx, const char *name, const char *mode, if (fid) break; } -#ifdef _WIN32 /* check if it lives in a ../share/proj dir of the proj dll */ - } else if ((sysname = get_path_from_win32_projlib(ctx, name, fname)) != - nullptr) { -#endif + } else if ((sysname = get_path_from_relative_share_proj( + ctx, name, fname)) != nullptr) { /* or hardcoded path */ } else if ((sysname = proj_lib_name) != nullptr) { fname = sysname; @@ -1503,14 +1560,12 @@ std::vector<std::string> pj_get_default_searchpaths(PJ_CONTEXT *ctx) { if (!envPROJ_LIB.empty()) { ret.push_back(envPROJ_LIB); } -#ifdef _WIN32 if (envPROJ_LIB.empty()) { - const std::string win32Dir = pj_get_win32_projlib(); - if (!win32Dir.empty()) { - ret.push_back(win32Dir); + const std::string relativeSharedProj = pj_get_relative_share_proj(ctx); + if (!relativeSharedProj.empty()) { + ret.push_back(relativeSharedProj); } } -#endif #ifdef PROJ_LIB if (envPROJ_LIB.empty()) { ret.push_back(PROJ_LIB); diff --git a/src/filemanager.hpp b/src/filemanager.hpp index 9446a0bc..233c657c 100644 --- a/src/filemanager.hpp +++ b/src/filemanager.hpp @@ -55,7 +55,7 @@ class FileManager { // "Low-level" interface. static PROJ_DLL std::unique_ptr<File> open(PJ_CONTEXT *ctx, const char *filename, FileAccess access); - static bool exists(PJ_CONTEXT *ctx, const char *filename); + static PROJ_DLL bool exists(PJ_CONTEXT *ctx, const char *filename); static bool mkdir(PJ_CONTEXT *ctx, const char *filename); static bool unlink(PJ_CONTEXT *ctx, const char *filename); static bool rename(PJ_CONTEXT *ctx, const char *oldPath, diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index 3c42f973..d14a48c6 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -415,6 +415,10 @@ if(UNIX) if(M_LIB) target_link_libraries(${PROJ_CORE_TARGET} -lm) endif() + find_library(DL_LIB dl) + if(M_LIB) + target_link_libraries(${PROJ_CORE_TARGET} -ldl) + endif() endif() if(USE_THREAD AND Threads_FOUND AND CMAKE_USE_PTHREADS_INIT) target_link_libraries(${PROJ_CORE_TARGET} ${CMAKE_THREAD_LIBS_INIT}) diff --git a/src/proj_internal.h b/src/proj_internal.h index 557c61cb..0cffb475 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -874,6 +874,7 @@ std::string PROJ_DLL pj_context_get_grid_cache_filename(PJ_CONTEXT *ctx); // For use by projsync std::string PROJ_DLL pj_context_get_user_writable_directory(PJ_CONTEXT *ctx, bool create); void PROJ_DLL pj_context_set_user_writable_directory(PJ_CONTEXT* ctx, const std::string& path); +std::string PROJ_DLL pj_get_relative_share_proj(PJ_CONTEXT *ctx); /* classic public API */ #include "proj_api.h" |
