diff options
-rw-r--r-- | Source/kwsys/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Source/kwsys/SharedForward.h.in | 499 |
2 files changed, 500 insertions, 1 deletions
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 48732d6..c3455f3 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -245,7 +245,7 @@ ENDFOREACH(header) # Build a list of classes and headers we need to implement the # selected components. Initialize with required components. SET(KWSYS_CLASSES) -SET(KWSYS_H_FILES Configure) +SET(KWSYS_H_FILES Configure SharedForward) SET(KWSYS_HXX_FILES Configure) # Enforce component dependencies. diff --git a/Source/kwsys/SharedForward.h.in b/Source/kwsys/SharedForward.h.in new file mode 100644 index 0000000..5ae521b --- /dev/null +++ b/Source/kwsys/SharedForward.h.in @@ -0,0 +1,499 @@ +/*========================================================================= + + Program: KWSys - Kitware System Library + Module: $RCSfile$ + + Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef @KWSYS_NAMESPACE@_SharedForward_h +#define @KWSYS_NAMESPACE@_SharedForward_h + +/* + This header is used to create a forwarding executable sets up the + shared library search path and replaces itself with a real + executable. This is useful when creating installations on UNIX with + shared libraries that will run from any install directory. Typical + usage: + + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD "foo-real" + #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL "../lib/foo-1.2/foo-real" + #include <@KWSYS_NAMESPACE@/SharedForward.h> + int main(int argc, char** argv) + { + return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); + } + */ + +/*--------------------------------------------------------------------------*/ +/* Configuration for this executable. Specify search and executable + paths relative to the forwarding executable location or as full + paths. Include no trailing slash. */ + +/* This is not useful on Windows. */ +#if defined(_WIN32) +# error "@KWSYS_NAMESPACE@/SharedForward.h is useless on Windows." +#endif + +/* Full path to the directory in which this executable is built. Do + not include a trailing slash. */ +#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD" +#endif +#if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD) +# define KWSYS_SHARED_FORWARD_DIR_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD +#endif + +/* Library search path for build tree. */ +#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD" +#endif +#if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD) +# define KWSYS_SHARED_FORWARD_PATH_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD +#endif + +/* Library search path for install tree. */ +#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL" +#endif +#if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL) +# define KWSYS_SHARED_FORWARD_PATH_INSTALL @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL +#endif + +/* The real executable to which to forward in the build tree. */ +#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD" +#endif +#if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD) +# define KWSYS_SHARED_FORWARD_EXE_BUILD @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD +#endif + +/* The real executable to which to forward in the install tree. */ +#if !defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL) +# error "Must define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL" +#endif +#if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL) +# define KWSYS_SHARED_FORWARD_EXE_INSTALL @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL +#endif + +/* Create command line option to print environment setting and exit. */ +#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT) +# if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) +# define KWSYS_SHARED_FORWARD_OPTION_PRINT @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT +# endif +#else +# undef KWSYS_SHARED_FORWARD_OPTION_PRINT +#endif + +/* Create command line option to run ldd or equivalent. */ +#if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD) +# if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD) +# define KWSYS_SHARED_FORWARD_OPTION_LDD @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD +# endif +#else +# undef KWSYS_SHARED_FORWARD_OPTION_LDD +#endif + +/*--------------------------------------------------------------------------*/ +/* Include needed system headers. */ + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> + +/*--------------------------------------------------------------------------*/ +/* Configuration for this platform. */ + +/* The path separator for this platform. */ +#define KWSYS_SHARED_FORWARD_PATH_SEP ':' +static const char kwsys_shared_forward_path_sep[2] = {KWSYS_SHARED_FORWARD_PATH_SEP, 0}; + +/* The maximum length of a file name. */ +#if defined(PATH_MAX) +# define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX +#elif defined(MAXPATHLEN) +# define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN +#else +# define KWSYS_SHARED_FORWARD_MAXPATH 16384 +#endif + +/* Select the environment variable holding the shared library runtime + search path for this platform and build configuration. Also select + ldd command equivalent. */ + +/* Linux */ +#if defined(__linux) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +#endif + +/* OSX */ +#if defined(__APPLE__) +# define KWSYS_SHARED_FORWARD_LDD "otool", "-L" +# define KWSYS_SHARED_FORWARD_LDD_N 2 +# define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH" +#endif + +/* AIX */ +#if defined(_AIX) +# define KWSYS_SHARED_FORWARD_LDD "dump", "-H" +# define KWSYS_SHARED_FORWARD_LDD_N 2 +# define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH" +#endif + +/* SUN */ +#if defined(__sparc) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# include <sys/isa_defs.h> +# if defined(_ILP32) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif defined(_LP64) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64" +# endif +#endif + +/* HP-UX */ +#if defined(__hpux) +# define KWSYS_SHARED_FORWARD_LDD "chatr" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if defined(__LP64__) +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# else +# define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH" +# endif +#endif + +/* SGI MIPS */ +#if defined(__sgi) && defined(_MIPS_SIM) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# if _MIPS_SIM == _ABIO32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +# elif _MIPS_SIM == _ABIN32 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH" +# elif _MIPS_SIM == _ABI64 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH" +# endif +#endif + +/* Guess on this unknown system. */ +#if !defined(KWSYS_SHARED_FORWARD_LDPATH) +# define KWSYS_SHARED_FORWARD_LDD "ldd" +# define KWSYS_SHARED_FORWARD_LDD_N 1 +# define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" +#endif + +/*--------------------------------------------------------------------------*/ +/* Function to get the directory containing the given file or directory. */ +static void kwsys_shared_forward_dirname(const char* begin, char* result) +{ + /* Find the location of the last slash. */ + int last_slash_index = -1; + const char* end = begin + strlen(begin); + for(;begin <= end && last_slash_index < 0; --end) + { + if(*end == '/') + { + last_slash_index = end-begin; + } + } + + /* Handle each case of the index of the last slash. */ + if(last_slash_index < 0) + { + /* No slashes. */ + strcpy(result, "."); + } + else if(last_slash_index == 0) + { + /* Only one leading slash. */ + strcpy(result, "/"); + } + else + { + /* A non-leading slash. */ + strncpy(result, begin, last_slash_index); + result[last_slash_index] = 0; + } +} + +/*--------------------------------------------------------------------------*/ +/* Function to locate the executable currently running. */ +static int kwsys_shared_forward_self_path(const char* argv0, char* result) +{ + /* Check whether argv0 has a slash. */ + int has_slash = 0; + const char* p = argv0; + for(;*p && !has_slash; ++p) + { + if(*p == '/') + { + has_slash = 1; + } + } + + if(has_slash) + { + /* There is a slash. Use the dirname of the given location. */ + kwsys_shared_forward_dirname(argv0, result); + return 1; + } + else + { + /* There is no slash. Search the PATH for the executable. */ + const char* path = getenv("PATH"); + const char* begin = path; + const char* end = begin + (begin?strlen(begin):0); + const char* first = begin; + while(first != end) + { + /* Store the end of this path entry. */ + const char* last; + + /* Skip all path separators. */ + for(;*first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first); + + /* Find the next separator. */ + for(last = first;*last && *last != KWSYS_SHARED_FORWARD_PATH_SEP; ++last); + + /* If we got a non-empty directory, look for the executable there. */ + if(first < last) + { + /* Determine the length without trailing slash. */ + int length = last-first; + if(*(last-1) == '/') + { + --length; + } + + /* Construct the name of the executable in this location. */ + strncpy(result, first, length); + result[length] = '/'; + strcpy(result+(length)+1, argv0); + + /* Check if it exists. */ + if(access(result, X_OK) == 0) + { + /* Found it. */ + result[length] = 0; + return 1; + } + } + + /* Move to the next directory in the path. */ + first = last; + } + } + + /* We could not find the executable. */ + return 0; +} + +/*--------------------------------------------------------------------------*/ +/* Function to convert a specified path to a full path. If it is not + already full, it is taken relative to the self path. */ +static int kwsys_shared_forward_fullpath(const char* self_path, + const char* in_path, + char* result, + const char* desc) +{ + /* Check the specified path type. */ + if(in_path[0] == '/') + { + /* Already a full path. */ + strcpy(result, in_path); + } + else + { + /* Relative to self path. */ + char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; + strcpy(temp_path, self_path); + strcat(temp_path, "/"); + strcat(temp_path, in_path); + if(!realpath(temp_path, result)) + { + if(desc) + { + fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", + desc, temp_path, strerror(errno)); + } + return 0; + } + } + return 1; +} + +/*--------------------------------------------------------------------------*/ +/* Function to compute the library search path and executable name + based on the self path. */ +static int kwsys_shared_forward_get_settings(const char* self_path, + char* ldpath, char* exe) +{ + /* Possible search paths. */ + static const char* search_path_build[] = {KWSYS_SHARED_FORWARD_PATH_BUILD, 0}; + static const char* search_path_install[] = {KWSYS_SHARED_FORWARD_PATH_INSTALL, 0}; + + /* Chosen paths. */ + const char** search_path; + const char* exe_path; + + /* Get the real name of the build and self paths. */ + char build_path[KWSYS_SHARED_FORWARD_MAXPATH]; + char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; + if(!realpath(self_path, self_path_real)) + { + fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", + self_path, strerror(errno)); + return 0; + } + + /* Check whether we are running in the build tree or an install tree. */ + if(realpath(KWSYS_SHARED_FORWARD_DIR_BUILD, build_path) && + strcmp(self_path_real, build_path) == 0) + { + /* Running in build tree. Use the build path and exe. */ + search_path = search_path_build; + exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; + } + else + { + /* Running in install tree. Use the install path and exe. */ + search_path = search_path_install; + exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; + } + + /* Construct the runtime search path. */ + { + const char** dir; + for(dir = search_path; *dir; ++dir) + { + /* Add seperator between path components. */ + if(dir != search_path) + { + strcat(ldpath, kwsys_shared_forward_path_sep); + } + + /* Add this path component. */ + if(!kwsys_shared_forward_fullpath(self_path, *dir, + ldpath+strlen(ldpath), + "runtime path entry")) + { + return 0; + } + } + } + + /* Construct the executable location. */ + if(!kwsys_shared_forward_fullpath(self_path, exe_path, exe, + "executable file")) + { + return 0; + } + return 1; +} + +/*--------------------------------------------------------------------------*/ +/* Function to print why execution of a command line failed. */ +static void kwsys_shared_forward_print_failure(char** argv, const char* msg) +{ + char** arg = argv; + fprintf(stderr, "Error running"); + for(; *arg; ++arg) + { + fprintf(stderr, " \"%s\"", *arg); + } + fprintf(stderr, ": %s\n", msg); +} + +/* Static storage space to store the updated environment variable. */ +static char kwsys_shared_forward_ldpath[KWSYS_SHARED_FORWARD_MAXPATH*16] = KWSYS_SHARED_FORWARD_LDPATH "="; + +/*--------------------------------------------------------------------------*/ +/* Main driver function to be called from main. */ +static int @KWSYS_NAMESPACE@_shared_forward_to_real(int argc, char** argv) +{ + /* Get the directory containing this executable. */ + char self_path[KWSYS_SHARED_FORWARD_MAXPATH]; + if(kwsys_shared_forward_self_path(argv[0], self_path)) + { + /* Found this executable. Use it to get the library directory. */ + char exe[KWSYS_SHARED_FORWARD_MAXPATH]; + if(kwsys_shared_forward_get_settings(self_path, + kwsys_shared_forward_ldpath, exe)) + { + /* Append the old runtime search path. */ + const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH); + if(old_ldpath) + { + strcat(kwsys_shared_forward_ldpath, kwsys_shared_forward_path_sep); + strcat(kwsys_shared_forward_ldpath, old_ldpath); + } + + /* Store the environment variable. */ + putenv(kwsys_shared_forward_ldpath); + +#if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT) + /* Look for the print command line option. */ + if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) + { + fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath); + fprintf(stdout, "%s\n", exe); + return 0; + } +#endif + +#if defined(KWSYS_SHARED_FORWARD_OPTION_LDD) + /* Look for the ldd command line option. */ + if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) + { + char* ldd_argv[] = {KWSYS_SHARED_FORWARD_LDD, 0, 0}; + ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; + execvp(ldd_argv[0], ldd_argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(ldd_argv, strerror(errno)); + return 1; + } +#endif + + /* Replace this process with the real executable. */ + argv[0] = exe; + execv(argv[0], argv); + + /* Report why execution failed. */ + kwsys_shared_forward_print_failure(argv, strerror(errno)); + } + else + { + /* Could not convert self path to the library directory. */ + } + } + else + { + /* Could not find this executable. */ + fprintf(stderr, "Error locating executable \"%s\".", argv[0]); + } + + /* Avoid unused argument warning. */ + (void)argc; + + /* Exit with failure. */ + return 1; +} + +#else +# error "@KWSYS_NAMESPACE@/SharedForward.h should be included only once." +#endif |