From beb07ea6df55a859c872fb929e5ba39274cd5c86 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Thu, 6 Jun 2024 13:59:16 +0100 Subject: [PATCH] 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. --- src/include/ngspice/cosim.h | 6 ++- src/xspice/icm/digital/d_cosim/cfunc.mod | 65 ++++++++++++++++++++++-- src/xspice/verilog/icarus_shim.c | 11 ++-- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/include/ngspice/cosim.h b/src/include/ngspice/cosim.h index fd198b8b8..8e2249ef3 100644 --- a/src/include/ngspice/cosim.h +++ b/src/include/ngspice/cosim.h @@ -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. diff --git a/src/xspice/icm/digital/d_cosim/cfunc.mod b/src/xspice/icm/digital/d_cosim/cfunc.mod index 84d66ac21..d4135dc0a 100644 --- a/src/xspice/icm/digital/d_cosim/cfunc.mod +++ b/src/xspice/icm/digital/d_cosim/cfunc.mod @@ -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 +#include +#include #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 + +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)) { diff --git a/src/xspice/verilog/icarus_shim.c b/src/xspice/verilog/icarus_shim.c index e1bcb0950..cc427a153 100644 --- a/src/xspice/verilog/icarus_shim.c +++ b/src/xspice/verilog/icarus_shim.c @@ -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(); }