SharedForward.h
Go to the documentation of this file.
1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2  file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
3 #ifndef vtksys_SharedForward_h
4 # define vtksys_SharedForward_h
5 
6 /*
7  This header is used to create a forwarding executable sets up the
8  shared library search path and replaces itself with a real
9  executable. This is useful when creating installations on UNIX with
10  shared libraries that will run from any install directory. Typical
11  usage:
12 
13  #if defined(CMAKE_INTDIR)
14  # define CONFIG_DIR_PRE CMAKE_INTDIR "/"
15  # define CONFIG_DIR_POST "/" CMAKE_INTDIR
16  #else
17  # define CONFIG_DIR_PRE ""
18  # define CONFIG_DIR_POST ""
19  #endif
20  #define vtksys_SHARED_FORWARD_DIR_BUILD "/path/to/foo-build/bin"
21  #define vtksys_SHARED_FORWARD_PATH_BUILD "." CONFIG_DIR_POST
22  #define vtksys_SHARED_FORWARD_PATH_INSTALL "../lib/foo-1.2"
23  #define vtksys_SHARED_FORWARD_EXE_BUILD CONFIG_DIR_PRE "foo-real"
24  #define vtksys_SHARED_FORWARD_EXE_INSTALL
25  "../lib/foo-1.2/foo-real"
26  #define vtksys_SHARED_FORWARD_OPTION_COMMAND "--command"
27  #define vtksys_SHARED_FORWARD_OPTION_PRINT "--print"
28  #define vtksys_SHARED_FORWARD_OPTION_LDD "--ldd"
29  #if defined(CMAKE_INTDIR)
30  # define vtksys_SHARED_FORWARD_CONFIG_NAME CMAKE_INTDIR
31  #endif
32  #include <vtksys/SharedForward.h>
33  int main(int argc, char** argv)
34  {
35  return vtksys_shared_forward_to_real(argc, argv);
36  }
37 
38  Specify search and executable paths relative to the forwarding
39  executable location or as full paths. Include no trailing slash.
40  In the case of a multi-configuration build, when CMAKE_INTDIR is
41  defined, the DIR_BUILD setting should point at the directory above
42  the executable (the one containing the per-configuration
43  subdirectory specified by CMAKE_INTDIR). Then PATH_BUILD entries
44  and EXE_BUILD should be specified relative to this location and use
45  CMAKE_INTDIR as necessary. In the above example imagine appending
46  the PATH_BUILD or EXE_BUILD setting to the DIR_BUILD setting. The
47  result should form a valid path with per-configuration subdirectory.
48 
49  Additional paths may be specified in the PATH_BUILD and PATH_INSTALL
50  variables by using comma-separated strings. For example:
51 
52  #define vtksys_SHARED_FORWARD_PATH_BUILD \
53  "." CONFIG_DIR_POST, "/path/to/bar-build" CONFIG_DIR_POST
54  #define vtksys_SHARED_FORWARD_PATH_INSTALL \
55  "../lib/foo-1.2", "../lib/bar-4.5"
56 
57  See the comments below for specific explanations of each macro.
58 */
59 
60 /* Disable -Wcast-qual warnings since they are too hard to fix in a
61  cross-platform way. */
62 # if defined(__clang__) && defined(__has_warning)
63 # if __has_warning("-Wcast-qual")
64 # pragma clang diagnostic push
65 # pragma clang diagnostic ignored "-Wcast-qual"
66 # endif
67 # endif
68 
69 # if defined(__BORLANDC__) && !defined(__cplusplus)
70 /* Code has no effect; raised by winnt.h in C (not C++) when ignoring an
71  unused parameter using "(param)" syntax (i.e. no cast to void). */
72 # pragma warn - 8019
73 # endif
74 
75 /* Full path to the directory in which this executable is built. Do
76  not include a trailing slash. */
77 # if !defined(vtksys_SHARED_FORWARD_DIR_BUILD)
78 # error "Must define vtksys_SHARED_FORWARD_DIR_BUILD"
79 # endif
80 # if !defined(KWSYS_SHARED_FORWARD_DIR_BUILD)
81 # define KWSYS_SHARED_FORWARD_DIR_BUILD \
82  vtksys_SHARED_FORWARD_DIR_BUILD
83 # endif
84 
85 /* Library search path for build tree. */
86 # if !defined(vtksys_SHARED_FORWARD_PATH_BUILD)
87 # error "Must define vtksys_SHARED_FORWARD_PATH_BUILD"
88 # endif
89 # if !defined(KWSYS_SHARED_FORWARD_PATH_BUILD)
90 # define KWSYS_SHARED_FORWARD_PATH_BUILD \
91  vtksys_SHARED_FORWARD_PATH_BUILD
92 # endif
93 
94 /* Library search path for install tree. */
95 # if !defined(vtksys_SHARED_FORWARD_PATH_INSTALL)
96 # error "Must define vtksys_SHARED_FORWARD_PATH_INSTALL"
97 # endif
98 # if !defined(KWSYS_SHARED_FORWARD_PATH_INSTALL)
99 # define KWSYS_SHARED_FORWARD_PATH_INSTALL \
100  vtksys_SHARED_FORWARD_PATH_INSTALL
101 # endif
102 
103 /* The real executable to which to forward in the build tree. */
104 # if !defined(vtksys_SHARED_FORWARD_EXE_BUILD)
105 # error "Must define vtksys_SHARED_FORWARD_EXE_BUILD"
106 # endif
107 # if !defined(KWSYS_SHARED_FORWARD_EXE_BUILD)
108 # define KWSYS_SHARED_FORWARD_EXE_BUILD \
109  vtksys_SHARED_FORWARD_EXE_BUILD
110 # endif
111 
112 /* The real executable to which to forward in the install tree. */
113 # if !defined(vtksys_SHARED_FORWARD_EXE_INSTALL)
114 # error "Must define vtksys_SHARED_FORWARD_EXE_INSTALL"
115 # endif
116 # if !defined(KWSYS_SHARED_FORWARD_EXE_INSTALL)
117 # define KWSYS_SHARED_FORWARD_EXE_INSTALL \
118  vtksys_SHARED_FORWARD_EXE_INSTALL
119 # endif
120 
121 /* The configuration name with which this executable was built (Debug/Release).
122  */
123 # if defined(vtksys_SHARED_FORWARD_CONFIG_NAME)
124 # define KWSYS_SHARED_FORWARD_CONFIG_NAME \
125  vtksys_SHARED_FORWARD_CONFIG_NAME
126 # else
127 # undef KWSYS_SHARED_FORWARD_CONFIG_NAME
128 # endif
129 
130 /* Create command line option to replace executable. */
131 # if defined(vtksys_SHARED_FORWARD_OPTION_COMMAND)
132 # if !defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
133 # define KWSYS_SHARED_FORWARD_OPTION_COMMAND \
134  vtksys_SHARED_FORWARD_OPTION_COMMAND
135 # endif
136 # else
137 # undef KWSYS_SHARED_FORWARD_OPTION_COMMAND
138 # endif
139 
140 /* Create command line option to print environment setting and exit. */
141 # if defined(vtksys_SHARED_FORWARD_OPTION_PRINT)
142 # if !defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
143 # define KWSYS_SHARED_FORWARD_OPTION_PRINT \
144  vtksys_SHARED_FORWARD_OPTION_PRINT
145 # endif
146 # else
147 # undef KWSYS_SHARED_FORWARD_OPTION_PRINT
148 # endif
149 
150 /* Create command line option to run ldd or equivalent. */
151 # if defined(vtksys_SHARED_FORWARD_OPTION_LDD)
152 # if !defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
153 # define KWSYS_SHARED_FORWARD_OPTION_LDD \
154  vtksys_SHARED_FORWARD_OPTION_LDD
155 # endif
156 # else
157 # undef KWSYS_SHARED_FORWARD_OPTION_LDD
158 # endif
159 
160 /* Include needed system headers. */
161 
162 # include <errno.h>
163 # include <limits.h>
164 # include <stddef.h> /* size_t */
165 # include <stdio.h>
166 # include <stdlib.h>
167 # include <string.h>
168 
169 # if defined(_WIN32) && !defined(__CYGWIN__)
170 # include <windows.h>
171 
172 # include <io.h>
173 # include <process.h>
174 # define KWSYS_SHARED_FORWARD_ESCAPE_ARGV /* re-escape argv for execvp */
175 # else
176 # include <sys/stat.h>
177 # include <unistd.h>
178 # endif
179 
180 /* Configuration for this platform. */
181 
182 /* The path separator for this platform. */
183 # if defined(_WIN32) && !defined(__CYGWIN__)
184 # define KWSYS_SHARED_FORWARD_PATH_SEP ';'
185 # define KWSYS_SHARED_FORWARD_PATH_SLASH '\\'
186 # else
187 # define KWSYS_SHARED_FORWARD_PATH_SEP ':'
188 # define KWSYS_SHARED_FORWARD_PATH_SLASH '/'
189 # endif
190 static const char kwsys_shared_forward_path_sep[2] = {
192 };
193 static const char kwsys_shared_forward_path_slash[2] = {
195 };
196 
197 /* The maximum length of a file name. */
198 # if defined(PATH_MAX)
199 # define KWSYS_SHARED_FORWARD_MAXPATH PATH_MAX
200 # elif defined(MAXPATHLEN)
201 # define KWSYS_SHARED_FORWARD_MAXPATH MAXPATHLEN
202 # else
203 # define KWSYS_SHARED_FORWARD_MAXPATH 16384
204 # endif
205 
206 /* Select the environment variable holding the shared library runtime
207  search path for this platform and build configuration. Also select
208  ldd command equivalent. */
209 
210 /* Linux */
211 # if defined(__linux)
212 # define KWSYS_SHARED_FORWARD_LDD "ldd"
213 # define KWSYS_SHARED_FORWARD_LDD_N 1
214 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
215 
216 /* FreeBSD */
217 # elif defined(__FreeBSD__)
218 # define KWSYS_SHARED_FORWARD_LDD "ldd"
219 # define KWSYS_SHARED_FORWARD_LDD_N 1
220 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
221 
222 /* OpenBSD */
223 # elif defined(__OpenBSD__)
224 # define KWSYS_SHARED_FORWARD_LDD "ldd"
225 # define KWSYS_SHARED_FORWARD_LDD_N 1
226 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
227 
228 /* OS X */
229 # elif defined(__APPLE__)
230 # define KWSYS_SHARED_FORWARD_LDD "otool", "-L"
231 # define KWSYS_SHARED_FORWARD_LDD_N 2
232 # define KWSYS_SHARED_FORWARD_LDPATH "DYLD_LIBRARY_PATH"
233 
234 /* AIX */
235 # elif defined(_AIX)
236 # define KWSYS_SHARED_FORWARD_LDD "dump", "-H"
237 # define KWSYS_SHARED_FORWARD_LDD_N 2
238 # define KWSYS_SHARED_FORWARD_LDPATH "LIBPATH"
239 
240 /* SUN */
241 # elif defined(__sun)
242 # define KWSYS_SHARED_FORWARD_LDD "ldd"
243 # define KWSYS_SHARED_FORWARD_LDD_N 1
244 # include <sys/isa_defs.h>
245 # if defined(_ILP32)
246 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
247 # elif defined(_LP64)
248 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH_64"
249 # endif
250 
251 /* HP-UX */
252 # elif defined(__hpux)
253 # define KWSYS_SHARED_FORWARD_LDD "chatr"
254 # define KWSYS_SHARED_FORWARD_LDD_N 1
255 # if defined(__LP64__)
256 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
257 # else
258 # define KWSYS_SHARED_FORWARD_LDPATH "SHLIB_PATH"
259 # endif
260 
261 /* SGI MIPS */
262 # elif defined(__sgi) && defined(_MIPS_SIM)
263 # define KWSYS_SHARED_FORWARD_LDD "ldd"
264 # define KWSYS_SHARED_FORWARD_LDD_N 1
265 # if _MIPS_SIM == _ABIO32
266 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
267 # elif _MIPS_SIM == _ABIN32
268 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARYN32_PATH"
269 # elif _MIPS_SIM == _ABI64
270 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY64_PATH"
271 # endif
272 
273 /* Cygwin */
274 # elif defined(__CYGWIN__)
275 # define KWSYS_SHARED_FORWARD_LDD \
276  "cygcheck" /* TODO: cygwin 1.7 has ldd \
277  */
278 # define KWSYS_SHARED_FORWARD_LDD_N 1
279 # define KWSYS_SHARED_FORWARD_LDPATH "PATH"
280 
281 /* Windows */
282 # elif defined(_WIN32)
283 # define KWSYS_SHARED_FORWARD_LDPATH "PATH"
284 
285 /* Guess on this unknown system. */
286 # else
287 # define KWSYS_SHARED_FORWARD_LDD "ldd"
288 # define KWSYS_SHARED_FORWARD_LDD_N 1
289 # define KWSYS_SHARED_FORWARD_LDPATH "LD_LIBRARY_PATH"
290 # endif
291 
292 # ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
293 typedef struct kwsys_sf_arg_info_s
294 {
295  const char* arg;
296  int size;
297  int quote;
298 } kwsys_sf_arg_info;
299 
300 static kwsys_sf_arg_info kwsys_sf_get_arg_info(const char* in)
301 {
302  /* Initialize information. */
303  kwsys_sf_arg_info info;
304 
305  /* String iterator. */
306  const char* c;
307 
308  /* Keep track of how many backslashes have been encountered in a row. */
309  int windows_backslashes = 0;
310 
311  /* Start with the length of the original argument, plus one for
312  either a terminating null or a separating space. */
313  info.arg = in;
314  info.size = (int)strlen(in) + 1;
315  info.quote = 0;
316 
317  /* Scan the string for characters that require escaping or quoting. */
318  for (c = in; *c; ++c) {
319  /* Check whether this character needs quotes. */
320  if (strchr(" \t?'#&<>|^", *c)) {
321  info.quote = 1;
322  }
323 
324  /* On Windows only backslashes and double-quotes need escaping. */
325  if (*c == '\\') {
326  /* Found a backslash. It may need to be escaped later. */
327  ++windows_backslashes;
328  } else if (*c == '"') {
329  /* Found a double-quote. We need to escape it and all
330  immediately preceding backslashes. */
331  info.size += windows_backslashes + 1;
332  windows_backslashes = 0;
333  } else {
334  /* Found another character. This eliminates the possibility
335  that any immediately preceding backslashes will be
336  escaped. */
337  windows_backslashes = 0;
338  }
339  }
340 
341  /* Check whether the argument needs surrounding quotes. */
342  if (info.quote) {
343  /* Surrounding quotes are needed. Allocate space for them. */
344  info.size += 2;
345 
346  /* We must escape all ending backslashes when quoting on windows. */
347  info.size += windows_backslashes;
348  }
349 
350  return info;
351 }
352 
353 static char* kwsys_sf_get_arg(kwsys_sf_arg_info info, char* out)
354 {
355  /* String iterator. */
356  const char* c;
357 
358  /* Keep track of how many backslashes have been encountered in a row. */
359  int windows_backslashes = 0;
360 
361  /* Whether the argument must be quoted. */
362  if (info.quote) {
363  /* Add the opening quote for this argument. */
364  *out++ = '"';
365  }
366 
367  /* Scan the string for characters that require escaping or quoting. */
368  for (c = info.arg; *c; ++c) {
369  /* On Windows only backslashes and double-quotes need escaping. */
370  if (*c == '\\') {
371  /* Found a backslash. It may need to be escaped later. */
372  ++windows_backslashes;
373  } else if (*c == '"') {
374  /* Found a double-quote. Escape all immediately preceding
375  backslashes. */
376  while (windows_backslashes > 0) {
377  --windows_backslashes;
378  *out++ = '\\';
379  }
380 
381  /* Add the backslash to escape the double-quote. */
382  *out++ = '\\';
383  } else {
384  /* We encountered a normal character. This eliminates any
385  escaping needed for preceding backslashes. */
386  windows_backslashes = 0;
387  }
388 
389  /* Store this character. */
390  *out++ = *c;
391  }
392 
393  if (info.quote) {
394  /* Add enough backslashes to escape any trailing ones. */
395  while (windows_backslashes > 0) {
396  --windows_backslashes;
397  *out++ = '\\';
398  }
399 
400  /* Add the closing quote for this argument. */
401  *out++ = '"';
402  }
403 
404  /* Store a terminating null without incrementing. */
405  *out = 0;
406 
407  return out;
408 }
409 # endif
410 
411 /* Function to convert a logical or relative path to a physical full path. */
412 static int kwsys_shared_forward_realpath(const char* in_path, char* out_path)
413 {
414 # if defined(_WIN32) && !defined(__CYGWIN__)
415  /* Implementation for Windows. */
416  DWORD n =
417  GetFullPathNameA(in_path, KWSYS_SHARED_FORWARD_MAXPATH, out_path, 0);
418  return n > 0 && n <= KWSYS_SHARED_FORWARD_MAXPATH;
419 # else
420  /* Implementation for UNIX. */
421  return realpath(in_path, out_path) != 0;
422 # endif
423 }
424 
425 static int kwsys_shared_forward_samepath(const char* file1, const char* file2)
426 {
427 # if defined(_WIN32)
428  int result = 0;
429  HANDLE h1 = CreateFileA(file1, GENERIC_READ, FILE_SHARE_READ, NULL,
430  OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
431  HANDLE h2 = CreateFileA(file2, GENERIC_READ, FILE_SHARE_READ, NULL,
432  OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
433  if (h1 != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE) {
434  BY_HANDLE_FILE_INFORMATION fi1;
435  BY_HANDLE_FILE_INFORMATION fi2;
436  GetFileInformationByHandle(h1, &fi1);
437  GetFileInformationByHandle(h2, &fi2);
438  result = (fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
439  fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
440  fi1.nFileIndexLow == fi2.nFileIndexLow);
441  }
442  CloseHandle(h1);
443  CloseHandle(h2);
444  return result;
445 # else
446  struct stat fs1, fs2;
447  return (stat(file1, &fs1) == 0 && stat(file2, &fs2) == 0 &&
448  memcmp(&fs2.st_dev, &fs1.st_dev, sizeof(fs1.st_dev)) == 0 &&
449  memcmp(&fs2.st_ino, &fs1.st_ino, sizeof(fs1.st_ino)) == 0 &&
450  fs2.st_size == fs1.st_size);
451 # endif
452 }
453 
454 /* Function to report a system error message. */
455 static void kwsys_shared_forward_strerror(char* message)
456 {
457 # if defined(_WIN32) && !defined(__CYGWIN__)
458  /* Implementation for Windows. */
459  DWORD original = GetLastError();
460  DWORD length =
461  FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
462  0, original, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
463  message, KWSYS_SHARED_FORWARD_MAXPATH, 0);
464  if (length < 1 || length > KWSYS_SHARED_FORWARD_MAXPATH) {
465  /* FormatMessage failed. Use a default message. */
466  _snprintf(message, KWSYS_SHARED_FORWARD_MAXPATH,
467  "Error 0x%X (FormatMessage failed with error 0x%X)", original,
468  GetLastError());
469  }
470 # else
471  /* Implementation for UNIX. */
472  strcpy(message, strerror(errno));
473 # endif
474 }
475 
476 /* Functions to execute a child process. */
477 static void kwsys_shared_forward_execvp(const char* cmd,
478  char const* const* argv)
479 {
480 # ifdef KWSYS_SHARED_FORWARD_ESCAPE_ARGV
481  /* Count the number of arguments. */
482  int argc = 0;
483  {
484  char const* const* argvc;
485  for (argvc = argv; *argvc; ++argvc, ++argc) {
486  }
487  }
488 
489  /* Create the escaped arguments. */
490  {
491  char** nargv = (char**)malloc((argc + 1) * sizeof(char*));
492  int i;
493  for (i = 0; i < argc; ++i) {
494  kwsys_sf_arg_info info = kwsys_sf_get_arg_info(argv[i]);
495  nargv[i] = (char*)malloc(info.size);
496  kwsys_sf_get_arg(info, nargv[i]);
497  }
498  nargv[argc] = 0;
499 
500  /* Replace the command line to be used. */
501  argv = (char const* const*)nargv;
502  }
503 # endif
504 
505 /* Invoke the child process. */
506 # if defined(_MSC_VER)
507  _execvp(cmd, argv);
508 # elif defined(__MINGW32__) && !defined(__MINGW64__)
509  execvp(cmd, argv);
510 # else
511  execvp(cmd, (char* const*)argv);
512 # endif
513 }
514 
515 /* Function to get the directory containing the given file or directory. */
516 static void kwsys_shared_forward_dirname(const char* begin, char* result)
517 {
518  /* Find the location of the last slash. */
519  int last_slash_index = -1;
520  const char* end = begin + strlen(begin);
521  for (; begin <= end && last_slash_index < 0; --end) {
522  if (*end == '/' || *end == '\\') {
523  last_slash_index = (int)(end - begin);
524  }
525  }
526 
527  /* Handle each case of the index of the last slash. */
528  if (last_slash_index < 0) {
529  /* No slashes. */
530  strcpy(result, ".");
531  } else if (last_slash_index == 0) {
532  /* Only one leading slash. */
533  strcpy(result, kwsys_shared_forward_path_slash);
534  }
535 # if defined(_WIN32)
536  else if (last_slash_index == 2 && begin[1] == ':') {
537  /* Only one leading drive letter and slash. */
538  strncpy(result, begin, (size_t)last_slash_index);
539  result[last_slash_index] = KWSYS_SHARED_FORWARD_PATH_SLASH;
540  result[last_slash_index + 1] = 0;
541  }
542 # endif
543  else {
544  /* A non-leading slash. */
545  strncpy(result, begin, (size_t)last_slash_index);
546  result[last_slash_index] = 0;
547  }
548 }
549 
550 /* Function to check if a file exists and is executable. */
551 static int kwsys_shared_forward_is_executable(const char* f)
552 {
553 # if defined(_MSC_VER)
554 # define KWSYS_SHARED_FORWARD_ACCESS _access
555 # else
556 # define KWSYS_SHARED_FORWARD_ACCESS access
557 # endif
558 # if defined(X_OK)
559 # define KWSYS_SHARED_FORWARD_ACCESS_OK X_OK
560 # else
561 # define KWSYS_SHARED_FORWARD_ACCESS_OK 04
562 # endif
564  return 1;
565  } else {
566  return 0;
567  }
568 }
569 
570 /* Function to locate the executable currently running. */
571 static int kwsys_shared_forward_self_path(const char* argv0, char* result)
572 {
573  /* Check whether argv0 has a slash. */
574  int has_slash = 0;
575  const char* p = argv0;
576  for (; *p && !has_slash; ++p) {
577  if (*p == '/' || *p == '\\') {
578  has_slash = 1;
579  }
580  }
581 
582  if (has_slash) {
583  /* There is a slash. Use the dirname of the given location. */
584  kwsys_shared_forward_dirname(argv0, result);
585  return 1;
586  } else {
587  /* There is no slash. Search the PATH for the executable. */
588  const char* path = getenv("PATH");
589  const char* begin = path;
590  const char* end = begin + (begin ? strlen(begin) : 0);
591  const char* first = begin;
592  while (first != end) {
593  /* Store the end of this path entry. */
594  const char* last;
595 
596  /* Skip all path separators. */
597  for (; *first && *first == KWSYS_SHARED_FORWARD_PATH_SEP; ++first)
598  ;
599 
600  /* Find the next separator. */
601  for (last = first; *last && *last != KWSYS_SHARED_FORWARD_PATH_SEP;
602  ++last)
603  ;
604 
605  /* If we got a non-empty directory, look for the executable there. */
606  if (first < last) {
607  /* Determine the length without trailing slash. */
608  size_t length = (size_t)(last - first);
609  if (*(last - 1) == '/' || *(last - 1) == '\\') {
610  --length;
611  }
612 
613  /* Construct the name of the executable in this location. */
614  strncpy(result, first, length);
615  result[length] = KWSYS_SHARED_FORWARD_PATH_SLASH;
616  strcpy(result + (length) + 1, argv0);
617 
618  /* Check if it exists and is executable. */
620  /* Found it. */
621  result[length] = 0;
622  return 1;
623  }
624  }
625 
626  /* Move to the next directory in the path. */
627  first = last;
628  }
629  }
630 
631  /* We could not find the executable. */
632  return 0;
633 }
634 
635 /* Function to convert a specified path to a full path. If it is not
636  already full, it is taken relative to the self path. */
637 static int kwsys_shared_forward_fullpath(const char* self_path,
638  const char* in_path, char* result,
639  const char* desc)
640 {
641  /* Check the specified path type. */
642  if (in_path[0] == '/') {
643  /* Already a full path. */
644  strcpy(result, in_path);
645  }
646 # if defined(_WIN32)
647  else if (in_path[0] && in_path[1] == ':') {
648  /* Already a full path. */
649  strcpy(result, in_path);
650  }
651 # endif
652  else {
653  /* Relative to self path. */
654  char temp_path[KWSYS_SHARED_FORWARD_MAXPATH];
655  strcpy(temp_path, self_path);
656  strcat(temp_path, kwsys_shared_forward_path_slash);
657  strcat(temp_path, in_path);
658  if (!kwsys_shared_forward_realpath(temp_path, result)) {
659  if (desc) {
660  char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
662  fprintf(stderr, "Error converting %s \"%s\" to real path: %s\n", desc,
663  temp_path, msgbuf);
664  }
665  return 0;
666  }
667  }
668  return 1;
669 }
670 
671 /* Function to compute the library search path and executable name
672  based on the self path. */
673 static int kwsys_shared_forward_get_settings(const char* self_path,
674  char* ldpath, char* exe)
675 {
676  /* Possible search paths. */
677  static const char* search_path_build[] = { KWSYS_SHARED_FORWARD_PATH_BUILD,
678  0 };
679  static const char* search_path_install[] = {
681  };
682 
683  /* Chosen paths. */
684  const char** search_path;
685  const char* exe_path;
686 
687 /* Get the real name of the build and self paths. */
688 # if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
689  char build_path[] =
690  KWSYS_SHARED_FORWARD_DIR_BUILD "/" KWSYS_SHARED_FORWARD_CONFIG_NAME;
691  char self_path_logical[KWSYS_SHARED_FORWARD_MAXPATH];
692 # else
693  char build_path[] = KWSYS_SHARED_FORWARD_DIR_BUILD;
694  const char* self_path_logical = self_path;
695 # endif
696  char build_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
697  char self_path_real[KWSYS_SHARED_FORWARD_MAXPATH];
698  if (!kwsys_shared_forward_realpath(self_path, self_path_real)) {
699  char msgbuf[KWSYS_SHARED_FORWARD_MAXPATH];
701  fprintf(stderr, "Error converting self path \"%s\" to real path: %s\n",
702  self_path, msgbuf);
703  return 0;
704  }
705 
706  /* Check whether we are running in the build tree or an install tree. */
707  if (kwsys_shared_forward_realpath(build_path, build_path_real) &&
708  kwsys_shared_forward_samepath(self_path_real, build_path_real)) {
709  /* Running in build tree. Use the build path and exe. */
710  search_path = search_path_build;
711 # if defined(_WIN32)
712  exe_path = KWSYS_SHARED_FORWARD_EXE_BUILD ".exe";
713 # else
715 # endif
716 
717 # if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
718  /* Remove the configuration directory from self_path. */
719  kwsys_shared_forward_dirname(self_path, self_path_logical);
720 # endif
721  } else {
722  /* Running in install tree. Use the install path and exe. */
723  search_path = search_path_install;
724 # if defined(_WIN32)
725  exe_path = KWSYS_SHARED_FORWARD_EXE_INSTALL ".exe";
726 # else
728 # endif
729 
730 # if defined(KWSYS_SHARED_FORWARD_CONFIG_NAME)
731  /* Use the original self path directory. */
732  strcpy(self_path_logical, self_path);
733 # endif
734  }
735 
736  /* Construct the runtime search path. */
737  {
738  const char** dir;
739  for (dir = search_path; *dir; ++dir) {
740  /* Add separator between path components. */
741  if (dir != search_path) {
742  strcat(ldpath, kwsys_shared_forward_path_sep);
743  }
744 
745  /* Add this path component. */
746  if (!kwsys_shared_forward_fullpath(self_path_logical, *dir,
747  ldpath + strlen(ldpath),
748  "runtime path entry")) {
749  return 0;
750  }
751  }
752  }
753 
754  /* Construct the executable location. */
755  if (!kwsys_shared_forward_fullpath(self_path_logical, exe_path, exe,
756  "executable file")) {
757  return 0;
758  }
759  return 1;
760 }
761 
762 /* Function to print why execution of a command line failed. */
763 static void kwsys_shared_forward_print_failure(char const* const* argv)
764 {
766  char const* const* arg = argv;
768  fprintf(stderr, "Error running");
769  for (; *arg; ++arg) {
770  fprintf(stderr, " \"%s\"", *arg);
771  }
772  fprintf(stderr, ": %s\n", msg);
773 }
774 
775 /* Static storage space to store the updated environment variable. */
776 static char kwsys_shared_forward_ldpath[65535] =
778 
779 /* Main driver function to be called from main. */
780 static int vtksys_shared_forward_to_real(int argc, char** argv_in)
781 {
782  char const** argv = (char const**)argv_in;
783  /* Get the directory containing this executable. */
784  char self_path[KWSYS_SHARED_FORWARD_MAXPATH];
785  if (kwsys_shared_forward_self_path(argv[0], self_path)) {
786  /* Found this executable. Use it to get the library directory. */
788  if (kwsys_shared_forward_get_settings(self_path,
790  /* Append the old runtime search path. */
791  const char* old_ldpath = getenv(KWSYS_SHARED_FORWARD_LDPATH);
792  if (old_ldpath) {
794  strcat(kwsys_shared_forward_ldpath, old_ldpath);
795  }
796 
797  /* Store the environment variable. */
799 
800 # if defined(KWSYS_SHARED_FORWARD_OPTION_COMMAND)
801  /* Look for the command line replacement option. */
802  if (argc > 1 &&
803  strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_COMMAND) == 0) {
804  if (argc > 2) {
805  /* Use the command line given. */
806  strcpy(exe, argv[2]);
807  argv += 2;
808  argc -= 2;
809  } else {
810  /* The option was not given an executable. */
811  fprintf(stderr,
812  "Option " KWSYS_SHARED_FORWARD_OPTION_COMMAND
813  " must be followed by a command line.\n");
814  return 1;
815  }
816  }
817 # endif
818 
819 # if defined(KWSYS_SHARED_FORWARD_OPTION_PRINT)
820  /* Look for the print command line option. */
821  if (argc > 1 &&
822  strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_PRINT) == 0) {
823  fprintf(stdout, "%s\n", kwsys_shared_forward_ldpath);
824  fprintf(stdout, "%s\n", exe);
825  return 0;
826  }
827 # endif
828 
829 # if defined(KWSYS_SHARED_FORWARD_OPTION_LDD)
830  /* Look for the ldd command line option. */
831  if (argc > 1 && strcmp(argv[1], KWSYS_SHARED_FORWARD_OPTION_LDD) == 0) {
832 # if defined(KWSYS_SHARED_FORWARD_LDD)
833  /* Use the named ldd-like executable and arguments. */
834  char const* ldd_argv[] = { KWSYS_SHARED_FORWARD_LDD, 0, 0 };
835  ldd_argv[KWSYS_SHARED_FORWARD_LDD_N] = exe;
836  kwsys_shared_forward_execvp(ldd_argv[0], ldd_argv);
837 
838  /* Report why execution failed. */
840  return 1;
841 # else
842  /* We have no ldd-like executable available on this platform. */
843  fprintf(stderr, "No ldd-like tool is known to this executable.\n");
844  return 1;
845 # endif
846  }
847 # endif
848 
849  /* Replace this process with the real executable. */
850  argv[0] = exe;
851  kwsys_shared_forward_execvp(argv[0], argv);
852 
853  /* Report why execution failed. */
855  } else {
856  /* Could not convert self path to the library directory. */
857  }
858  } else {
859  /* Could not find this executable. */
860  fprintf(stderr, "Error locating executable \"%s\".\n", argv[0]);
861  }
862 
863  /* Avoid unused argument warning. */
864  (void)argc;
865 
866  /* Exit with failure. */
867  return 1;
868 }
869 
870 /* Restore warning stack. */
871 # if defined(__clang__) && defined(__has_warning)
872 # if __has_warning("-Wcast-qual")
873 # pragma clang diagnostic pop
874 # endif
875 # endif
876 
877 #else
878 # error "vtksys/SharedForward.h should be included only once."
879 #endif
static int kwsys_shared_forward_realpath(const char *in_path, char *out_path)
int
#define KWSYS_SHARED_FORWARD_PATH_SEP
static int kwsys_shared_forward_fullpath(const char *self_path, const char *in_path, char *result, const char *desc)
static void kwsys_shared_forward_print_failure(char const *const *argv)
length
info
static void kwsys_shared_forward_execvp(const char *cmd, char const *const *argv)
#define KWSYS_SHARED_FORWARD_PATH_BUILD
Definition: SharedForward.h:90
#define KWSYS_SHARED_FORWARD_ACCESS_OK
dir
static const char kwsys_shared_forward_path_sep[2]
#define KWSYS_SHARED_FORWARD_LDD_N
#define KWSYS_SHARED_FORWARD_EXE_INSTALL
#define KWSYS_SHARED_FORWARD_EXE_BUILD
size
static void kwsys_shared_forward_strerror(char *message)
#define KWSYS_SHARED_FORWARD_DIR_BUILD
Definition: SharedForward.h:81
static int vtksys_shared_forward_to_real(int argc, char **argv_in)
static int kwsys_shared_forward_samepath(const char *file1, const char *file2)
static void kwsys_shared_forward_dirname(const char *begin, char *result)
#define KWSYS_SHARED_FORWARD_LDD
#define KWSYS_SHARED_FORWARD_ACCESS
static int kwsys_shared_forward_is_executable(const char *f)
static char kwsys_shared_forward_ldpath[65535]
#define KWSYS_SHARED_FORWARD_PATH_SLASH
#define KWSYS_SHARED_FORWARD_PATH_INSTALL
Definition: SharedForward.h:99
static const char kwsys_shared_forward_path_slash[2]
#define KWSYS_SHARED_FORWARD_LDPATH
#define KWSYS_SHARED_FORWARD_MAXPATH
static int kwsys_shared_forward_get_settings(const char *self_path, char *ldpath, char *exe)
static int kwsys_shared_forward_self_path(const char *argv0, char *result)