Fix for GitHub issue #121 - correctly determine ivl_root.

Pull request #116 added the ability for the iverilog driver to determine
ivl_root from the location of the iverilog executable (this is needed to
support relocation at the time iverilog is installed). However, the code
did not support the possible variations in the library path name.
This commit is contained in:
Martin Whitaker 2016-08-24 00:00:24 +01:00
parent a2fbdeff78
commit 41075a45e6
1 changed files with 94 additions and 57 deletions

View File

@ -825,69 +825,106 @@ static void add_sft_file(const char *module)
free(file);
}
static void find_ivl_root_failed(const char *reason)
{
fprintf(stderr, "Cannot locate IVL modules : %s\n", reason);
exit(1);
}
static void find_ivl_root(void)
{
#ifdef __MINGW32__
const char *ivl_lib_prefix = "\\lib";
const char *ivl_lib_suffix = "\\ivl" IVL_SUFFIX;
#else
const char *ivl_lib_prefix = IVL_LIB;
const char *ivl_lib_suffix = "/ivl" IVL_SUFFIX;
#endif
ssize_t len = 0;
char *s;
#ifndef __MINGW32__
/* First try the location specified in the build process. */
if (access(IVL_ROOT, F_OK) != -1) {
assert(strlen(IVL_ROOT) < sizeof ivl_root);
strcpy(ivl_root, IVL_ROOT);
return;
}
#endif
/* If that fails, calculate the ivl_root from the path to the
command. This is always necessary on Windows because of the
installation process, but may also be necessary on other OSs
if the package has been relocated.
On Windows we know the command path is formed like this:
$(prefix)\bin\iverilog.exe
The module path in a Windows installation is the path:
$(prefix)\lib\ivl$(suffix)
so we chop the file name and the last directory by
turning the last two \ characters to null. Then we append
the lib\ivl$(suffix) to finish.
On other OSs, we expect the command path to be:
$(prefix)/bin/iverilog
and the module path to be:
$(prefix)/$(lib)/ivl$(suffix)
so we extract the $(prefix) from the command location as for
Windows and the $(lib) from IVL_LIB. This will of course fail
if the user has overridden $(bindir) or $(libdir), but there's
not a lot we can do in that case.
*/
#ifdef __MINGW32__
char tmppath[MAXSIZE];
len = GetModuleFileName(NULL, tmppath, sizeof tmppath);
if (len >= (ssize_t) sizeof ivl_root) {
find_ivl_root_failed("command path exceeds size of string buffer.");
}
/* Convert to a short name to remove any embedded spaces. */
len = GetShortPathName(tmppath, ivl_root, sizeof ivl_root);
#else
len = readlink("/proc/self/exe", ivl_root, sizeof ivl_root);
#endif
if (len >= (ssize_t) sizeof ivl_root) {
find_ivl_root_failed("command path exceeds size of string buffer.");
}
if (len <= 0) {
find_ivl_root_failed("couldn't get command path from OS.");
}
s = strrchr(ivl_root, sep);
if (s == 0) {
find_ivl_root_failed("missing first separator in command path.");
}
*s = 0;
s = strrchr(ivl_root, sep);
if (s == 0) {
find_ivl_root_failed("missing second separator in command path.");
}
*s = 0;
len = s - ivl_root;
s = strrchr(ivl_lib_prefix, sep);
assert(s);
if (len + strlen(s) + strlen(ivl_lib_suffix) >= (ssize_t) sizeof ivl_root) {
find_ivl_root_failed("module path exceeds size of string buffer.");
}
strcat(ivl_root, s);
strcat(ivl_root, ivl_lib_suffix);
}
int main(int argc, char **argv)
{
int e_flag = 0;
int version_flag = 0;
int opt;
/* Calculate the ivl_root from the path to the command. This
is necessary because of the installation process on
Windows (and using some package managers such as conda).
Mostly, it is those darn drive letters, but oh
well. We know the command path is formed like this:
D:\iverilog\bin\iverilog.exe
The module path in a Windows installation is the path:
D:\iverilog\lib\ivl$(suffix)
so we chop the file name and the last directory by
turning the last two \ characters to null. Then we append
the lib\ivl$(suffix) to finish. */
char *s;
#ifdef __MINGW32__
char tmppath[MAXSIZE];
GetModuleFileName(NULL, tmppath, sizeof tmppath);
/* Convert to a short name to remove any embedded spaces. */
GetShortPathName(tmppath, ivl_root, sizeof ivl_root);
#else
ssize_t len = 0;
if (access("/proc/self/exe", F_OK) != -1) {
len = readlink("/proc/self/exe", ivl_root, sizeof ivl_root);
assert(len < (ssize_t) sizeof ivl_root);
/* Terminate the string with a NULL. */
if (len > 0) ivl_root[len] = '\0';
}
/* In a UNIX environment, if /proc/self/exe does not exist or
reading fails, the IVL_ROOT from the Makefile is dependable.
It points to the $prefix/lib/ivl directory, where the
sub-parts are installed. */
if (len <= 0) {
assert(strlen(IVL_ROOT) < sizeof ivl_root);
strcpy(ivl_root, IVL_ROOT);
}
#endif
s = strrchr(ivl_root, sep);
if (s) *s = 0;
else {
fprintf(stderr, "%s: Missing first %c in exe path!\n",
argv[0], sep);
exit(1);
}
s = strrchr(ivl_root, sep);
if (s) *s = 0;
else {
fprintf(stderr, "%s: Missing second %c in exe path!\n",
argv[0], sep);
exit(1);
}
#ifdef __MINGW32__
strcat(ivl_root, "\\lib\\ivl" IVL_SUFFIX);
#else
strcat(ivl_root, "/lib/ivl" IVL_SUFFIX);
#endif
find_ivl_root();
base = ivl_root;
/* Create a temporary file for communicating input parameters