aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/ProjConfig.cmake8
-rw-r--r--cmake/proj_config.cmake.in3
-rw-r--r--configure.ac1
-rw-r--r--docs/source/resource_files.rst19
-rw-r--r--scripts/reference_exported_symbols.txt2
-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
-rwxr-xr-xtravis/install.sh16
11 files changed, 136 insertions, 42 deletions
diff --git a/cmake/ProjConfig.cmake b/cmake/ProjConfig.cmake
index 661e6e4f..fa085384 100644
--- a/cmake/ProjConfig.cmake
+++ b/cmake/ProjConfig.cmake
@@ -25,9 +25,11 @@ check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
check_function_exists(localeconv HAVE_LOCALECONV)
check_function_exists(strerror HAVE_STRERROR)
-
-# check libm need on unix
-check_library_exists(m ceil "" HAVE_LIBM)
+if(NOT WIN32)
+ check_library_exists(dl dladdr "" HAVE_LIBDL)
+ # check libm need on unix
+ check_library_exists(m ceil "" HAVE_LIBM)
+endif()
set(PACKAGE "proj")
set(PACKAGE_BUGREPORT "https://github.com/OSGeo/PROJ/issues")
diff --git a/cmake/proj_config.cmake.in b/cmake/proj_config.cmake.in
index d8385ce9..ddb24347 100644
--- a/cmake/proj_config.cmake.in
+++ b/cmake/proj_config.cmake.in
@@ -4,6 +4,9 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
+/* Define to 1 if you have the `dl' library (-ldl). */
+#cmakedefine HAVE_LIBDL 1
+
/* Define to 1 if you have the `m' library (-lm). */
#cmakedefine HAVE_LIBM 1
diff --git a/configure.ac b/configure.ac
index fba41302..ea8c7eb4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,6 +199,7 @@ AC_SEARCH_LIBS([sqrt], [m])
AC_CHECK_FUNC(localeconv, [AC_DEFINE(HAVE_LOCALECONV,1,[Define to 1 if you have localeconv])])
AC_CHECK_FUNCS([strerror])
+AC_CHECK_LIB(dl,dladdr,,,)
dnl ---------------------------------------------------------------------------
dnl Provide a mechanism to disable real mutex support (if lacking win32 or
diff --git a/docs/source/resource_files.rst b/docs/source/resource_files.rst
index 28628d30..48120982 100644
--- a/docs/source/resource_files.rst
+++ b/docs/source/resource_files.rst
@@ -23,8 +23,8 @@ PROJ will attempt to locate its resource files - database, transformation grids
or init-files - from several directories.
The following paths are checked in order:
-- For transformation grids that have an explict relative or absolute path,
- the directory specified in the grid filename.
+- For resource files that have an explict relative or absolute path,
+ the directory specified in the filename.
- Path resolved by the callback function set with
the :c:func:`proj_context_set_file_finder`. If it is set, the next tests
@@ -35,7 +35,9 @@ The following paths are checked in order:
.. _user_writable_directory:
-- The PROJ user writable directory, which is :
+- .. versionadded:: 7.0
+
+ The PROJ user writable directory, which is :
* on Windows, ${LOCALAPPDATA}/proj
* on MacOSX, ${HOME}/Library/Application Support/proj
@@ -45,13 +47,16 @@ The following paths are checked in order:
- Path(s) set with by the environment variable :envvar:`PROJ_LIB`.
On Linux/MacOSX/Unix, use ``:`` to separate paths. On Windows, ``;``
-- On Windows, the *..\\share\\proj\\* and its contents are found automatically
+- .. versionadded:: 7.0
+
+ The *../share/proj/* and its contents are found automatically
at run-time if the installation respects the build structure. That is, the
- binaries and proj.dll are installed under *..\\bin\\*, and resource files
- are in *..\\share\\proj\\*.
+ binaries and proj.dll/libproj.so are installed under *../bin/* or *../lib/*,
+ and resource files are in *../share/proj/*.
- A path built into PROJ as its resource installation directory (whose value is
- $(pkgdatadir)), for builds using the Makefile build system. Note, however,
+ $(pkgdatadir) for builds using the Makefile build system or
+ ${CMAKE_INSTALL_PREFIX}/${DATADIR} for CMake builds). Note, however,
that since this is a hard-wired path setting, it only works if the whole
PROJ installation is not moved somewhere else.
diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt
index d624a893..01f8204b 100644
--- a/scripts/reference_exported_symbols.txt
+++ b/scripts/reference_exported_symbols.txt
@@ -282,6 +282,7 @@ osgeo::proj::datum::VerticalReferenceFrame::create(osgeo::proj::util::PropertyMa
osgeo::proj::datum::VerticalReferenceFrame::realizationMethod() const
osgeo::proj::datum::VerticalReferenceFrame::~VerticalReferenceFrame()
osgeo::proj::File::~File()
+osgeo::proj::FileManager::exists(projCtx_t*, char const*)
osgeo::proj::FileManager::open(projCtx_t*, char const*, osgeo::proj::FileAccess)
osgeo::proj::File::read_line(unsigned long, bool&, bool&)
osgeo::proj::GenericShiftGrid::~GenericShiftGrid()
@@ -780,6 +781,7 @@ pj_get_default_ctx
pj_get_default_fileapi
pj_get_default_searchpaths(projCtx_t*)
pj_get_errno_ref
+pj_get_relative_share_proj(projCtx_t*)
pj_get_release
pj_get_spheroid_defn
pj_has_inverse
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"
diff --git a/travis/install.sh b/travis/install.sh
index 953a7f0b..b0c16881 100755
--- a/travis/install.sh
+++ b/travis/install.sh
@@ -82,6 +82,14 @@ if [ "$SKIP_BUILDS_WITHOUT_GRID" != "yes" ]; then
cd ..
+ if [ $TRAVIS_OS_NAME != "osx" ]; then
+ # Check that we can retrieve the resource directory in a relative way after renaming the installation prefix
+ mkdir /tmp/proj_autoconf_install_from_dist_all_renamed
+ mv /tmp/proj_autoconf_install_from_dist_all /tmp/proj_autoconf_install_from_dist_all_renamed/subdir
+ LD_LIBRARY_PATH=/tmp/proj_autoconf_install_from_dist_all_renamed/subdir/lib /tmp/proj_autoconf_install_from_dist_all_renamed/subdir/bin/projsync --source-id ? --dry-run --system-directory || /bin/true
+ LD_LIBRARY_PATH=/tmp/proj_autoconf_install_from_dist_all_renamed/subdir/lib /tmp/proj_autoconf_install_from_dist_all_renamed/subdir/bin/projsync --source-id ? --dry-run --system-directory 2>/dev/null | grep "Downloading from https://cdn.proj.org into /tmp/proj_autoconf_install_from_dist_all_renamed/subdir/share/proj"
+ fi
+
# cmake build from generated tarball
mkdir build_cmake
cd build_cmake
@@ -92,6 +100,14 @@ if [ "$SKIP_BUILDS_WITHOUT_GRID" != "yes" ]; then
find /tmp/proj_cmake_install
cd ..
+ if [ $TRAVIS_OS_NAME != "osx" ]; then
+ # Check that we can retrieve the resource directory in a relative way after renaming the installation prefix
+ mkdir /tmp/proj_cmake_install_renamed
+ mv /tmp/proj_cmake_install /tmp/proj_cmake_install_renamed/subdir
+ /tmp/proj_cmake_install_renamed/subdir/bin/projsync --source-id ? --dry-run --system-directory || /bin/true
+ /tmp/proj_cmake_install_renamed/subdir/bin/projsync --source-id ? --dry-run --system-directory 2>/dev/null | grep "Downloading from https://cdn.proj.org into /tmp/proj_cmake_install_renamed/subdir/share/proj"
+ fi
+
# return to root
cd ../..
fi