PageRenderTime 81ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/R-2.15.1/src/unix/dynload.c

#
C | 247 lines | 142 code | 34 blank | 71 comment | 23 complexity | b69b794b4b2e9dc33edc980a649d28d0 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0, CC-BY-SA-4.0, BSD-3-Clause, AGPL-3.0, GPL-2.0, GPL-3.0, LGPL-2.0
  1. /*
  2. * R : A Computer Language for Statistical Data Analysis
  3. * Copyright (C) 1995-1996 Robert Gentleman and Ross Ihaka
  4. * Copyright (C) 1997-2001 The R Core Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, a copy is available at
  18. * http://www.r-project.org/Licenses/
  19. */
  20. /* <UTF8> char here is handled as a whole string */
  21. /* This provides a table of built-in C and Fortran functions.
  22. We include this table, even when we have dlopen and friends.
  23. This is so that the functions are actually loaded at link time. */
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27. #include <Defn.h>
  28. #include <Rdynpriv.h>
  29. #ifdef HAVE_UNISTD_H
  30. #include <unistd.h>
  31. #endif
  32. /* HP-UX 11.0 has dlfcn.h, but according to libtool as of Dec 2001
  33. this support is broken. So we force use of shlib even when dlfcn.h
  34. is available */
  35. # ifdef __hpux
  36. # ifdef HAVE_DL_H
  37. # include "hpdlfcn.c"
  38. # define HAVE_DYNAMIC_LOADING
  39. # endif
  40. # else
  41. # ifdef HAVE_DLFCN_H
  42. # include <dlfcn.h>
  43. # define HAVE_DYNAMIC_LOADING
  44. # endif
  45. # endif
  46. #ifdef HAVE_DYNAMIC_LOADING
  47. static void *loadLibrary(const char *path, int asLocal, int now,
  48. const char *search);
  49. static void closeLibrary(void *handle);
  50. static void deleteCachedSymbols(DllInfo *);
  51. static DL_FUNC R_local_dlsym(DllInfo *info, char const *name);
  52. static void getFullDLLPath(SEXP call, char *buf, const char *path);
  53. static void getSystemError(char *buf, int len);
  54. static int computeDLOpenFlag(int asLocal, int now);
  55. void attribute_hidden InitFunctionHashing()
  56. {
  57. R_osDynSymbol->loadLibrary = loadLibrary;
  58. R_osDynSymbol->dlsym = R_local_dlsym;
  59. R_osDynSymbol->closeLibrary = closeLibrary;
  60. R_osDynSymbol->getError = getSystemError;
  61. R_osDynSymbol->deleteCachedSymbols = deleteCachedSymbols;
  62. R_osDynSymbol->lookupCachedSymbol = Rf_lookupCachedSymbol;
  63. R_osDynSymbol->getFullDLLPath = getFullDLLPath;
  64. }
  65. static void getSystemError(char *buf, int len)
  66. {
  67. strcpy(buf, dlerror());
  68. }
  69. static void *loadLibrary(const char *path, int asLocal, int now,
  70. const char *search)
  71. {
  72. void *handle;
  73. int openFlag = 0;
  74. openFlag = computeDLOpenFlag(asLocal, now);
  75. handle = (void *) dlopen(path,openFlag);
  76. return(handle);
  77. }
  78. static void closeLibrary(HINSTANCE handle)
  79. {
  80. dlclose(handle);
  81. }
  82. /*
  83. If we are caching the native level symbols, this routine
  84. discards the ones from the DLL identified by loc.
  85. This is called as the initial action of DeleteDLL().
  86. */
  87. static void deleteCachedSymbols(DllInfo *dll)
  88. {
  89. #ifdef CACHE_DLL_SYM
  90. int i;
  91. /* Wouldn't a linked list be easier here?
  92. Potentially ruin the contiguity of the memory.
  93. */
  94. for(i = nCPFun - 1; i >= 0; i--)
  95. if(!strcmp(CPFun[i].pkg, dll->name)) {
  96. if(i < nCPFun - 1) {
  97. strcpy(CPFun[i].name, CPFun[--nCPFun].name);
  98. strcpy(CPFun[i].pkg, CPFun[nCPFun].pkg);
  99. CPFun[i].func = CPFun[nCPFun].func;
  100. } else nCPFun--;
  101. }
  102. #endif /* CACHE_DLL_SYM */
  103. }
  104. /*
  105. Computes the flag to be passed as the second argument to dlopen(),
  106. controlling whether the local or global symbol integration
  107. and lazy or eager resolution of the undefined symbols.
  108. The arguments determine which of each of these possibilities
  109. to use and the results are or'ed together. We need a separate
  110. routine to keep things clean(er) because some symbolic constants
  111. may not be defined, such as RTLD_LOCAL on certain Solaris 2.5.1
  112. and Irix 6.4 boxes. In such cases, we emit a warning message and
  113. use the default by not modifying the value of the flag.
  114. Called only by AddDLL().
  115. */
  116. static int computeDLOpenFlag(int asLocal, int now)
  117. {
  118. #if !defined(RTLD_LOCAL) || !defined(RTLD_GLOBAL) || !defined(RTLD_NOW) || !defined(RTLD_LAZY)
  119. static char *warningMessages[] = {
  120. N_("Explicit local dynamic loading not supported on this platform. Using default."),
  121. N_("Explicit global dynamic loading not supported on this platform. Using default."),
  122. N_("Explicit non-lazy dynamic loading not supported on this platform. Using default."),
  123. N_("Explicit lazy dynamic loading not supported on this platform. Using default.")
  124. };
  125. /* Define a local macro for issuing the warnings.
  126. This allows us to redefine it easily so that it only emits the
  127. warning once as in
  128. DL_WARN(i) if(warningMessages[i]) {\
  129. warning(warningMessages[i]); \
  130. warningMessages[i] = NULL; \
  131. }
  132. or to control the emission via the options currently in effect at
  133. call time.
  134. */
  135. # define DL_WARN(i) \
  136. if(asInteger(GetOption1(install("warn"))) == 1 || \
  137. asInteger(GetOption1(install("verbose"))) > 0) \
  138. warning(_(warningMessages[i]))
  139. #endif
  140. int openFlag = 0; /* Default value so no-ops for undefined
  141. flags should do nothing in the
  142. resulting dlopen(). */
  143. if(asLocal != 0) {
  144. #ifndef RTLD_LOCAL
  145. # ifndef __CYGWIN__
  146. DL_WARN(0);
  147. # endif
  148. #else
  149. openFlag = RTLD_LOCAL;
  150. #endif
  151. } else {
  152. #ifndef RTLD_GLOBAL
  153. # ifndef __CYGWIN__
  154. DL_WARN(1);
  155. # endif
  156. #else
  157. openFlag = RTLD_GLOBAL;
  158. #endif
  159. }
  160. if(now != 0) {
  161. #ifndef RTLD_NOW
  162. # ifndef __CYGWIN__
  163. DL_WARN(2);
  164. # endif
  165. #else
  166. openFlag |= RTLD_NOW;
  167. #endif
  168. } else {
  169. #ifndef RTLD_LAZY
  170. # ifndef __CYGWIN__
  171. DL_WARN(3);
  172. # endif
  173. #else
  174. openFlag |= RTLD_LAZY;
  175. #endif
  176. }
  177. return(openFlag);
  178. }
  179. /*
  180. This is the system/OS-specific version for resolving a
  181. symbol in a shared object. A cast would not be legal C.
  182. */
  183. typedef union {void *p; DL_FUNC fn;} fn_ptr;
  184. static DL_FUNC R_local_dlsym(DllInfo *info, char const *name)
  185. {
  186. fn_ptr tmp;
  187. tmp.p = dlsym(info->handle, name);
  188. return tmp.fn;
  189. }
  190. /*
  191. In the future, this will receive an additional argument
  192. which will specify the nature of the symbol expected by the
  193. caller, specifically whether it is for a .C(), .Call(),
  194. .Fortran(), .External(), generic, etc. invocation. This will
  195. reduce the pool of possible symbols in the case of a library
  196. that registers its routines.
  197. */
  198. static void getFullDLLPath(SEXP call, char *buf, const char *path)
  199. {
  200. if(path[0] == '~')
  201. strcpy(buf, R_ExpandFileName(path));
  202. else if(path[0] != '/') {
  203. #ifdef HAVE_GETCWD
  204. if(!getcwd(buf, PATH_MAX))
  205. #endif
  206. errorcall(call, _("cannot get working directory!"));
  207. strcat(buf, "/");
  208. strcat(buf, path);
  209. }
  210. else strcpy(buf, path);
  211. }
  212. #endif /* end of `ifdef HAVE_DYNAMIC_LOADING' */