Ticket #850: loadlib_dots.patch
File loadlib_dots.patch, 13.5 KB (added by jkeenan, 13 years ago) |
---|
-
src/call_list.txt
319 319 320 320 # crypt 321 321 t tt 322 323 v ip 324 v pt 325 i ptpPPi -
src/dynext.c
122 122 123 123 /* 124 124 125 =item C<static STRING*126 get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name)>125 =item C<static char * 126 filestem(char * full_name)> 127 127 128 Return path and handle of a dynamic lib, setting lib_name to just the filestem129 (i.e. without path or extension) as a freshly-allocated Cstring.128 Returns the file stem, no path and no ext of the parameter full_name. stem is a 129 freshly allocated c string. 130 130 131 131 =cut 132 132 133 133 */ 134 134 135 static STRING*136 get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name)135 static char * 136 filestem(char * full_name) 137 137 { 138 STRING *path; 139 char *full_name, *file_name, *file_w_ext = NULL; 140 char *tmp_lib_name, *path_end, *ext_start; 141 const char *err; 138 char * stem; 139 char * path_end; 140 char * extension_loc; 142 141 143 /* Find the pure library name, without path or extension. */ 144 file_name = string_to_cstring(interpreter, lib); 145 tmp_lib_name = file_name; 146 path_end = strrchr(tmp_lib_name, '/'); 142 /* if there's path, remove it */ 143 path_end = strrchr(full_name, '/'); 147 144 if (! path_end) 148 path_end = strrchr(tmp_lib_name, '\\'); 149 if (path_end) 150 tmp_lib_name = path_end+1; 151 *lib_name = malloc(strlen(tmp_lib_name)+1); 152 strcpy(*lib_name, tmp_lib_name); 153 ext_start = strrchr(*lib_name, '.'); 154 if (ext_start) 155 *ext_start = '\0'; 145 path_end = strrchr(full_name, '\\'); 146 if (! path_end) 147 path_end = full_name; 148 else 149 path_end++; 150 /* path_end now points at the first part of full_name that isn't path */ 156 151 157 /* 158 * first, try to add an extension to the file if it has none. 159 */ 160 if (! ext_start) { 161 file_w_ext = malloc(strlen(file_name) + 162 strlen(PARROT_LOAD_EXT) + 1); 163 strcpy(file_w_ext, file_name); 164 strcat(file_w_ext, PARROT_LOAD_EXT); 165 full_name = Parrot_locate_runtime_file(interpreter, file_w_ext, 152 stem = strdup(path_end); 153 154 /* remove extension if there is one */ 155 extension_loc = strrchr(stem, '.'); 156 if (extension_loc) 157 *extension_loc = '\0'; 158 159 return stem; 160 } 161 162 /* 163 164 =item C<static const char * 165 try_load(Interp *interpreter, char *clib, void **handle, STRING **path, char **lib_name)> 166 167 Try loading a the library in clib out of library path or Parrot's runtime 168 paths. Returns a pointer to err on failure, except not found and path is passed 169 by reference and used to return path. Otherwise behavior is the same as 170 get_path 171 172 =cut 173 174 */ 175 176 static const char * 177 try_load(Interp *interpreter, char *clib, void **handle, STRING ** path, char **lib_name) 178 { 179 char *runtime; 180 181 *handle = Parrot_dlopen(clib); 182 if (*handle) { 183 *path = string_from_cstring(interpreter, clib, 0); 184 *lib_name = filestem(clib); 185 } 186 else 187 { 188 const char *err = Parrot_dlerror(); 189 /* FIXME rm: need better way to ignore not found errors */ 190 if (err && !strstr(err, "No such file or directory")) 191 return err; 192 193 runtime = Parrot_locate_runtime_file(interpreter, clib, 166 194 PARROT_RUNTIME_FT_DYNEXT); 167 if (full_name) { 168 *handle = Parrot_dlopen(full_name); 195 if (runtime) 196 { 197 *handle = Parrot_dlopen(runtime); 169 198 if (*handle) { 170 path = string_from_cstring(interpreter, full_name, 0); 171 string_cstring_free(file_name); 172 string_cstring_free(full_name); 173 string_cstring_free(file_w_ext); 174 return path; 199 *path = string_from_cstring(interpreter, runtime, 0); 200 *lib_name = filestem(runtime); 175 201 } 176 err = Parrot_dlerror(); 177 fprintf(stderr, "Couldn't load '%s': %s\n", 178 full_name, err ? err : "unknown reason"); 179 string_cstring_free(file_name); 180 string_cstring_free(full_name); 181 string_cstring_free(file_w_ext); 182 return NULL; 183 } 184 /* 185 * then file.extension w/o prefix 186 */ 187 *handle = Parrot_dlopen(file_w_ext); 188 if (*handle) { 189 path = string_from_cstring(interpreter, file_w_ext, 0); 190 string_cstring_free(file_name); 191 string_cstring_free(file_w_ext); 192 return path; 193 } 194 string_cstring_free(file_w_ext); 195 if (strcmp(PARROT_LOAD_EXT, PARROT_SHARE_EXT)) { 196 file_w_ext = malloc(strlen(file_name) + 197 strlen(PARROT_SHARE_EXT) + 1); 198 strcpy(file_w_ext, file_name); 199 strcat(file_w_ext, PARROT_SHARE_EXT); 200 full_name = Parrot_locate_runtime_file(interpreter, file_w_ext, 201 PARROT_RUNTIME_FT_DYNEXT); 202 if (full_name) { 203 *handle = Parrot_dlopen(full_name); 204 if (*handle) { 205 path = string_from_cstring(interpreter, full_name, 0); 206 string_cstring_free(file_name); 207 string_cstring_free(file_w_ext); 208 return path; 209 } 202 else 203 { 210 204 err = Parrot_dlerror(); 211 fprintf(stderr, "Couldn't load '%s': %s\n", 212 full_name, err ? err : "unknown reason"); 213 string_cstring_free(file_name); 214 string_cstring_free(file_w_ext); 215 return NULL; 205 /* FIXME rm: need better way to ignore not found errors */ 206 if (err && !strstr(err, "No such file or directory")) 207 return err; 216 208 } 217 /*218 * then file.extension w/o prefix219 */220 *handle = Parrot_dlopen(file_w_ext);221 if (*handle) {222 path = string_from_cstring(interpreter, file_w_ext, 0);223 string_cstring_free(file_name);224 string_cstring_free(file_w_ext);225 return path;226 }227 string_cstring_free(file_w_ext);228 209 } 210 string_cstring_free(runtime); 229 211 } 230 /* 231 * finally, try the given file name as is. we still use 232 * Parrot_locate_runtime_file so that (a) relative pathnames are searched in 233 * the standard locations, and (b) the angle of the slashes are adjusted as 234 * required for non-Unix systems. 235 */ 236 full_name = Parrot_locate_runtime_file(interpreter, file_name, 237 PARROT_RUNTIME_FT_DYNEXT); 238 if (full_name) { 239 *handle = Parrot_dlopen(full_name); 240 if (*handle) { 241 path = string_from_cstring(interpreter, full_name, 0); 242 string_cstring_free(file_name); 243 string_cstring_free(full_name); 244 return path; 212 213 return NULL; 214 } 215 216 /* 217 218 =item C<static STRING * 219 get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name)> 220 221 Return path and handle of a dynamic lib, setting lib_name to just the filestem 222 (i.e. without path or extension) as a freshly-allocated C string. 223 224 =cut 225 226 */ 227 228 static STRING * 229 get_path(Interp *interpreter, STRING *lib, void **handle, char **lib_name) 230 { 231 STRING *path = NULL; 232 char *clib = NULL; 233 char *clib_mod = NULL; 234 char *clib_no_ext = NULL; 235 unsigned int i; 236 const char * err; 237 238 clib = string_to_cstring(interpreter, lib); 239 240 /* clear out dlerror in case it hasn't been */ 241 Parrot_dlerror(); 242 243 /* swap slashes if they're backwards */ 244 for (i = 0; i < strlen(clib); i++) 245 #ifdef WIN32 246 if (clib[i] == '/') 247 clib[i] = '\\'; 248 #else 249 if (clib[i] == '\\') 250 clib[i] = '/'; 251 #endif 252 253 /* try to load unmodified */ 254 err = try_load(interpreter, clib, handle, &path, lib_name); 255 if (err) 256 { 257 fprintf(stderr, "Couldn't load '%s': %s\n", clib, err); 258 goto done; 259 } 260 if (path) 261 goto done; 262 263 /* FIXME rm: check for mem_sys_allocate failures and handle them the parrot 264 * way */ 265 266 /* try to add extension */ 267 clib_mod = mem_sys_allocate(strlen(clib) + strlen(PARROT_LOAD_EXT) + 1); 268 strcpy(clib_mod, clib); 269 strcat(clib_mod, PARROT_LOAD_EXT); 270 err = try_load(interpreter, clib_mod, handle, &path, lib_name); 271 if (err) 272 { 273 fprintf(stderr, "Couldn't load '%s': %s\n", clib_mod, err); 274 goto done; 275 } 276 if (path) 277 goto done; 278 279 /* if ext, remove it (since it's apparently wrong) and put right one on */ 280 string_cstring_free(clib_mod); 281 clib_mod = NULL; 282 clib_no_ext = strdup(clib); 283 char *ext_loc = strrchr(clib_no_ext, '.'); 284 if (ext_loc) { 285 *ext_loc = '\0'; 286 clib_mod = mem_sys_allocate(strlen(clib_no_ext) + 287 strlen(PARROT_LOAD_EXT) + 1); 288 strcpy(clib_mod, clib_no_ext); 289 strcat(clib_mod, PARROT_LOAD_EXT); 290 err = try_load(interpreter, clib_mod, handle, &path, lib_name); 291 if (err) 292 { 293 fprintf(stderr, "Couldn't load '%s': %s\n", clib_mod, err); 294 goto done; 245 295 } 296 if (path) 297 goto done; 246 298 } 247 /* 248 * and on windows strip a leading "lib" 249 * [shouldn't this happen in Parrot_locate_runtime_file instead?] 250 */ 251 #ifdef WIN32 252 if (memcmp(file_name, "lib", 3) == 0) { 253 *handle = Parrot_dlopen(file_name + 3); 254 if (*handle) { 255 path = string_from_cstring(interpreter, file_name + 3, 0); 256 string_cstring_free(file_name); 257 return path; 299 300 /* this doesn't work for lib's with path info or the wrong ext, but it's 301 * just duplicating old behavior. it used to be wrapped in win32 ifdef's 302 * but it doesn't hurt to try it */ 303 if (memcmp(clib, "lib", 3) == 0) { 304 err = try_load(interpreter, clib + 3, handle, &path, lib_name); 305 if (err) 306 { 307 fprintf(stderr, "Couldn't load '%s': %s\n", clib + 3, err); 308 goto done; 258 309 } 310 if (path) 311 goto done; 259 312 } 260 #endif 261 err = Parrot_dlerror(); 262 fprintf(stderr, "Couldn't load '%s': %s\n", 263 file_name, err ? err : "unknown reason"); 264 string_cstring_free(file_name); 265 return NULL; 313 314 fprintf(stderr, "Couldn't load '%s': No such file or directory\n", clib); 315 316 done: 317 string_cstring_free(clib); 318 string_cstring_free(clib_mod); 319 string_cstring_free(clib_no_ext); 320 return path; 266 321 } 267 322 268 323 /* -
t/pmc/nci_loadlib.t
1 #! perl -w 2 # Copyright: 2005 The Perl Foundation. All Rights Reserved. 3 # $Id: foo.t 8254 2005-06-02 14:20:39Z leo $ 4 5 =head1 NAME 6 7 t/pmc/nci_loadlib.t - Test loadlib ability to load a library specified in 8 various maners (name, file, w/extension, w/wrong extension, ...) 9 10 =head1 SYNOPSIS 11 12 % perl -Ilib t/pmc/nci_loadlib.t 13 14 =head1 DESCRIPTION 15 16 Tests loadlib library loading 17 18 =cut 19 20 use Parrot::Test; 21 use Parrot::Config; 22 23 # known exts 24 my @exts = qw/.so .dll .dynlib .nothing/; 25 # no ext 26 push @exts, ''; 27 28 my @perms = (); 29 30 # foo out of runtime and with rel win/unix paths (always runs) 31 foreach (@exts) 32 { 33 push @perms, 'foo'.$_, 'runtime/parrot/dynext/foo'.$_, 34 "runtime\\parrot\\dynext\\foo".$_; 35 }; 36 37 # if libm is around use it from path and with full win/unix paths 38 if (-e '/usr/lib/libm.so') 39 { 40 foreach (@exts) 41 { 42 push @perms, 'libm'.$_, '/usr/lib/libm'.$_, "\\usr\\lib\\libm".$_; 43 }; 44 } 45 46 # if gtk's lib happens to be around go ahead and test with it for the '.' tests 47 # path and full win/unix 48 if (-e '/usr/lib/libgtk-x11-2.0.so') 49 { 50 foreach (@exts) 51 { 52 push @perms, 'libgtk-x11-2.0'.$_, '/usr/lib/libgtk-x11-2.0'.$_, 53 "\\usr\\lib\\libgtk-x11-2.0".$_; 54 }; 55 } 56 57 # +2 for the lib removal test, below 58 plan tests => scalar (@perms) + 2; 59 60 # run each of the above permutations constrcuted above 61 foreach (@perms) 62 { 63 pir_output_is(" 64 65 .sub main 66 .local pmc dynlib 67 dynlib = loadlib '$_' 68 unless dynlib goto FAILED 69 print '42' 70 goto DONE 71 FAILED: 72 print 'failed to load $_' 73 DONE: 74 end 75 .end 76 77 ", '42', 'load '.$_); 78 } 79 80 # test out leading lib removal, special b/c we have to have the correct ext 81 pir_output_is(" 82 83 .sub main 84 .local pmc dynlib 85 .local pmc interp 86 .local pmc conf 87 .local string ext 88 .local string libname 89 90 .include 'iglobals.pasm' 91 interp = getinterp 92 conf = interp[.IGLOBALS_CONFIG_HASH] 93 ext = conf['load_ext'] 94 95 libname = concat 'libfoo', ext 96 dynlib = loadlib libname 97 unless dynlib goto FAILED 98 print '42' 99 goto DONE 100 FAILED: 101 print 'failed to load ' 102 print libname 103 DONE: 104 end 105 .end 106 107 ", '42', 'load libfoo, lib removal'); 108 109 pir_output_is(" 110 111 .sub main 112 .local pmc dynlib 113 dynlib = loadlib 'something_that_should_never_exist' 114 unless dynlib goto FAILED 115 print '42' 116 goto DONE 117 FAILED: 118 print 'failed to load something_that_should_never_exist' 119 DONE: 120 end 121 .end 122 123 ", "Couldn't load 'something_that_should_never_exist': No such file or directory 124 failed to load something_that_should_never_exist", 125 'fail to load non-existent');