Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Tom Lane wrote:
> >> I guess what you are saying is we should have a configure-time option to
> >> address configured directories via relative paths from the executable's
> >> directory, rather than absolute paths? Seems reasonable ...
>
> > Yep. In fact, why would we not use that by default?
>
> Because it'll be slower. Instead of
> /usr/local/pgsql/lib
> we'd be using something like
> /usr/local/pgsql/bin/../lib
> which is not too bad here but would get worse if the directories are not
> so close.
>
> But perhaps we can arrange for the path to be simplified down to an
> absolute form when it's constructed at backend startup? You'd need a
> routine anyway to combine the bindir path (determined by FindExec) with
> the relative path provided by configure, so maybe this routine could be
> smart about leading ../ in the configure path.
I wrote relative_path() which does the mapping from compiled src/dst to
a new path. For example:
$ tst1 /usr/local/pgsql/bin /usr/local/pgsql/lib /users/fred/pgsql/bin
/users/fred/pgsql/lib
$ tst1 /a/b/c /a/d /f/g/h
/f/d
This can be used in the backend to map from your bindir to a relative
libdir at runtime, and share too. It returns [mp]alloc'ed values, or
NULL if it can't do the tranformation.
Patch attached.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Index: src/include/port.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/port.h,v
retrieving revision 1.27
diff -c -c -r1.27 port.h
*** src/include/port.h 30 Apr 2004 17:52:07 -0000 1.27
--- src/include/port.h 4 May 2004 17:07:30 -0000
***************
*** 26,31 ****
--- 26,32 ----
extern char *last_path_separator(const char *filename);
extern void canonicalize_path(char *path);
extern char *get_progname(char *argv0);
+ extern char *relative_path(const char *src, const char *dst, const char *target);
/* Portable delay handling */
extern void pg_usleep(long microsec);
Index: src/port/path.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/port/path.c,v
retrieving revision 1.5
diff -c -c -r1.5 path.c
*** src/port/path.c 9 Mar 2004 04:49:02 -0000 1.5
--- src/port/path.c 4 May 2004 17:07:31 -0000
***************
*** 13,21 ****
--- 13,31 ----
*-------------------------------------------------------------------------
*/
+ #ifndef FRONTEND
+ #include "postgres.h"
+ #else
#include "c.h"
+ #endif
#include <ctype.h>
+ #ifndef WIN32
+ #define ISSEP(c) ((c) == '/')
+ #else
+ #define ISSEP(c) ((c) == '/' || (c) == '\\')
+ #endif
+
/*
* is_absolute_path
*/
***************
*** 33,39 ****
}
-
/*
* first_path_separator
*/
--- 43,48 ----
***************
*** 120,123 ****
--- 129,241 ----
return argv0;
else
return last_path_separator(argv0) + 1;
+ }
+
+
+ /*
+ * relative_path
+ *
+ * Determine the relative path for getting from 'src' to 'dst' and
+ * map that change from 'target' to a new directory.
+ */
+ char *
+ relative_path(const char *src, const char *dst, const char *target)
+ {
+ const char *dst_slash = NULL;
+ char *ret;
+ int dirs_up;
+
+ #ifdef WIN32
+ if (isalpha(*src) && src[1] == ':' &&
+ isalpha(*dst) && dst[1] == ':')
+ {
+ if (toupper(*src) != toupper(*src))
+ return NULL; /* no relative path, can't cross drive letters */
+ }
+
+ /* Move past drive letters */
+ if (isalpha(*src) && src[1] == ':')
+ src += 2;
+ if (isalpha(*dst) && dst[1] == ':')
+ src += 2;
+ #endif
+
+ /* If we don't have two absolute paths, give up */
+ if (!is_absolute_path(src) ||
+ !is_absolute_path(dst))
+ return NULL;
+
+ dst_slash = dst;
+
+ while (1)
+ {
+ /* Move past adjacent slashes like //, and trailing ones */
+ while (ISSEP(*src) && (ISSEP(src[1]) || !src[1]))
+ src++;
+ while (ISSEP(*dst) && (ISSEP(dst[1]) || !dst[1]))
+ dst++;
+
+ /* Paths are done or not equal? */
+ if (!*src || !*dst)
+ break;
+ #ifndef WIN32
+ if (*src != *dst)
+ break;
+ #else
+ /* Win32 filesystem is case insensitive */
+ if (toupper(*src) != toupper(*dst) &&
+ (!ISSEP(*src) || !ISSEP(*dst))) /* '/' == '\\' */
+ break;
+ #endif
+ if (ISSEP(*dst))
+ dst_slash = dst;
+
+ src++;
+ dst++;
+ }
+
+ /* Did the last part of the path match? */
+ dirs_up = ((*src == '\0' || ISSEP(*src)) &&
+ (*dst == '\0' || ISSEP(*dst))) ? 0 : 1;
+
+ /* How many directories do we have to move up? */
+ while (*src)
+ {
+ if (ISSEP(*src))
+ {
+ while (ISSEP(*src))
+ src++;
+ if (*src != '\0') /* skip trailing slash */
+ dirs_up++;
+ }
+ else
+ src++;
+ }
+
+ #ifndef FRONTEND
+ ret = palloc(strlen(target) + strlen(dst) + 1);
+ #else
+ ret = malloc(strlen(target) + strlen(dst) + 1);
+ #endif
+
+ strcpy(ret, target);
+
+ /* Trim off trailing slash from target */
+ if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1]))
+ dirs_up++;
+
+ while (dirs_up--)
+ if (last_path_separator(ret) != NULL)
+ *last_path_separator(ret) = '\0'; /* trim off directory */
+ else
+ return NULL;
+
+ /* Add dst to trimmed target */
+ strcat(ret, dst_slash);
+
+ /* Trim off trailing slash from result */
+ if (strlen(ret) > 0 && ISSEP(ret[strlen(ret)-1]))
+ *last_path_separator(ret) = '\0'; /* trim off slash */
+
+ return ret;
}