Alexandre Julliard : libwine: Use dladdr if supported to get the run-time path of libwine.so

Alexandre Julliard julliard at wine.codeweavers.com
Mon Feb 13 07:03:20 CST 2006


Module: wine
Branch: refs/heads/master
Commit: 0b34fb365657b9983a591610b2d80e298623d6f0
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=0b34fb365657b9983a591610b2d80e298623d6f0

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Sat Feb 11 22:38:44 2006 +0100

libwine: Use dladdr if supported to get the run-time path of libwine.so
and define the default dll and bin directories relative to it.

---

 libs/wine/Makefile.in |    2 -
 libs/wine/config.c    |  110 ++++++++++++++++++++++++++++++++++++++++++++++++-
 libs/wine/loader.c    |    6 ++-
 3 files changed, 112 insertions(+), 6 deletions(-)

diff --git a/libs/wine/Makefile.in b/libs/wine/Makefile.in
index b9ddf42..34b6400 100644
--- a/libs/wine/Makefile.in
+++ b/libs/wine/Makefile.in
@@ -5,7 +5,7 @@ VPATH     = @srcdir@
 LIBRARY   = wine
 SOVERSION = 1
 VERSCRIPT = $(SRCDIR)/wine.map
-EXTRADEFS = -D__WINESRC__ -DBINDIR="\"$(bindir)\"" -DDLLDIR="\"$(dlldir)\""
+EXTRADEFS = -D__WINESRC__ -DBINDIR="\"$(bindir)\"" -DLIBDIR="\"$(libdir)\"" -DDLLDIR="\"$(dlldir)\""
 EXTRALIBS = $(LIBPORT) @DLLIBS@ @CRTLIBS@ @LDLIBWINEFLAGS@
 
 C_SRCS = \
diff --git a/libs/wine/config.c b/libs/wine/config.c
index b2b039c..33aa87a 100644
--- a/libs/wine/config.c
+++ b/libs/wine/config.c
@@ -101,6 +101,103 @@ inline static void remove_trailing_slash
     while (len > 1 && path[len-1] == '/') path[--len] = 0;
 }
 
+/* determine where the destination path is located relative to the 'from' path */
+inline static const char *get_relative_path( const char *from, const char *dest, unsigned int *dotdots )
+{
+#define DIR_END(p)  (*(p) == 0 || *(p) == '/')
+    const char *start;
+
+    *dotdots = 0;
+    for (;;)
+    {
+        while (*from == '/') from++;
+        while (*dest == '/') dest++;
+        start = dest;  /* save start of next path element */
+        if (!*from) break;
+
+        while (!DIR_END(from) && *from == *dest) { from++; dest++; }
+        if (DIR_END(from) && DIR_END(dest)) continue;
+
+        /* count remaining elements in 'from' */
+        do
+        {
+            (*dotdots)++;
+            while (!DIR_END(from)) from++;
+            while (*from == '/') from++;
+        }
+        while (*from);
+        break;
+    }
+    return start;
+#undef DIR_END
+}
+
+/* return the directory that contains the library at run-time */
+static const char *get_runtime_libdir(void)
+{
+    static char *libdir;
+
+#ifdef HAVE_DLADDR
+    Dl_info info;
+    char *p;
+
+    if (!libdir && dladdr( get_runtime_libdir, &info ) && (p = strrchr( info.dli_fname, '/' )))
+    {
+        unsigned int len = p - info.dli_fname;
+        if (!len) len++;  /* include initial slash */
+        libdir = xmalloc( len + 1 );
+        memcpy( libdir, info.dli_fname, len );
+        libdir[len] = 0;
+    }
+#endif /* HAVE_DLADDR */
+    return libdir;
+}
+
+/* determine the proper location of the given path based on the current libdir */
+static char *get_path_from_libdir( const char *path, const char *filename )
+{
+    char *p, *ret;
+    const char *libdir = get_runtime_libdir();
+
+    /* retrieve the library load path */
+
+    if (libdir)
+    {
+        unsigned int dotdots = 0;
+        const char *start = get_relative_path( LIBDIR, path, &dotdots );
+
+        ret = xmalloc( strlen(libdir) + 3 * dotdots + strlen(start) + strlen(filename) + 3 );
+        strcpy( ret, libdir );
+        p = ret + strlen(libdir);
+        if (p[-1] != '/') *p++ = '/';
+
+        while (dotdots--)
+        {
+            p[0] = '.';
+            p[1] = '.';
+            p[2] = '/';
+            p += 3;
+        }
+
+        strcpy( p, start );
+        p += strlen(p);
+    }
+    else
+    {
+        ret = xmalloc( strlen(path) + strlen(filename) + 2 );
+        strcpy( ret, path );
+        p = ret + strlen(ret);
+    }
+
+    if (*filename)
+    {
+        if (p[-1] != '/') *p++ = '/';
+        strcpy( p, filename );
+    }
+    else if (p[-1] == '/') p[-1] = 0;
+    return ret;
+}
+
 /* initialize the server directory value */
 static void init_server_dir( dev_t dev, ino_t ino )
 {
@@ -127,6 +224,15 @@ static void init_server_dir( dev_t dev, 
         sprintf( p, "%lx", (unsigned long)ino );
 }
 
+/* retrieve the default dll dir */
+const char *get_default_dlldir(void)
+{
+    static const char *dlldir;
+
+    if (!dlldir) dlldir = get_path_from_libdir( DLLDIR, "" );
+    return dlldir;
+}
+
 /* initialize all the paths values */
 static void init_paths(void)
 {
@@ -314,9 +420,7 @@ void wine_exec_wine_binary( const char *
     else if (!name) name = argv0_name;
 
     /* first, try bin directory */
-    argv[0] = xmalloc( sizeof(BINDIR "/") + strlen(name) );
-    strcpy( argv[0], BINDIR "/" );
-    strcat( argv[0], name );
+    argv[0] = get_path_from_libdir( BINDIR, name );
     preloader_exec( argv, envp, use_preloader );
     free( argv[0] );
 
diff --git a/libs/wine/loader.c b/libs/wine/loader.c
index 50ab544..e58ab7c 100644
--- a/libs/wine/loader.c
+++ b/libs/wine/loader.c
@@ -74,13 +74,14 @@ static const IMAGE_NT_HEADERS *main_exe;
 
 static load_dll_callback_t load_dll_callback;
 
-static const char default_dlldir[] = DLLDIR;
+static const char *default_dlldir;
 static const char **dll_paths;
 static int nb_dll_paths;
 static int dll_path_maxlen;
 
 extern void mmap_init(void);
 extern void debug_init(void);
+extern const char *get_default_dlldir(void);
 
 /* build the dll load path from the WINEDLLPATH variable */
 static void build_dll_path(void)
@@ -121,7 +122,8 @@ static void build_dll_path(void)
     }
 
     /* append default dll dir (if not empty) to path */
-    if ((len = sizeof(default_dlldir)-1))
+    default_dlldir = get_default_dlldir();
+    if ((len = strlen(default_dlldir)) > 0)
     {
         if (len > dll_path_maxlen) dll_path_maxlen = len;
         dll_paths[nb_dll_paths++] = default_dlldir;




More information about the wine-cvs mailing list