/[ascend]/trunk/base/generic/utilities/ascDynaLoad.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/ascDynaLoad.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 804 - (show annotations) (download) (as text)
Fri Aug 4 05:54:34 2006 UTC (13 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 18203 byte(s)
In slv9, made changes to keep CONOPT from complaining. CMSlv still not working as expected though.
Decreased required version of Bison to 2.0.
Switched search path for CONOPT on Linux to the CONOPT_PATH env var
(LD_LIBRARY_PATH was being interfered with when ASC_DEV=1).
Some other debug message changes.
1 /* ASCEND modelling environment
2 Copyright (C) 2006 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20
21 This file *should* support unix/linux-style systems (dlfcn.h)
22 and Windows.
23
24 Note that under many systems, profiling does not work
25 with dynamic libraries!
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include "ascConfig.h"
32 #include "error.h"
33 #include "ascPrint.h"
34 #include "ascPanic.h"
35 #include "ascMalloc.h"
36 #include "ascDynaLoad.h"
37
38 #include <general/env.h>
39 #include <general/ospath.h>
40 #include <compiler/instance_enum.h>
41 #include <general/list.h>
42 #include <compiler/compiler.h>
43 #include <compiler/extfunc.h>
44
45 typedef int (*ExternalLibraryRegister_fptr_t)(void);
46
47 /*--------------------------------------
48 GENERIC STUFF
49 */
50
51 struct ascend_dlrecord {
52 char *path; /* library name */
53 void *dlreturn; /* return from dlopen */
54 struct ascend_dlrecord *next;
55 };
56
57 /* Linked list of library names & dlopen() return values. */
58 static struct ascend_dlrecord *g_ascend_dllist = NULL;
59
60 /*
61 * Adds a record of the path and handle to the list.
62 * If it fails to do this, returns 1, else 0.
63 */
64 static int AscAddRecord(void *dlreturn, CONST char *path){
65 struct ascend_dlrecord *new;
66 char *keeppath;
67 if (dlreturn == NULL || path == NULL) {
68 return 1;
69 }
70 keeppath = ascstrdup((char *)path);
71 if (keeppath==NULL) return 1;
72 new = ASC_NEW(struct ascend_dlrecord);
73 if (new==NULL) {
74 ascfree(keeppath);
75 return 1;
76 }
77 new->next = g_ascend_dllist; /* insert at head */
78 g_ascend_dllist = new;
79 new->path = keeppath;
80 new->dlreturn = dlreturn;
81 return 0;
82 }
83
84 /*
85 * Finds a record of the path given and returns the associated handle.
86 * If it fails to do this, returns NULL.
87 */
88 static
89 void *AscFindDLRecord(CONST char *path)
90 {
91 struct ascend_dlrecord *new;
92 if (path == NULL) {
93 return NULL;
94 }
95 new = g_ascend_dllist;
96 while (new != NULL && strcmp(new->path,path) != 0) {
97 /* advance new until no more new or new with path found */
98 new = new->next;
99 }
100 return (new != NULL) ? new->dlreturn : NULL;
101 }
102
103 /*
104 * Finds and returns the handle to path, if one matches, and
105 * deletes the record from the list. Returns NULL if not found.
106 */
107 static
108 void *AscDeleteRecord(CONST char *path)
109 {
110 struct ascend_dlrecord *nextptr, *lastptr, *old;
111 void *dlreturn = NULL;
112
113 if ((g_ascend_dllist == NULL) || (NULL == path)) return NULL;
114
115 if (strcmp(path,g_ascend_dllist->path)==0) {
116 /* head case */
117 old = g_ascend_dllist;
118 g_ascend_dllist = old->next;
119 dlreturn = old->dlreturn;
120 ascfree(old->path);
121 ascfree(old);
122 } else {
123 lastptr = g_ascend_dllist;
124 nextptr = lastptr->next;
125 while (nextptr != NULL && strcmp(nextptr->path,path) != 0) {
126 lastptr = nextptr;
127 nextptr = nextptr->next;
128 }
129 /* so either nextptr is NULL and not in list, or nextptr is
130 * what we want to delete and lastptr is the link to it.
131 */
132 if (nextptr != NULL) {
133 old = nextptr;
134 lastptr->next = nextptr->next;
135 dlreturn = old->dlreturn;
136 ascfree(old->path);
137 ascfree(old);
138 }
139 }
140 return dlreturn;
141 }
142
143 /*
144 * Checks the list for a conflicting handle so we can issue
145 * a more helpful warning, if need be, than the standard message.
146 */
147 static
148 void AscCheckDuplicateLoad(CONST char *path)
149 {
150 struct ascend_dlrecord *r;
151
152 if (NULL == path) {
153 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Null path");
154 return;
155 }
156
157 r = g_ascend_dllist;
158 while (r != NULL) {
159 if (strcmp(path,r->path)==0) {
160 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Attempt to load already loaded '%s'.",path);
161 return;
162 }
163 r = r->next;
164 }
165 }
166
167
168 /*-----------------------------------------------
169 WINDOWS
170 */
171 #if defined(__WIN32__)
172 # include <windows.h>
173
174 int Asc_DynamicLoad(CONST char *path, CONST char *initFun){
175 HINSTANCE xlib;
176 ExternalLibraryRegister_fptr_t install = NULL;
177
178 if (NULL == path) {
179 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path\n");
180 return 1;
181 }
182
183 AscCheckDuplicateLoad(path); /* whine if we've see it before */
184 /*
185 * If the named library does not exist, if it's not loadable or if
186 * it does not define the named install proc, report an error
187 */
188
189 xlib = LoadLibrary(path);
190 if (xlib == NULL) {
191 ERROR_REPORTER_HERE(ASC_PROG_ERR,"LoadLibrary failed\n'%s'",path);
192 return 1;
193 }
194 ERROR_REPORTER_HERE(ASC_PROG_NOTE,"LoadLibrary succeeded, '%s'\n",path);
195
196 if (NULL != initFun) {
197 install = (int (*)(void))GetProcAddress(xlib,initFun);
198 if (install == NULL) {
199 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Required function '%s' not found", initFun);
200 (void)FreeLibrary(xlib);
201 return 1;
202 }else{
203 FPRINTF(ASCERR,"FOUND INITFCN %s AT %d\n",initFun,install);
204 }
205 }
206 if (0 != AscAddRecord(xlib,path)) {
207 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)\n",path);
208 }
209 return (install == NULL) ? 0 : (*install)();
210 }
211 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
212
213 # define UNLOAD FreeLibrary
214 # define DLLSYM GetProcAddress
215 # define DLL_CAST (HINSTANCE)
216 # define ASC_DLERRSTRING "unknown"
217 # define UNLOAD_SUCCESS TRUE
218
219 #endif /* __WIN32__ */
220
221 /*-----------------------------------------------
222 UNIX/LINUX
223 */
224 /*
225 SOLARIS and LINUX
226 */
227 /* NOTE, added defined(__unix__) here, not sure if that's a bad thing or not -- johnpye */
228 /*
229 From a quick Google, it appears that AIX 5.1 now provides dlfcn.h,
230 so I'll remove the code that was emulating it here. -- johnpye
231 */
232 #if (defined(sun) || defined(linux) || defined(__unix__) || defined(solaris) || defined(_AIX) || defined(_SGI_SOURCE))
233 # ifndef MACH
234 # include <dlfcn.h>
235 # else
236 # error "MACH unsupported"
237 # endif /* mach */
238
239 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
240 {
241 void *xlib;
242 ExternalLibraryRegister_fptr_t install = NULL;
243
244 if (NULL == path) {
245 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null path");
246 return 1;
247 }
248
249 AscCheckDuplicateLoad(path); /* whine if we've see it before */
250
251 /*
252 * If the named library does not exist, if it's not loadable or if
253 * it does not define the named install proc, report an error
254 */
255 xlib = dlopen(path, 1);
256 if (xlib == NULL) {
257 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
258 return 1;
259 }
260 if (NULL != initFun) {
261 install = (int (*)())dlsym(xlib, initFun);
262 if (install == NULL) {
263 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"%s",(char *)dlerror());
264 dlclose(xlib);
265 return 1;
266 }
267 }
268
269 if (0 != AscAddRecord(xlib,path)) {
270 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path);
271 }
272 return (install == NULL) ? 0 : (*install)();
273 }
274 #define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
275
276 # define UNLOAD dlclose
277 # define DLLSYM dlsym
278 # define DLL_CAST (void *)
279 # define ASC_DLERRSTRING dlerror()
280 # define UNLOAD_SUCCESS 0
281
282 #endif /* posix: linux, unix, solaris,sgi */
283
284 /*-----------------------------------------------
285 HPUX
286 */
287 #ifdef __hpux
288 /*
289 Kirk Abbott last fiddled with the following, which was
290 originally put in place my Michael Moore for an
291 HP/UX 9.X Operating Sys back in 1993. Arrr. No idea if
292 it still works.
293 */
294
295 # include <dl.h>
296 # include <errno.h>
297
298 int Asc_DynamicLoad(CONST char *path, CONST char *initFun)
299 {
300 shl_t xlib;
301 ExternalLibraryRegister_fptr_t install = NULL;
302 int i;
303
304 if (NULL == path) {
305 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null path");
306 return 1;
307 }
308
309 AscCheckDuplicateLoad(path); /* whine if we've see it before */
310
311 /*
312 * If the named library does not exist, if it's not loadable or if
313 * it does not define the named install proc, report an error
314 */
315 xlib = shl_load(path, BIND_IMMEDIATE | BIND_VERBOSE, 0L);
316 if (xlib == (shl_t) NULL) {
317 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to load shared library: %s",strerror(errno));
318 return 1;
319 }
320 if (NULL != initFun) {
321 i = shl_findsym(&xlib, initFun, TYPE_PROCEDURE, &install);
322 if (i == -1) {
323 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s': %s",
324 initFun, strerror(errno));
325 shl_unload(xlib); /* baa */
326 return 1;
327 }
328 if(install == NULL) {
329 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find needed symbol '%s'. Error type unknown",initFun);
330 shl_unload(xlib); /* baa */
331 return 1;
332 }
333 }
334 if (0 != AscAddRecord(xlib,path)) {
335 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to record library (%s)",path);
336 }
337 return (install == NULL) ? 0 : (*install)();
338 }
339 # define ASCDL_OK /* this line should appear inside each Asc_DynamicLoad */
340
341 # define UNLOAD shl_unload
342 # define DLL_CAST (shl_t)
343 # define ASC_DLERRSTRING "NULL definition"
344 # define UNLOAD_SUCCESS 0
345
346 #endif /* __hpux */
347
348 /*-----------------------------------------------
349 Did we get something from the above?
350 */
351
352 #ifndef ASCDL_OK
353 # error "Unable to define an Asc_DynamicLoad function. Check your compiler options and installed system libraries."
354 #endif
355
356 /**-----------------------------------------------
357 DYNAMIC UNLOADING
358 */
359
360 int Asc_DynamicUnLoad(CONST char *path)
361 {
362 void *dlreturn;
363 int retval;
364
365 if (NULL == path) {
366 ERROR_REPORTER_HERE(ASC_PROG_ERR, "Failed: Null path");
367 return -3;
368 }
369
370 dlreturn = AscDeleteRecord(path);
371 if (dlreturn == NULL) {
372 ERROR_REPORTER_HERE(ASC_PROG_ERR, "Unable to remember or unload %s", path);
373 return -3;
374 }
375 CONSOLE_DEBUG("Asc_DynamicUnLoad: forgetting & unloading %s", path);
376 /*
377 * dlclose() returns 0 on success, FreeLibrary() returns TRUE.
378 * A uniform convention is preferable, so trap and return 0 on success.
379 */
380 retval = UNLOAD(DLL_CAST dlreturn);
381 return (retval == UNLOAD_SUCCESS) ? 0 : retval;
382 }
383
384 /**-----------------------------------------------
385 DYNAMIC VARIABLE LINKING
386 */
387 void *Asc_DynamicVariable(CONST char *libname, CONST char *symbol)
388 {
389 void *dlreturn;
390 void *symreturn;
391 #ifdef __hpux
392 int i;
393 #endif
394
395 if (libname == NULL) {
396 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null libname");
397 return NULL;
398 }
399 if (symbol == NULL) {
400 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: Null symbol");
401 return NULL;
402 }
403
404 dlreturn = AscFindDLRecord(libname);
405 if (dlreturn == NULL) {
406 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname);
407 return NULL;
408 }
409 #ifdef __hpux
410 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
411 if (i == -1) {
412 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s (%s)",
413 symbol, libname, strerror(errno));
414 symreturn = NULL;
415 }
416 #elif defined(__WIN32__)
417 /*
418 * Here's a bit of possibly-misdirected casting horror.
419 * ISO C forbids casting between function and data pointers, so, naturally,
420 * we cast between function and data pointers. Well, we don't have much
421 * choice. GetProcAddress() returns a function pointer for both functions
422 * and variables so we have to do the cast for variables. This is ok on
423 * 32 bit Windows since the pointers are compatible. Then, to avoid
424 * being reminded by the compiler that we're doing something illegal,
425 * we apply convoluted casting to shut it up.
426 * Oh, the crap you can find on the internet... JDS
427 */
428 *(FARPROC*)(&symreturn) = GetProcAddress((HINSTANCE)dlreturn, symbol);
429 #else
430 /* no problem on POSIX systems - dlsym() returns a void *. */
431 symreturn = dlsym(dlreturn, symbol);
432 #endif
433 if (symreturn == NULL) {
434 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested symbol '%s' in %s",symbol,libname);
435 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING);
436 }
437 return symreturn;
438 }
439
440 /**-----------------------------------------------
441 DYNAMIC FUNCTION LINKING
442 */
443 DynamicF Asc_DynamicFunction(CONST char *libname, CONST char *symbol)
444 {
445 void *dlreturn;
446 DynamicF symreturn;
447 #ifdef __hpux
448 int i;
449 #endif
450
451 if (libname == NULL) {
452 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null library name");
453 return NULL;
454 }
455 if (symbol == NULL) {
456 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed: null function name");
457 return NULL;
458 }
459
460 dlreturn = AscFindDLRecord(libname);
461 if (dlreturn == NULL) {
462 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested library %s", libname);
463 return NULL;
464 }
465 #ifdef __hpux
466 i = shl_findsym(&dlreturn, symbol, TYPE_UNDEFINED, &symreturn);
467 if (i == -1) {
468 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s (%s)",
469 symbol, libname, strerror(errno));
470 symreturn = NULL;
471 }
472 #elif defined(__WIN32__)
473 /* no problem on Windows - GetProcAddress() returns a function pointer. */
474 symreturn = (DynamicF)GetProcAddress((HINSTANCE)dlreturn, symbol);
475 #else
476 /*
477 * Here's the corresponding bit of possibly-misdirected casting horror.
478 * ISO C forbids casting between function and data pointers, so, naturally,
479 * we cast between function and data pointers. Well, we don't have much
480 * choice. dlsym() returns a void* for both variables and functions so we
481 * have to do the cast for functions. This is ok on POSIX systems since the
482 * pointer types are compatible. Then, to avoid being reminded by the
483 * compiler that we're doing something illegal, we apply convoluted casting
484 * to shut it up. Oh, the crap you can find on the internet... JDS
485 */
486 *(void**)(&symreturn) = dlsym(dlreturn, symbol);
487 #endif
488 if (symreturn == NULL) {
489 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to find requested function '%s' in %s",symbol,libname);
490 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Error type: %s",ASC_DLERRSTRING);
491 }
492 return symreturn;
493 }
494
495
496 /*-----------------------------------------------------------------------------
497 SEARCHING FOR LIBRARIES
498 */
499
500 /**
501 A little structure to help with searching for libraries
502
503 @see test_librarysearch
504 */
505 struct LibrarySearch{
506 struct FilePath *partialpath;
507 char fullpath[PATH_MAX];
508 };
509
510 FilePathTestFn test_librarysearch;
511
512 /**
513 A 'test' function for passing to the ospath_searchpath_iterate function.
514 This test function will return a match when a library having the required
515 name is present in the fully resolved path.
516 */
517 int test_librarysearch(struct FilePath *path, void *userdata){
518 /* user data = the relative path, plus a place
519 to store the full path when found */
520 FILE *f;
521 struct LibrarySearch *ls;
522 struct FilePath *fp;
523
524 ls = (struct LibrarySearch *)userdata;
525 fp = ospath_concat(path,ls->partialpath);
526 if(fp==NULL){
527 char *tmp;
528 tmp = ospath_str(path);
529 CONSOLE_DEBUG("Unable to concatenate '%s'...",tmp);
530 ospath_free_str(tmp);
531 tmp = ospath_str(ls->partialpath);
532 CONSOLE_DEBUG("... and '%s'...",tmp);
533 ospath_free_str(tmp);
534 return 0;
535 }
536
537 ospath_strncpy(fp,ls->fullpath,PATH_MAX);
538 CONSOLE_DEBUG("SEARCHING FOR %s",ls->fullpath);
539
540 f = ospath_fopen(fp,"r");
541 if(f==NULL){
542 ospath_free(fp);
543 return 0;
544 }
545 fclose(f);
546
547 /* ERROR_REPORTER_HERE(ASC_PROG_NOTE,"FOUND! %s\n",ls->fullpath); */
548 ospath_free(fp);
549 return 1;
550 }
551
552 char *SearchArchiveLibraryPath(CONST char *name, char *dpath, char *envv){
553 struct FilePath *fp1, *fp2, *fp3; /* relative path */
554 char *s1;
555 char buffer[PATH_MAX];
556
557 struct LibrarySearch ls;
558 struct FilePath **sp;
559 char *path, *foundpath;
560 ospath_stat_t buf;
561 FILE *f;
562
563 fp1 = ospath_new_noclean(name);
564 if(fp1==NULL){
565 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",name);
566 ospath_free(fp1);
567 return NULL;
568 }
569
570 s1 = ospath_getfilestem(fp1);
571 if(s1==NULL){
572 /* not a file, so fail... */
573 return NULL;
574 }
575
576 fp2 = ospath_getdir(fp1);
577 if(fp2==NULL){
578 ERROR_REPORTER_HERE(ASC_PROG_ERR,"unable to retrieve file dir");
579 return NULL;
580 }
581
582 /* CONSOLE_DEBUG("FILESTEM = '%s'",s1); */
583
584 # if defined(ASC_SHLIBSUFFIX) && defined(ASC_SHLIBPREFIX)
585 /*
586 this is the preferred operation: SCons reports what the local system
587 uses as its shared library file extension.
588 */
589 snprintf(buffer,PATH_MAX,"%s%s%s",ASC_SHLIBPREFIX,s1,ASC_SHLIBSUFFIX);
590 # else
591 /**
592 @DEPRECATED
593
594 If we don't have ASC_SHLIB-SUFFIX and -PREFIX then we can do some
595 system-specific stuff here, but it's not as general.
596 */
597 # ifdef __WIN32__
598 snprintf(buffer,PATH_MAX,"%s.dll",s1);
599 # elif defined(linux)
600 snprintf(buffer,PATH_MAX,"lib%s.so",s1); /* changed from .o to .so -- JP */
601 # elif defined(sun) || defined(solaris)
602 snprintf(buffer,PATH_MAX,"%s.so.1.0",s1);
603 # elif defined(__hpux)
604 snprintf(buffer,PATH_MAX,"%s.sl",s1);
605 # elif defined(_SGI_SOURCE)
606 snprintf(buffer,PATH_MAX,"%s.so",s1);
607 # else
608 # error "Unknown system type (please define ASC_SHLIBSUFFIX and ASC_SHLIBPREFIX)"
609 # endif
610 # endif
611
612 fp3 = ospath_new(buffer);
613 ospath_free(fp1);
614 fp1 = ospath_concat(fp2,fp3);
615 ospath_free(fp2);
616 ospath_free(fp3);
617 ospath_free_str(s1);
618
619 /* attempt to open "name" directly */
620 if(0==ospath_stat(fp1,&buf) && NULL!=(f = ospath_fopen(fp1,"r")) ){
621 char *tmp;
622 tmp = ospath_str(fp1);
623 CONSOLE_DEBUG("Library '%s' opened directly, without path search",tmp);
624 ospath_free_str(tmp);
625 fp2 = ospath_getabs(fp1);
626 foundpath = ospath_str(fp2);
627 ospath_free(fp2);
628 fclose(f);
629 }else{
630
631 ls.partialpath = fp1;
632
633 path=Asc_GetEnv(envv);
634 if(path==NULL){
635 /* CONSOLE_DEBUG("ENV VAR NOT FOUND, FALLING BACK TO DEFAULT SEARCH PATH = '%s'",dpath); */
636 path=dpath;
637 }
638
639 /* CONSOLE_DEBUG("SEARCHPATH IS %s",path); */
640 sp = ospath_searchpath_new(path);
641
642 if(NULL==ospath_searchpath_iterate(sp,&test_librarysearch,&ls)){
643 ospath_free(fp1);
644 ospath_searchpath_free(sp);
645 return NULL;
646 }
647
648 foundpath = ASC_NEW_ARRAY(char,strlen(ls.fullpath)+1);
649 strcpy(foundpath,ls.fullpath);
650 ospath_searchpath_free(sp);
651 }
652
653 ospath_free(fp1);
654 return foundpath;
655 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22