Add a utility function to the d_cosim code model to open dynamic
libraries. It automatically tries adding standard file extensions, so that model lines for d_cosim can be the same for all OSs.
This commit is contained in:
parent
cdbe31868f
commit
beb07ea6df
|
|
@ -62,7 +62,7 @@ struct co_info {
|
||||||
|
|
||||||
void (*out_fn)(struct co_info *, unsigned int, Digital_t *);
|
void (*out_fn)(struct co_info *, unsigned int, Digital_t *);
|
||||||
void *handle; // Co-simulator's private handle
|
void *handle; // Co-simulator's private handle
|
||||||
volatile double vtime; // Time in the co-simulation.
|
volatile double vtime; // Time in the co-simulation.
|
||||||
Cosim_method method; // May be set in Cosim_setup;
|
Cosim_method method; // May be set in Cosim_setup;
|
||||||
|
|
||||||
/* Arguments for the co-simulator shim and the simulation itself
|
/* Arguments for the co-simulator shim and the simulation itself
|
||||||
|
|
@ -73,6 +73,10 @@ struct co_info {
|
||||||
int sim_argc;
|
int sim_argc;
|
||||||
const char * const * const lib_argv;
|
const char * const * const lib_argv;
|
||||||
const char * const * const sim_argv;
|
const char * const * const sim_argv;
|
||||||
|
|
||||||
|
/* Utility function for access to dynamic libraries. */
|
||||||
|
|
||||||
|
void *(*dlopen_fn)(const char *fn);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void Cosim_setup(struct co_info *pinfo); // This must exist.
|
extern void Cosim_setup(struct co_info *pinfo); // This must exist.
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,15 @@ char *dlerror(void) // Lifted from dev.c.
|
||||||
if (rc == 0) { /* FormatMessage failed */
|
if (rc == 0) { /* FormatMessage failed */
|
||||||
(void) sprintf(errstr, errstr_fmt, (unsigned long) GetLastError());
|
(void) sprintf(errstr, errstr_fmt, (unsigned long) GetLastError());
|
||||||
} else {
|
} else {
|
||||||
snprintf(errstr, sizeof errstr, "%s", lpMsgBuf);
|
snprintf(errstr, sizeof errstr, "%s", (char *)lpMsgBuf);
|
||||||
LocalFree(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
}
|
}
|
||||||
return errstr;
|
return errstr;
|
||||||
} /* end of function dlerror */
|
} /* end of function dlerror */
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ngspice/cosim.h"
|
#include "ngspice/cosim.h"
|
||||||
|
|
@ -109,6 +111,60 @@ static void callback(ARGS, Mif_Callback_Reason_t reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A utility function used to open static libraries, trying an installation
|
||||||
|
* directory and different file extenstions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (__MINGW32__) || defined (__CYGWIN__) || defined (_MSC_VER)
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
static const char *exts[] = { "", ".so", ".DLL", NULL};
|
||||||
|
#define CMPFN _stricmp // Ignores case.
|
||||||
|
#define TESTFN(f) (_access(f, 4) == 0) // Checks for read access.
|
||||||
|
#define SLIBFILE "DLL"
|
||||||
|
#ifndef NGSPICELIBDIR
|
||||||
|
#define NGSPICELIBDIR "C:\\Spice64\\lib\\ngspice" // Defined by configure?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const char *exts[] = { "", ".so", NULL};
|
||||||
|
#define CMPFN strcmp
|
||||||
|
#define TESTFN(f) (access(f, R_OK) == 0)
|
||||||
|
#define SLIBFILE "shared library"
|
||||||
|
#endif
|
||||||
|
#define FLAGS (RTLD_GLOBAL | RTLD_NOW)
|
||||||
|
|
||||||
|
static void *cosim_dlopen(const char *fn)
|
||||||
|
{
|
||||||
|
const char **xp;
|
||||||
|
size_t l1, l2;
|
||||||
|
void *handle;
|
||||||
|
char path[2048];
|
||||||
|
|
||||||
|
l1 = strlen(fn);
|
||||||
|
for (xp = exts; *xp; xp++) {
|
||||||
|
l2 = strlen(*xp);
|
||||||
|
if (l2 && l1 > l2 && !CMPFN(*xp, fn + l1 - l2))
|
||||||
|
continue; // Extension already present
|
||||||
|
snprintf(path, sizeof path, "%s%s", fn, *xp);
|
||||||
|
handle = dlopen(path, FLAGS);
|
||||||
|
if (handle)
|
||||||
|
return handle;
|
||||||
|
if (TESTFN(path)) // File exists.
|
||||||
|
break;
|
||||||
|
snprintf(path, sizeof path, NGSPICELIBDIR "/%s%s", fn, *xp);
|
||||||
|
handle = dlopen(path, FLAGS);
|
||||||
|
if (handle)
|
||||||
|
return handle;
|
||||||
|
if (TESTFN(path))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Cannot open " SLIBFILE " %s: %s\n", path, dlerror());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Function called when a co-simulator output changes.
|
/* Function called when a co-simulator output changes.
|
||||||
* Out-of-range values for bit_num must be ignored.
|
* Out-of-range values for bit_num must be ignored.
|
||||||
*/
|
*/
|
||||||
|
|
@ -409,11 +465,9 @@ void ucm_d_cosim(ARGS)
|
||||||
/* Load the shared library containing the co-simulator. */
|
/* Load the shared library containing the co-simulator. */
|
||||||
|
|
||||||
fn = PARAM(simulation);
|
fn = PARAM(simulation);
|
||||||
handle = dlopen(fn, RTLD_GLOBAL | RTLD_NOW);
|
handle = cosim_dlopen(fn);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
cm_message_send("Failed to load simulation binary. "
|
cm_message_send("d_cosim failed to load simulation binary.");
|
||||||
"Try setting LD_LIBRARY_PATH.");
|
|
||||||
cm_message_send(dlerror());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ifp = (void (*)(struct co_info *))dlsym(handle, "Cosim_setup");
|
ifp = (void (*)(struct co_info *))dlsym(handle, "Cosim_setup");
|
||||||
|
|
@ -432,6 +486,7 @@ void ucm_d_cosim(ARGS)
|
||||||
ip->so_handle = handle;
|
ip->so_handle = handle;
|
||||||
ip->info.vtime = 0.0;
|
ip->info.vtime = 0.0;
|
||||||
ip->info.out_fn = accept_output;
|
ip->info.out_fn = accept_output;
|
||||||
|
ip->info.dlopen_fn = cosim_dlopen;
|
||||||
CALLBACK = callback;
|
CALLBACK = callback;
|
||||||
|
|
||||||
if (PARAM_NULL(lib_args)) {
|
if (PARAM_NULL(lib_args)) {
|
||||||
|
|
|
||||||
|
|
@ -285,15 +285,10 @@ void Cosim_setup(struct co_info *pinfo)
|
||||||
if (pinfo->lib_argc > 0 && pinfo->lib_argv[0][0]) // Explicit path to VVP?
|
if (pinfo->lib_argc > 0 && pinfo->lib_argv[0][0]) // Explicit path to VVP?
|
||||||
file = (char *)pinfo->lib_argv[0];
|
file = (char *)pinfo->lib_argv[0];
|
||||||
else //libvvp is assumed to be in the OS search path.
|
else //libvvp is assumed to be in the OS search path.
|
||||||
#if defined(__MINGW32__) || defined(_MSC_VER)
|
file = "libvvp";
|
||||||
file = "libvvp.DLL";
|
context->vvp_handle = pinfo->dlopen_fn(file);
|
||||||
#else
|
|
||||||
file = "libvvp.so";
|
|
||||||
#endif
|
|
||||||
context->vvp_handle = dlopen(file, RTLD_GLOBAL | RTLD_NOW);
|
|
||||||
if (!context->vvp_handle) {
|
if (!context->vvp_handle) {
|
||||||
fprintf(stderr, "Icarus shim failed to load VVP library: %s.\n",
|
fprintf(stderr, "Icarus shim failed to load VVP library\n");
|
||||||
dlerror());
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue