/[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 818 - (show annotations) (download) (as text)
Wed Aug 16 12:54:08 2006 UTC (15 years, 10 months ago) by johnpye
File MIME type: text/x-csrc
File size: 18197 byte(s)
Renamed the installer from 'ASCEND PyGTK' to 'ASCEND'
Added the '-y' to YACCFLAGS and '-l' TO LEXFLAGS.
Other changes are trivial.
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