/*========================================================================= 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 #include #include #include #include #include /*--------------------------------------------------------------------------*/ /* 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 /* FreeBSD */ #if defined(__FreeBSD__) # 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 # 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