aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2020-02-09 00:53:35 +0100
committerEven Rouault <even.rouault@spatialys.com>2020-02-11 15:48:05 +0100
commit29583196dfae2565a35c7a8759cc8a5640d6a2b1 (patch)
treec862cb9d4206f3be8bc11b9f28855abe43cff018 /src
parenta10b5edfad805b1e09d88b31b953707412440b09 (diff)
downloadPROJ-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.cpp7
-rw-r--r--src/filemanager.cpp115
-rw-r--r--src/filemanager.hpp2
-rw-r--r--src/lib_proj.cmake4
-rw-r--r--src/proj_internal.h1
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"