| /*============================================================================ |
| KWSys - Kitware System Library |
| Copyright 2000-2009 Kitware, Inc., Insight Software Consortium |
| |
| Distributed under the OSI-approved BSD License (the "License"); |
| see accompanying file Copyright.txt for details. |
| |
| This software is distributed WITHOUT ANY WARRANTY; without even the |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the License 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: |
| |
| #if defined(CMAKE_INTDIR) |
| # define CONFIG_DIR_PRE CMAKE_INTDIR "/" |
| # define CONFIG_DIR_POST "/" CMAKE_INTDIR |
| #else |
| # define CONFIG_DIR_PRE "" |
| # define CONFIG_DIR_POST "" |
| #endif |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_EXE_INSTALL "../lib/foo-1.2/foo-real" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND "--command" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_PRINT "--print" |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_LDD "--ldd" |
| #if defined(CMAKE_INTDIR) |
| # define @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR |
| #endif |
| #include <@KWSYS_NAMESPACE@/SharedForward.h> |
| int main(int argc, char** argv) |
| { |
| return @KWSYS_NAMESPACE@_shared_forward_to_real(argc, argv); |
| } |
| |
| Specify search and executable paths relative to the forwarding |
| executable location or as full paths. Include no trailing slash. |
| In the case of a multi-configuration build, when CMAKE_INTDIR is |
| defined, the DIR_BUILD setting should point at the directory above |
| the executable (the one containing the per-configuration |
| subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries |
| and EXE_BUILD should be specified relative to this location and use |
| CMAKE_INTDIR as necessary. In the above example imagine appending |
| the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The |
| result should form a valid path with per-configuration subdirectory. |
| |
| Additional paths may be specified in the PATH_BUILD and PATH_INSTALL |
| variables by using comma-separated strings. For example: |
| |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_BUILD \ |
| "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST |
| #define @KWSYS_NAMESPACE@_SHARED_FORWARD_PATH_INSTALL \ |
| "../lib/foo-1.2", "../lib/bar-4.5" |
| |
| See the comments below for specific explanations of each macro. |
| */ |
| |
| /*--------------------------------------------------------------------------*/ |
| |
| /* 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 |
| |
| /* The configuration name with which this executable was built (Debug/Release). */ |
| #if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME) |
| # define KWSYS_SHARED_FORWARD_CONFIG_NAME @KWSYS_NAMESPACE@_SHARED_FORWARD_CONFIG_NAME |
| #else |
| # undef KWSYS_SHARED_FORWARD_CONFIG_NAME |
| #endif |
| |
| /* Create command line option to replace executable. */ |
| #if defined(@KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND) |
| # if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND) |
| # define KWSYS_SHARED_FORWARD_OPTION_COMMAND @KWSYS_NAMESPACE@_SHARED_FORWARD_OPTION_COMMAND |
| # endif |
| #else |
| # undef KWSYS_SHARED_FORWARD_OPTION_COMMAND |
| #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 <stddef.h> /* size_t */ |
| #include <limits.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <stdio.h> |
| |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| # include <io.h> |
| # include <windows.h> |
| # include <process.h> |
| # define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */ |
| #else |
| # include <unistd.h> |
| # include <sys/stat.h> |
| #endif |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Configuration for this platform. */ |
| |
| /* The path separator for this platform. */ |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| # define KWSYS_SHARED_FORWARD_PATH_SEP ';' |
| # define KWSYS_SHARED_FORWARD_PATH_SLASH '\\' |
| #else |
| # define KWSYS_SHARED_FORWARD_PATH_SEP ':' |
| # define KWSYS_SHARED_FORWARD_PATH_SLASH '/' |
| #endif |
| static const char kwsys_shared_forward_path_sep[2] = {KWSYS_SHARED_FORWARD_PATH_SEP, 0}; |
| static const char kwsys_shared_forward_path_slash[2] = {KWSYS_SHARED_FORWARD_PATH_SLASH, 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" |
| |
| /* FreeBSD */ |
| #elif defined(__FreeBSD__) |
| # define KWSYS_SHARED_FORWARD_LDD "ldd" |
| # define KWSYS_SHARED_FORWARD_LDD_N 1 |
| # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" |
| |
| /* OpenBSD */ |
| #elif defined(__OpenBSD__) |
| # define KWSYS_SHARED_FORWARD_LDD "ldd" |
| # define KWSYS_SHARED_FORWARD_LDD_N 1 |
| # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" |
| |
| /* OSX */ |
| #elif defined(__APPLE__) |
| # define KWSYS_SHARED_FORWARD_LDD "otool", "-L" |
| # define KWSYS_SHARED_FORWARD_LDD_N 2 |
| # define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH" |
| |
| /* AIX */ |
| #elif defined(_AIX) |
| # define KWSYS_SHARED_FORWARD_LDD "dump", "-H" |
| # define KWSYS_SHARED_FORWARD_LDD_N 2 |
| # define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH" |
| |
| /* SUN */ |
| #elif defined(__sun) |
| # 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 |
| |
| /* HP-UX */ |
| #elif 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 |
| |
| /* SGI MIPS */ |
| #elif 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 |
| |
| /* Cygwin */ |
| #elif defined(__CYGWIN__) |
| # define KWSYS_SHARED_FORWARD_LDD "cygcheck" /* TODO: cygwin 1.7 has ldd */ |
| # define KWSYS_SHARED_FORWARD_LDD_N 1 |
| # define KWSYS_SHARED_FORWARD_LDPATH "PATH" |
| |
| /* Windows */ |
| #elif defined(_WIN32) |
| # define KWSYS_SHARED_FORWARD_LDPATH "PATH" |
| |
| /* Guess on this unknown system. */ |
| #else |
| # define KWSYS_SHARED_FORWARD_LDD "ldd" |
| # define KWSYS_SHARED_FORWARD_LDD_N 1 |
| # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH" |
| #endif |
| |
| #ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV |
| /*--------------------------------------------------------------------------*/ |
| typedef struct kwsys_sf_arg_info_s |
| { |
| const char* arg; |
| int size; |
| int quote; |
| } kwsys_sf_arg_info; |
| |
| /*--------------------------------------------------------------------------*/ |
| static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in) |
| { |
| /* Initialize information. */ |
| kwsys_sf_arg_info info; |
| |
| /* String iterator. */ |
| const char* c; |
| |
| /* Keep track of how many backslashes have been encountered in a row. */ |
| int windows_backslashes = 0; |
| |
| /* Start with the length of the original argument, plus one for |
| either a terminating null or a separating space. */ |
| info.arg = in; |
| info.size = (int)strlen(in) + 1; |
| info.quote = 0; |
| |
| /* Scan the string for characters that require escaping or quoting. */ |
| for(c=in; *c; ++c) |
| { |
| /* Check whether this character needs quotes. */ |
| if(strchr(" \t?'#&<>|^", *c)) |
| { |
| info.quote = 1; |
| } |
| |
| /* On Windows only backslashes and double-quotes need escaping. */ |
| if(*c == '\\') |
| { |
| /* Found a backslash. It may need to be escaped later. */ |
| ++windows_backslashes; |
| } |
| else if(*c == '"') |
| { |
| /* Found a double-quote. We need to escape it and all |
| immediately preceding backslashes. */ |
| info.size += windows_backslashes + 1; |
| windows_backslashes = 0; |
| } |
| else |
| { |
| /* Found another character. This eliminates the possibility |
| that any immediately preceding backslashes will be |
| escaped. */ |
| windows_backslashes = 0; |
| } |
| } |
| |
| /* Check whether the argument needs surrounding quotes. */ |
| if(info.quote) |
| { |
| /* Surrounding quotes are needed. Allocate space for them. */ |
| info.size += 2; |
| |
| /* We must escape all ending backslashes when quoting on windows. */ |
| info.size += windows_backslashes; |
| } |
| |
| return info; |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out) |
| { |
| /* String iterator. */ |
| const char* c; |
| |
| /* Keep track of how many backslashes have been encountered in a row. */ |
| int windows_backslashes = 0; |
| |
| /* Whether the argument must be quoted. */ |
| if(info.quote) |
| { |
| /* Add the opening quote for this argument. */ |
| *out++ = '"'; |
| } |
| |
| /* Scan the string for characters that require escaping or quoting. */ |
| for(c=info.arg; *c; ++c) |
| { |
| /* On Windows only backslashes and double-quotes need escaping. */ |
| if(*c == '\\') |
| { |
| /* Found a backslash. It may need to be escaped later. */ |
| ++windows_backslashes; |
| } |
| else if(*c == '"') |
| { |
| /* Found a double-quote. Escape all immediately preceding |
| backslashes. */ |
| while(windows_backslashes > 0) |
| { |
| --windows_backslashes; |
| *out++ = '\\'; |
| } |
| |
| /* Add the backslash to escape the double-quote. */ |
| *out++ = '\\'; |
| } |
| else |
| { |
| /* We encountered a normal character. This eliminates any |
| escaping needed for preceding backslashes. */ |
| windows_backslashes = 0; |
| } |
| |
| /* Store this character. */ |
| *out++ = *c; |
| } |
| |
| if(info.quote) |
| { |
| /* Add enough backslashes to escape any trailing ones. */ |
| while(windows_backslashes > 0) |
| { |
| --windows_backslashes; |
| *out++ = '\\'; |
| } |
| |
| /* Add the closing quote for this argument. */ |
| *out++ = '"'; |
| } |
| |
| /* Store a terminating null without incrementing. */ |
| *out = 0; |
| |
| return out; |
| } |
| #endif |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Function to convert a logical or relative path to a physical full path. */ |
| static int kwsys_shared_forward_realpath(const char* in_path, char* out_path) |
| { |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| /* Implementation for Windows. */ |
| DWORD n = GetFullPathName(in_path, KWSYS_SHARED_FORWARD_MAXPATH, |
| out_path, 0); |
| return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH; |
| #else |
| /* Implementation for UNIX. */ |
| return realpath(in_path, out_path) != 0; |
| #endif |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| static int kwsys_shared_forward_samepath(const char* file1, const char* file2) |
| { |
| #if defined(_WIN32) |
| int result = 0; |
| HANDLE h1 = CreateFile(file1, GENERIC_READ, FILE_SHARE_READ, NULL, |
| OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); |
| HANDLE h2 = CreateFile(file2, GENERIC_READ, FILE_SHARE_READ, NULL, |
| OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); |
| if(h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) |
| { |
| BY_HANDLE_FILE_INFORMATION fi1; |
| BY_HANDLE_FILE_INFORMATION fi2; |
| GetFileInformationByHandle(h1, &fi1); |
| GetFileInformationByHandle(h2, &fi2); |
| result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && |
| fi1.nFileIndexHigh == fi2.nFileIndexHigh && |
| fi1.nFileIndexLow == fi2.nFileIndexLow); |
| } |
| CloseHandle(h1); |
| CloseHandle(h2); |
| return result; |
| #else |
| struct stat fs1, fs2; |
| return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 && |
| memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 && |
| memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 && |
| fs2.st_size == fs1.st_size); |
| #endif |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Function to report a system error message. */ |
| static void kwsys_shared_forward_strerror(char* message) |
| { |
| #if defined(_WIN32) && !defined(__CYGWIN__) |
| /* Implementation for Windows. */ |
| DWORD original = GetLastError(); |
| DWORD length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | |
| FORMAT_MESSAGE_IGNORE_INSERTS, 0, original, |
| MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| message, KWSYS_SHARED_FORWARD_MAXPATH, 0); |
| if(length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) |
| { |
| /* FormatMessage failed. Use a default message. */ |
| _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH, |
| "Error 0x%X (FormatMessage failed with error 0x%X)", |
| original, GetLastError()); |
| } |
| #else |
| /* Implementation for UNIX. */ |
| strcpy(message, strerror(errno)); |
| #endif |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Functions to execute a child process. */ |
| static void kwsys_shared_forward_execvp(const char* cmd, |
| char const* const* argv) |
| { |
| #ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV |
| /* Count the number of arguments. */ |
| int argc = 0; |
| { |
| char const* const* argvc; |
| for(argvc = argv; *argvc; ++argvc,++argc) {} |
| } |
| |
| /* Create the escaped arguments. */ |
| { |
| char** nargv = (char**)malloc((argc+1) * sizeof(char*)); |
| int i; |
| for(i=0; i < argc; ++i) |
| { |
| kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]); |
| nargv[i] = (char*)malloc(info.size); |
| kwsys_sf_get_arg(info, nargv[i]); |
| } |
| nargv[argc] = 0; |
| |
| /* Replace the command line to be used. */ |
| argv = (char const* const*)nargv; |
| } |
| #endif |
| |
| /* Invoke the child process. */ |
| #if defined(_MSC_VER) |
| _execvp(cmd, argv); |
| #elif defined(__MINGW32__) |
| execvp(cmd, argv); |
| #else |
| execvp(cmd, (char* const*)argv); |
| #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 == '/' || *end == '\\') |
| { |
| last_slash_index = (int)(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, kwsys_shared_forward_path_slash); |
| } |
| #if defined(_WIN32) |
| else if(last_slash_index == 2 && begin[1] == ':') |
| { |
| /* Only one leading drive letter and slash. */ |
| strncpy(result, begin, (size_t)last_slash_index); |
| result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH; |
| result[last_slash_index+1] = 0; |
| } |
| #endif |
| else |
| { |
| /* A non-leading slash. */ |
| strncpy(result, begin, (size_t)last_slash_index); |
| result[last_slash_index] = 0; |
| } |
| } |
| |
| /*--------------------------------------------------------------------------*/ |
| /* Function to check if a file exists and is executable. */ |
| static int kwsys_shared_forward_is_executable(const char* f) |
| { |
| #if defined(_MSC_VER) |
| # define KWSYS_SHARED_FORWARD_ACCESS _access |
| #else |
| # define KWSYS_SHARED_FORWARD_ACCESS access |
| #endif |
| #if defined(X_OK) |
| # define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK |
| #else |
| # define KWSYS_SHARED_FORWARD_ACCESS_OK 04 |
| #endif |
| if(KWSYS_SHARED_FORWARD_ACCESS(f, KWSYS_SHARED_FORWARD_ACCESS_OK) == 0) |
| { |
| return 1; |
| } |
| else |
| { |
| return 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 == '/' || *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. */ |
| size_t length = (size_t)(last-first); |
| if(*(last-1) == '/' || *(last-1) == '\\') |
| { |
| --length; |
| } |
| |
| /* Construct the name of the executable in this location. */ |
| strncpy(result, first, length); |
| result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH; |
| strcpy(result+(length)+1, argv0); |
| |
| /* Check if it exists and is executable. */ |
| if(kwsys_shared_forward_is_executable(result)) |
| { |
| /* 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); |
| } |
| #if defined(_WIN32) |
| else if(in_path[0] && in_path[1] == ':') |
| { |
| /* Already a full path. */ |
| strcpy(result, in_path); |
| } |
| #endif |
| else |
| { |
| /* Relative to self path. */ |
| char temp_path[KWSYS_SHARED_FORWARD_MAXPATH]; |
| strcpy(temp_path, self_path); |
| strcat(temp_path, kwsys_shared_forward_path_slash); |
| strcat(temp_path, in_path); |
| if(!kwsys_shared_forward_realpath(temp_path, result)) |
| { |
| if(desc) |
| { |
| char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; |
| kwsys_shared_forward_strerror(msgbuf); |
| fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", |
| desc, temp_path, msgbuf); |
| } |
| 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. */ |
| #if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) |
| char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME; |
| char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH]; |
| #else |
| char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD; |
| const char* self_path_logical = self_path; |
| #endif |
| char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; |
| char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH]; |
| if(!kwsys_shared_forward_realpath(self_path, self_path_real)) |
| { |
| char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH]; |
| kwsys_shared_forward_strerror(msgbuf); |
| fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n", |
| self_path, msgbuf); |
| return 0; |
| } |
| |
| /* Check whether we are running in the build tree or an install tree. */ |
| if(kwsys_shared_forward_realpath(build_path, build_path_real) && |
| kwsys_shared_forward_samepath(self_path_real, build_path_real)) |
| { |
| /* Running in build tree. Use the build path and exe. */ |
| search_path = search_path_build; |
| #if defined(_WIN32) |
| exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe"; |
| #else |
| exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD; |
| #endif |
| |
| #if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) |
| /* Remove the configuration directory from self_path. */ |
| kwsys_shared_forward_dirname(self_path, self_path_logical); |
| #endif |
| } |
| else |
| { |
| /* Running in install tree. Use the install path and exe. */ |
| search_path = search_path_install; |
| #if defined(_WIN32) |
| exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe"; |
| #else |
| exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL; |
| #endif |
| |
| #if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME) |
| /* Use the original self path directory. */ |
| strcpy(self_path_logical, self_path); |
| #endif |
| } |
| |
| /* Construct the runtime search path. */ |
| { |
| const char** dir; |
| for(dir = search_path; *dir; ++dir) |
| { |
| /* Add separator 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_logical, *dir, |
| ldpath+strlen(ldpath), |
| "runtime path entry")) |
| { |
| return 0; |
| } |
| } |
| } |
| |
| /* Construct the executable location. */ |
| if(!kwsys_shared_forward_fullpath(self_path_logical, 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 const* const* argv) |
| { |
| char msg[KWSYS_SHARED_FORWARD_MAXPATH]; |
| char const* const* arg = argv; |
| kwsys_shared_forward_strerror(msg); |
| 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_in) |
| { |
| char const** argv = (char const**)argv_in; |
| /* 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_COMMAND) |
| /* Look for the command line replacement option. */ |
| if(argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) |
| { |
| if(argc > 2) |
| { |
| /* Use the command line given. */ |
| strcpy(exe, argv[2]); |
| argv += 2; |
| argc -= 2; |
| } |
| else |
| { |
| /* The option was not given an executable. */ |
| fprintf(stderr, "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND |
| " must be followed by a command line.\n"); |
| return 1; |
| } |
| } |
| #endif |
| |
| #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) |
| { |
| # if defined(KWSYS_SHARED_FORWARD_LDD) |
| /* Use the named ldd-like executable and arguments. */ |
| char const* ldd_argv[] = {KWSYS_SHARED_FORWARD_LDD, 0, 0}; |
| ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe; |
| kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv); |
| |
| /* Report why execution failed. */ |
| kwsys_shared_forward_print_failure(ldd_argv); |
| return 1; |
| # else |
| /* We have no ldd-like executable available on this platform. */ |
| fprintf(stderr, "No ldd-like tool is known to this executable.\n"); |
| return 1; |
| # endif |
| } |
| #endif |
| |
| /* Replace this process with the real executable. */ |
| argv[0] = exe; |
| kwsys_shared_forward_execvp(argv[0], argv); |
| |
| /* Report why execution failed. */ |
| kwsys_shared_forward_print_failure(argv); |
| } |
| else |
| { |
| /* Could not convert self path to the library directory. */ |
| } |
| } |
| else |
| { |
| /* Could not find this executable. */ |
| fprintf(stderr, "Error locating executable \"%s\".\n", 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 |