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:
Giles Atkinson 2024-06-06 13:59:16 +01:00 committed by Holger Vogt
parent cdbe31868f
commit beb07ea6df
3 changed files with 68 additions and 14 deletions

View File

@ -62,7 +62,7 @@ struct co_info {
void (*out_fn)(struct co_info *, unsigned int, Digital_t *);
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;
/* Arguments for the co-simulator shim and the simulation itself
@ -73,6 +73,10 @@ struct co_info {
int sim_argc;
const char * const * const lib_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.

View File

@ -39,13 +39,15 @@ char *dlerror(void) // Lifted from dev.c.
if (rc == 0) { /* FormatMessage failed */
(void) sprintf(errstr, errstr_fmt, (unsigned long) GetLastError());
} else {
snprintf(errstr, sizeof errstr, "%s", lpMsgBuf);
snprintf(errstr, sizeof errstr, "%s", (char *)lpMsgBuf);
LocalFree(lpMsgBuf);
}
return errstr;
} /* end of function dlerror */
#else
#include <dlfcn.h>
#include <unistd.h>
#include <fcntl.h>
#endif
#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.
* 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. */
fn = PARAM(simulation);
handle = dlopen(fn, RTLD_GLOBAL | RTLD_NOW);
handle = cosim_dlopen(fn);
if (!handle) {
cm_message_send("Failed to load simulation binary. "
"Try setting LD_LIBRARY_PATH.");
cm_message_send(dlerror());
cm_message_send("d_cosim failed to load simulation binary.");
return;
}
ifp = (void (*)(struct co_info *))dlsym(handle, "Cosim_setup");
@ -432,6 +486,7 @@ void ucm_d_cosim(ARGS)
ip->so_handle = handle;
ip->info.vtime = 0.0;
ip->info.out_fn = accept_output;
ip->info.dlopen_fn = cosim_dlopen;
CALLBACK = callback;
if (PARAM_NULL(lib_args)) {

View File

@ -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?
file = (char *)pinfo->lib_argv[0];
else //libvvp is assumed to be in the OS search path.
#if defined(__MINGW32__) || defined(_MSC_VER)
file = "libvvp.DLL";
#else
file = "libvvp.so";
#endif
context->vvp_handle = dlopen(file, RTLD_GLOBAL | RTLD_NOW);
file = "libvvp";
context->vvp_handle = pinfo->dlopen_fn(file);
if (!context->vvp_handle) {
fprintf(stderr, "Icarus shim failed to load VVP library: %s.\n",
dlerror());
fprintf(stderr, "Icarus shim failed to load VVP library\n");
abort();
}