Simplify use of iverilog-vpi under Windows.

iverilog-vpi now automatically finds the IVL root directory,
eliminating the need for the -ivl option. Also, if the MinGW
root path hasn't been added to the registry, it now searches
the system path for it.
This commit is contained in:
Martin Whitaker 2015-05-08 20:15:54 +01:00
parent 45dc13e496
commit 3069b8dd51
1 changed files with 107 additions and 111 deletions

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2002-2015 Gus Baldauf (gus@picturel.com)
* Copyright (c) 2002 Gus Baldauf (gus@picturel.com)
* Copyright (c) 2015 Martin Whitaker
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -20,7 +21,7 @@
/*
* iverilog-vpi.c
*
* this program provides the functionality of iverilog-vpi.sh under Win32
* this program provides the functionality of iverilog-vpi.sh under Windows
*/
#include <stdio.h>
@ -52,8 +53,8 @@ static struct global_strings {
char *pIVL; /* path to IVL directory */
char *pCCFLAGS; /* compiler flags for compiling C source files */
char *pCXFLAGS; /* compiler flags for compiling C++ source files */
char *pLDLIBS; /* LDLIBS option */
char *pNewPath; /* new PATH environment variable setting */
char *pLDLIBS; /* linker flags for final linking stage */
char *pCCNAME; /* base name of compiler */
char *pLD; /* what to use for a linker */
} gstr;
@ -79,8 +80,8 @@ static void myExit(int exitVal)
deInitDynString(gstr.pCCFLAGS);
deInitDynString(gstr.pCXFLAGS);
deInitDynString(gstr.pLDLIBS);
deInitDynString(gstr.pNewPath);
free(gstr.pLD);
deInitDynString(gstr.pCCNAME);
deInitDynString(gstr.pLD);
exit(exitVal);
}
@ -89,9 +90,8 @@ static void myExit(int exitVal)
static void usage(void)
{
fprintf(stderr,"usage: iverilog-vpi" IVERILOG_SUFFIX " [src and obj files]...\n");
fprintf(stderr,"usage: iverilog-vpi" IVERILOG_SUFFIX " [options] [src and obj files]...\n");
fprintf(stderr," or iverilog-vpi" IVERILOG_SUFFIX " -mingw=dir\n");
fprintf(stderr," or iverilog-vpi" IVERILOG_SUFFIX " -ivl=dir\n");
myExit(1);
}
@ -111,6 +111,8 @@ static void initDynString(char **str)
static void init(void)
{
char *ptr;
initDynString(&gstr.pCCSRC);
initDynString(&gstr.pCXSRC);
initDynString(&gstr.pOBJ);
@ -123,7 +125,14 @@ static void init(void)
initDynString(&gstr.pCCFLAGS);
initDynString(&gstr.pCXFLAGS);
initDynString(&gstr.pLDLIBS);
initDynString(&gstr.pNewPath);
initDynString(&gstr.pCCNAME);
initDynString(&gstr.pLD);
/* Get the base name of the C compiler. */
assign(&gstr.pCCNAME, IVERILOG_VPI_CC);
ptr = strchr(gstr.pCCNAME, ' ');
if (ptr != NULL) *ptr = '\0';
/* By default use the C compiler to link the programs. */
assign(&gstr.pLD, IVERILOG_VPI_CC);
}
@ -265,19 +274,22 @@ static int GetRegistryKey(char *key, char **value)
static void SetRegistryKey(char *key, char *value)
{
long lrv;
HKEY hkKey;
DWORD res;
if (RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
"Software\\Icarus Verilog",
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,NULL,
&hkKey,
&res) != ERROR_SUCCESS)
return;
lrv = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Icarus Verilog", 0, "",
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkKey, &res);
if (lrv != ERROR_SUCCESS) {
char message[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, lrv, LANG_USER_DEFAULT,
message, sizeof(message), NULL);
fprintf(stderr, "error: couldn't write to registry - %s\n", message);
if (lrv == ERROR_ACCESS_DENIED) {
fprintf(stderr, " try running as administrator\n");
}
return;
}
/* This needs an unsigned char *, but for MinGW the char is signed. */
RegSetValueEx(hkKey, key, 0, REG_SZ, (unsigned char *) value,
@ -302,7 +314,6 @@ static int parse(int argc, char *argv[])
char lib_option[] = "-l";
char inc_option[] = "-I";
char mingw_option[] = "-mingw=";
char ivl_option[] = "-ivl=";
char def_option[] = "-D";
if (argc == 1) return 0;
@ -352,10 +363,6 @@ static int parse(int argc, char *argv[])
else if (startsWith(mingw_option, argv[idx]))
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
strlen(argv[idx])-(sizeof(mingw_option)-1));
/* Check for the -ivl option */
else if (startsWith(ivl_option, argv[idx]))
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
strlen(argv[idx])-(sizeof(ivl_option)-1));
/* Check for the --name option */
else if (startsWith(name_option, argv[idx])) {
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
@ -396,7 +403,7 @@ static int parse(int argc, char *argv[])
/* Check for the --install-dir option */
else if (stricmp("--install-dir", argv[idx]) == 0) {
setup_ivl_environment();
printf("%s\\\\lib\\\\ivl" IVERILOG_SUFFIX "\\\\.\n", gstr.pIVL);
printf("%s\\lib\\ivl" IVERILOG_SUFFIX "\\.\n", gstr.pIVL);
myExit(0);
}
/* This is different than iverilog-vpi.sh, we don't
@ -407,13 +414,14 @@ static int parse(int argc, char *argv[])
/* In case there is a --name without source/object files */
if (0 == srcFileCnt) assign(&gstr.pOUT,"");
/* Normally it's an error if there are no source or object files */
/* Unless we are setting the IVL or MinGW registry entries */
if (!*gstr.pOUT) {
if (!*gstr.pMINGW && !*gstr.pIVL) return 0;
} else
if (*gstr.pOUT) {
/* We have a valid result file so add the .vpi extension */
append(&gstr.pOUT, ".vpi");
} else {
/* Unless we are setting the MinGW registry entry, it's
an error if there are no source or object files */
if (!*gstr.pMINGW) return 0;
}
return 1;
}
@ -424,26 +432,22 @@ static void checkMingwDir(char *root)
{
int irv;
struct _stat stat_buf;
char *path;
char *path, *comp, *cp;
initDynString(&path);
assign(&path,gstr.pMINGW);
appendBackSlash(&path);
append(&path,"bin\\");
/* Get just the compiler name (the first word) */
comp = strdup(IVERILOG_VPI_CC);
cp = strchr(comp, ' ');
if (cp != NULL) *cp = '\0';
append(&path, comp);
append(&path, gstr.pCCNAME);
append(&path,".exe");
free(comp);
irv = _stat(path,&stat_buf);
deInitDynString(path);
if (irv) {
fprintf(stderr,"error: %s does not appear to be the valid root directory\n",root);
fprintf(stderr," of MinGW. Use the -mingw option of iverilog-vpi.exe to\n");
fprintf(stderr,"error: %s\n", root);
fprintf(stderr," does not appear to be the valid root directory of\n");
fprintf(stderr," MinGW. Use the -mingw option of iverilog-vpi.exe to\n");
fprintf(stderr," point to the MinGW root directory. For a Windows command\n");
fprintf(stderr," shell the option would be something like -mingw=c:\\mingw\n");
fprintf(stderr," For a Cygwin shell the option would be something like\n");
@ -452,100 +456,97 @@ static void checkMingwDir(char *root)
}
}
/* do minimal check that the Icarus Verilog root directory looks valid */
static void checkIvlDir(char *root)
{
int irv;
struct _stat stat_buf;
char *path;
initDynString(&path);
assign(&path,gstr.pIVL);
appendBackSlash(&path);
append(&path,"bin\\vvp" IVERILOG_SUFFIX ".exe");
irv = _stat(path,&stat_buf);
deInitDynString(path);
if (irv) {
fprintf(stderr,"error: %s does not appear to be the valid root directory of\n",root);
fprintf(stderr," Icarus Verilog. Use the -ivl option of iverilog-vpi" IVERILOG_SUFFIX " to\n");
fprintf(stderr," point to the Icarus Verilog root directory. For a Windows\n");
fprintf(stderr," command shell the option would be something like -ivl=c:\\iverilog\n");
fprintf(stderr," For a Cygwin shell the option would be something like\n");
fprintf(stderr," -ivl=c:\\\\iverilog\n");
myExit(6);
}
}
/* see if we can find mingw root */
#define IVL_REGKEY_MINGW "MingwDir"
static void setup_mingw_environment(void)
{
char *pOldPATH = getenv("PATH"); /* get current path */
char buffer[1]; /* doesn't matter how big this is, as we don't use the result */
char *path;
if (*gstr.pMINGW) {
checkMingwDir(gstr.pMINGW);
SetRegistryKey(IVL_REGKEY_MINGW,gstr.pMINGW);
} else if (!GetRegistryKey(IVL_REGKEY_MINGW,&gstr.pMINGW)) {
fprintf(stderr,"error: can not locate the MinGW root directory, use the -mingw option of\n");
fprintf(stderr," iverilog-vpi.exe to point to the MinGW root directory. For\n");
fprintf(stderr," a Windows command shell the option would be something like\n");
fprintf(stderr," -mingw=c:\\mingw For a Cygwin shell the option would be\n");
fprintf(stderr," something like -mingw=c:\\\\mingw\n");
myExit(5);
}
if (!*gstr.pOUT) SetRegistryKey(IVL_REGKEY_MINGW, gstr.pMINGW);
} else if (GetRegistryKey(IVL_REGKEY_MINGW, &gstr.pMINGW)) {
checkMingwDir(gstr.pMINGW);
} else if (SearchPath(NULL, gstr.pCCNAME, ".exe", sizeof(buffer), buffer, NULL)) {
return;
} else {
fprintf(stderr,"error: cannot locate the MinGW C compiler - either add its location\n");
fprintf(stderr," to the PATH environment variable or use the -mingw option of\n");
fprintf(stderr," iverilog-vpi.exe to point to the MinGW root directory. For\n");
fprintf(stderr," a Windows command shell the option would be something like\n");
fprintf(stderr," -mingw=c:\\mingw For a Cygwin shell the option would be\n");
fprintf(stderr," something like -mingw=c:\\\\mingw\n");
myExit(5);
}
/* Create new path with MinGW in it */
assign(&gstr.pNewPath,"PATH=");
append(&gstr.pNewPath,gstr.pMINGW);
appendBackSlash(&gstr.pNewPath);
append(&gstr.pNewPath, "\\");
append(&gstr.pNewPath,"bin;");
append(&gstr.pNewPath,pOldPATH);
initDynString(&path);
assign(&path, "PATH=");
append(&path, gstr.pMINGW);
appendBackSlash(&path);
append(&path, "bin;");
append(&path, getenv("PATH"));
/* Place new path in environment */
_putenv(gstr.pNewPath);
_putenv(path);
deInitDynString(path);
}
/* see if we can find iverilog root */
#define IVL_REGKEY_IVL "InstallDir"
/* find the iverilog root and initialise the compiler options */
static void setup_ivl_environment(void)
{
if (*gstr.pIVL) {
checkIvlDir(gstr.pIVL);
SetRegistryKey(IVL_REGKEY_IVL,gstr.pIVL);
} else if (!GetRegistryKey(IVL_REGKEY_IVL,&gstr.pIVL)) {
fprintf(stderr,"error: can not locate the Icarus Verilog root directory, use the -ivl option\n");
fprintf(stderr," of iverilog-vpi" IVERILOG_SUFFIX " to point to the Icarus Verilog root directory.\n");
fprintf(stderr," For a Windows command shell the option would be something like\n");
fprintf(stderr," -ivl=c:\\iverilog For a Cygwin shell the option would be something\n");
fprintf(stderr," like -ivl=c:\\\\iverilog\n");
myExit(6);
}
char path[4096];
char *ptr;
/* Extract the Icarus Verilog root directory from the path to the
command. The command path will look something like this:
C:\iverilog\bin\iverilog-vpi.exe
The corresponding root directory is
C:\iverilog
so we chop off the file name and the last directory. */
GetModuleFileName(NULL, path, sizeof(path));
ptr = strrchr(path, '\\');
if (!ptr) {
fprintf(stderr,"error: couldn't find start of program name in command path '%s'\n", path);
myExit(6);
}
*ptr = 0;
ptr = strrchr(path, '\\');
if (!ptr) {
fprintf(stderr,"error: couldn't find start of bin directory in command path '%s'\n", path);
myExit(6);
}
*ptr = 0;
assign(&gstr.pIVL, path);
/* Build up the CCFLAGS option string */
assign(&gstr.pCCFLAGS,IVERILOG_VPI_CFLAGS " -I\"");
append(&gstr.pCCFLAGS,gstr.pIVL);
assign(&gstr.pCCFLAGS, IVERILOG_VPI_CFLAGS " -I\"");
append(&gstr.pCCFLAGS, gstr.pIVL);
appendBackSlash(&gstr.pCCFLAGS);
append(&gstr.pCCFLAGS,"\\include\\\\iverilog\"" IVERILOG_SUFFIX);
append(&gstr.pCCFLAGS, "include\\iverilog\"" IVERILOG_SUFFIX);
/* Build up the CXFLAGS option string */
assign(&gstr.pCXFLAGS,IVERILOG_VPI_CXXFLAGS " -I\"");
append(&gstr.pCXFLAGS,gstr.pIVL);
assign(&gstr.pCXFLAGS, IVERILOG_VPI_CXXFLAGS " -I\"");
append(&gstr.pCXFLAGS, gstr.pIVL);
appendBackSlash(&gstr.pCXFLAGS);
append(&gstr.pCXFLAGS,"\\include\\\\iverilog\"" IVERILOG_SUFFIX);
append(&gstr.pCXFLAGS, "include\\iverilog\"" IVERILOG_SUFFIX);
/* Build up the LDFLAGS option string */
assign(&gstr.pLDLIBS,"-L\"");
append(&gstr.pLDLIBS,gstr.pIVL);
assign(&gstr.pLDLIBS, "-L\"");
append(&gstr.pLDLIBS, gstr.pIVL);
appendBackSlash(&gstr.pLDLIBS);
append(&gstr.pLDLIBS,"\\lib\" " IVERILOG_VPI_LDLIBS);
append(&gstr.pLDLIBS, "lib\" " IVERILOG_VPI_LDLIBS);
}
/* compile source modules */
@ -609,12 +610,7 @@ static void compile_and_link(void)
/* To make the output match iverilog-vpi.sh do not print out the
* root directories */
// printf("MinGW root directory: %s.\n", gstr.pMINGW);
checkMingwDir(gstr.pMINGW);
// printf("Icarus Verilog root directory: %s.\n", gstr.pIVL);
checkIvlDir(gstr.pIVL);
/* compile the C source files (*.c) */
compile(gstr.pCCSRC, gstr.pCCFLAGS, &gstr.pOBJ, &compile_errors, IVERILOG_VPI_CC );